ic_memory/runtime/
adoption.rs1use super::{MemoryRuntime, RuntimeLifecycle, RuntimeOpenError};
2use crate::{AllocationDeclaration, 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(
53 &self,
54 requirements: &SealedDeclarationSnapshot,
55 authority: &str,
56 ) -> Result<(), RuntimeAdoptionError> {
57 let RuntimeLifecycle::Bootstrapped { binding, .. } = &self.lifecycle else {
58 return Err(RuntimeOpenError::NotBootstrapped.into());
59 };
60 let committed = &binding.declarations;
61 let mut found = false;
62 for registration in requirements.registered_declarations() {
63 if registration.authority() == authority {
64 found = true;
65 let expected = registration.declaration();
66 verify_requirement(
67 committed,
68 authority,
69 expected.stable_key(),
70 expected.schema(),
71 Some(expected),
72 )?;
73 }
74 }
75 for request in requirements.requests() {
76 if request.authority() == authority {
77 found = true;
78 verify_requirement(
79 committed,
80 authority,
81 request.stable_key(),
82 request.schema(),
83 None,
84 )?;
85 }
86 }
87 if !found {
88 return Err(RuntimeAdoptionError::UnknownAuthority {
89 authority: authority.to_string(),
90 });
91 }
92 Ok(())
93 }
94}
95
96fn verify_requirement(
97 committed: &SealedDeclarationSnapshot,
98 authority: &str,
99 key: &StableKey,
100 schema: &SchemaMetadata,
101 fixed: Option<&AllocationDeclaration>,
102) -> Result<(), RuntimeAdoptionError> {
103 let registration = committed
104 .registered_declaration(key)
105 .ok_or_else(|| RuntimeOpenError::StableKeyNotCommitted(key.to_string()))?;
106 if registration.authority() != authority {
107 return Err(RuntimeAdoptionError::AuthorityMismatch {
108 stable_key: key.to_string(),
109 committed_authority: registration.authority().to_string(),
110 requested_authority: authority.to_string(),
111 });
112 }
113 let committed = registration.declaration();
114 if let Some(expected) = fixed
115 && expected.slot() != committed.slot()
116 {
117 return Err(RuntimeOpenError::MemoryIdMismatch {
118 stable_key: key.to_string(),
119 committed_id: committed.slot().id(),
120 requested_id: expected.slot().id(),
121 }
122 .into());
123 }
124 if schema != committed.schema()
125 || fixed.is_some_and(|expected| expected.label() != committed.label())
126 {
127 return Err(RuntimeAdoptionError::DeclarationMetadataMismatch {
128 stable_key: key.to_string(),
129 });
130 }
131 Ok(())
132}