ic_memory/runtime/
adoption.rs1use super::{MemoryRuntime, RuntimeLifecycle, RuntimeOpenError};
2use crate::{SchemaMetadata, SealedDeclarationSnapshot, StableKey};
3use ic_stable_structures::Memory;
4
5#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
14#[non_exhaustive]
15pub enum RuntimeAdoptionError {
16 #[error(transparent)]
18 Open(#[from] RuntimeOpenError),
19 #[error("no allocation requirements declared by authority '{authority}'")]
21 UnknownAuthority { authority: String },
22 #[error(
24 "stable key '{stable_key}' is committed under '{committed_authority}', not '{requested_authority}'"
25 )]
26 AuthorityMismatch {
27 stable_key: String,
28 committed_authority: String,
29 requested_authority: String,
30 },
31 #[error("declaration metadata for stable key '{stable_key}' differs from the commitment")]
33 DeclarationMetadataMismatch { stable_key: String },
34}
35
36impl<M: Memory> MemoryRuntime<M> {
37 pub fn verify_authority(
46 &self,
47 requirements: &SealedDeclarationSnapshot,
48 authority: &str,
49 ) -> Result<(), RuntimeAdoptionError> {
50 let RuntimeLifecycle::Bootstrapped {
51 binding,
52 committed_allocations,
53 } = &self.lifecycle
54 else {
55 return Err(RuntimeOpenError::NotBootstrapped.into());
56 };
57 let mut found = false;
58 for request in requirements.requests() {
59 if request.authority() == authority {
60 found = true;
61 verify_requirement(
62 committed_allocations,
63 &binding.pool,
64 authority,
65 request.stable_key(),
66 request.schema(),
67 )?;
68 }
69 }
70 if !found {
71 return Err(RuntimeAdoptionError::UnknownAuthority {
72 authority: authority.to_string(),
73 });
74 }
75 Ok(())
76 }
77}
78
79fn verify_requirement(
80 committed: &crate::CommittedAllocations,
81 pool: &crate::MemoryAllocationPool,
82 authority: &str,
83 key: &StableKey,
84 schema: &SchemaMetadata,
85) -> Result<(), RuntimeAdoptionError> {
86 let declaration =
87 crate::capability::declaration_for_key(committed.declarations(), key.as_str())
88 .ok_or_else(|| RuntimeOpenError::StableKeyNotCommitted(key.to_string()))?;
89 let admitted_authority = pool
90 .authority_for_key(key)
91 .expect("committed key has an admitted owner");
92 if admitted_authority != authority {
93 return Err(RuntimeAdoptionError::AuthorityMismatch {
94 stable_key: key.to_string(),
95 committed_authority: admitted_authority.to_string(),
96 requested_authority: authority.to_string(),
97 });
98 }
99 if schema != declaration.schema() {
100 return Err(RuntimeAdoptionError::DeclarationMetadataMismatch {
101 stable_key: key.to_string(),
102 });
103 }
104 Ok(())
105}