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