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 From<super::RuntimeStateError> for RuntimeAdoptionError {
37 fn from(error: super::RuntimeStateError) -> Self {
38 Self::Open(RuntimeOpenError::State(error))
39 }
40}
41
42impl<M: Memory> MemoryRuntime<M> {
43 pub fn verify_authority(
52 &self,
53 requirements: &SealedDeclarationSnapshot,
54 authority: &str,
55 ) -> Result<(), RuntimeAdoptionError> {
56 let RuntimeLifecycle::Bootstrapped {
57 binding,
58 committed_allocations,
59 } = &self.lifecycle
60 else {
61 return Err(RuntimeOpenError::NotBootstrapped.into());
62 };
63 let mut found = false;
64 for request in requirements.requests() {
65 if request.authority() == authority {
66 found = true;
67 verify_requirement(
68 committed_allocations,
69 &binding.pool,
70 authority,
71 request.stable_key(),
72 request.schema(),
73 )?;
74 }
75 }
76 if !found {
77 return Err(RuntimeAdoptionError::UnknownAuthority {
78 authority: authority.to_string(),
79 });
80 }
81 Ok(())
82 }
83}
84
85fn verify_requirement(
86 committed: &crate::CommittedAllocations,
87 pool: &crate::MemoryAllocationPool,
88 authority: &str,
89 key: &StableKey,
90 schema: &SchemaMetadata,
91) -> Result<(), RuntimeAdoptionError> {
92 let declaration =
93 crate::capability::declaration_for_key(committed.declarations(), key.as_str())
94 .ok_or_else(|| RuntimeOpenError::StableKeyNotCommitted(key.to_string()))?;
95 let admitted_authority = pool
96 .authority_for_key(key)
97 .expect("committed key has an admitted owner");
98 if admitted_authority != authority {
99 return Err(RuntimeAdoptionError::AuthorityMismatch {
100 stable_key: key.to_string(),
101 committed_authority: admitted_authority.to_string(),
102 requested_authority: authority.to_string(),
103 });
104 }
105 if schema != declaration.schema() {
106 return Err(RuntimeAdoptionError::DeclarationMetadataMismatch {
107 stable_key: key.to_string(),
108 });
109 }
110 Ok(())
111}