Skip to main content

ic_memory/runtime/
adoption.rs

1use super::{MemoryRuntime, RuntimeLifecycle, RuntimeOpenError};
2use crate::{SealedDeclarationSnapshot, StableKey};
3use ic_stable_structures::Memory;
4
5///
6/// RuntimeAdoptionError
7///
8/// A consumer's declared requirements do not match the existing committed
9/// runtime. Verification never bootstraps, grants authority, opens memory,
10/// replays admission, or changes the host's policy or bucket configuration.
11///
12
13#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
14#[non_exhaustive]
15pub enum RuntimeAdoptionError {
16    /// Runtime readiness, key resolution or requirement verification failed.
17    #[error(transparent)]
18    Open(#[from] RuntimeOpenError),
19    /// The supplied snapshot contains no requests for this authority.
20    #[error("no allocation requirements declared by authority '{authority}'")]
21    UnknownAuthority { authority: String },
22    /// This key was committed under a different current declaration authority.
23    #[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}
32
33impl<M: Memory> MemoryRuntime<M> {
34    /// Verify every logical request for one authority in
35    /// the supplied requirements against this runtime's current commitment.
36    ///
37    /// Requests must match key and authority while
38    /// retaining the host's assigned ID. Other authorities and additional
39    /// committed keys are ignored. An authority with no requirements rejects.
40    /// Grants and application schema semantics are not revalidated. Success
41    /// neither grants new access nor proves application lifecycle readiness.
42    pub fn verify_authority(
43        &self,
44        requirements: &SealedDeclarationSnapshot,
45        authority: &str,
46    ) -> Result<(), RuntimeAdoptionError> {
47        let RuntimeLifecycle::Bootstrapped {
48            binding,
49            committed_allocations,
50        } = &self.lifecycle
51        else {
52            return Err(RuntimeOpenError::NotBootstrapped.into());
53        };
54        let mut found = false;
55        for request in requirements.requests() {
56            if request.authority() == authority {
57                found = true;
58                verify_requirement(
59                    committed_allocations,
60                    &binding.pool,
61                    authority,
62                    request.stable_key(),
63                )?;
64            }
65        }
66        if !found {
67            return Err(RuntimeAdoptionError::UnknownAuthority {
68                authority: authority.to_string(),
69            });
70        }
71        Ok(())
72    }
73}
74
75fn verify_requirement(
76    committed: &crate::CommittedAllocations,
77    pool: &crate::MemoryAllocationPool,
78    authority: &str,
79    key: &StableKey,
80) -> Result<(), RuntimeAdoptionError> {
81    crate::capability::declaration_for_key(committed.declarations(), key.as_str())
82        .ok_or_else(|| RuntimeOpenError::StableKeyNotCommitted(key.to_string()))?;
83    let admitted_authority = pool
84        .authority_for_key(key)
85        .expect("committed key has an admitted owner");
86    if admitted_authority != authority {
87        return Err(RuntimeAdoptionError::AuthorityMismatch {
88            stable_key: key.to_string(),
89            committed_authority: admitted_authority.to_string(),
90            requested_authority: authority.to_string(),
91        });
92    }
93    Ok(())
94}