Skip to main content

ic_memory/runtime/
adoption.rs

1use super::{MemoryRuntime, RuntimeOpenError};
2use crate::{SealedDeclarationSnapshot, StableKey};
3use ic_platform::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 committed = self.committed()?;
48        let mut found = false;
49        for request in requirements.requests() {
50            if request.authority() == authority {
51                found = true;
52                verify_requirement(
53                    &committed.allocations,
54                    &committed.binding.pool,
55                    authority,
56                    request.stable_key(),
57                )?;
58            }
59        }
60        if !found {
61            return Err(RuntimeAdoptionError::UnknownAuthority {
62                authority: authority.to_string(),
63            });
64        }
65        Ok(())
66    }
67}
68
69fn verify_requirement(
70    committed: &[crate::AllocationDeclaration],
71    pool: &crate::MemoryAllocationPool,
72    authority: &str,
73    key: &StableKey,
74) -> Result<(), RuntimeAdoptionError> {
75    crate::declaration::declaration_for_key(committed, key.as_str())
76        .ok_or_else(|| RuntimeOpenError::StableKeyNotCommitted(key.to_string()))?;
77    let admitted_authority = pool
78        .authority_for_key(key)
79        .expect("committed key has an admitted owner");
80    if admitted_authority != authority {
81        return Err(RuntimeAdoptionError::AuthorityMismatch {
82            stable_key: key.to_string(),
83            committed_authority: admitted_authority.to_string(),
84            requested_authority: authority.to_string(),
85        });
86    }
87    Ok(())
88}