Skip to main content

ic_memory/runtime/
policy.rs

1use super::{RuntimeBootstrapError, RuntimePolicyError};
2use crate::{
3    AllocationPolicy, AllocationSlotDescriptor, PolicyIdentity, PolicyIdentityError,
4    RuntimeBootstrapPolicy, StableKey,
5    registry::SealedDeclarationSnapshot,
6    slot::{
7        IC_MEMORY_AUTHORITY_OWNER, IC_MEMORY_LEDGER_STABLE_KEY, MemoryManagerRangeAuthorityError,
8    },
9};
10use std::convert::Infallible;
11
12pub(super) fn runtime_bootstrap_error_from_bootstrap<P>(
13    err: crate::BootstrapError<RuntimePolicyError<P>>,
14) -> RuntimeBootstrapError<P> {
15    match err {
16        crate::BootstrapError::Ledger(err) => RuntimeBootstrapError::LedgerCommit(err),
17        crate::BootstrapError::Validation(err) => RuntimeBootstrapError::Validation(err),
18        crate::BootstrapError::Staging(err) => RuntimeBootstrapError::Staging(err),
19    }
20}
21
22pub(super) struct RuntimeMemoryManagerPolicy<'a, P> {
23    pub(super) declarations: &'a SealedDeclarationSnapshot,
24    pub(super) custom_policy: &'a P,
25}
26
27impl<P: AllocationPolicy> AllocationPolicy for RuntimeMemoryManagerPolicy<'_, P> {
28    type Error = RuntimePolicyError<P::Error>;
29
30    fn validate_key(&self, key: &StableKey) -> Result<(), Self::Error> {
31        let authority = self.declaration_authority(key)?;
32        if authority == IC_MEMORY_AUTHORITY_OWNER {
33            return Ok(());
34        }
35        self.custom_policy
36            .validate_key(key)
37            .map_err(RuntimePolicyError::Custom)
38    }
39
40    fn validate_slot(
41        &self,
42        key: &StableKey,
43        slot: &AllocationSlotDescriptor,
44    ) -> Result<(), Self::Error> {
45        let authority = self.declaration_authority(key)?;
46        self.validate_runtime_range(authority, slot)?;
47        if authority == IC_MEMORY_AUTHORITY_OWNER {
48            return Ok(());
49        }
50        self.custom_policy
51            .validate_slot(key, slot)
52            .map_err(RuntimePolicyError::Custom)
53    }
54
55    fn validate_reserved_slot(
56        &self,
57        key: &StableKey,
58        slot: &AllocationSlotDescriptor,
59    ) -> Result<(), Self::Error> {
60        let authority = self.declaration_authority(key)?;
61        self.validate_runtime_range(authority, slot)?;
62        if authority == IC_MEMORY_AUTHORITY_OWNER {
63            return Ok(());
64        }
65        self.custom_policy
66            .validate_reserved_slot(key, slot)
67            .map_err(RuntimePolicyError::Custom)
68    }
69}
70
71impl<P: AllocationPolicy> RuntimeMemoryManagerPolicy<'_, P> {
72    fn declaration_authority(&self, key: &StableKey) -> Result<&str, RuntimePolicyError<P::Error>> {
73        if key.as_str() == IC_MEMORY_LEDGER_STABLE_KEY {
74            return Ok(IC_MEMORY_AUTHORITY_OWNER);
75        }
76        self.declarations
77            .registered_declaration(key)
78            .map(crate::StaticMemoryDeclaration::authority)
79            .ok_or_else(|| RuntimePolicyError::MissingDeclarationMetadata(key.as_str().to_string()))
80    }
81
82    fn validate_runtime_range(
83        &self,
84        authority: &str,
85        slot: &AllocationSlotDescriptor,
86    ) -> Result<(), RuntimePolicyError<P::Error>> {
87        if authority == IC_MEMORY_AUTHORITY_OWNER || self.declarations.user_ranges_registered() {
88            self.declarations
89                .range_authority()
90                .validate_slot_authority(slot, authority)?;
91            return Ok(());
92        }
93
94        let id = slot
95            .memory_manager_id()
96            .map_err(MemoryManagerRangeAuthorityError::Slot)?;
97        if self
98            .declarations
99            .range_authority()
100            .authority_for_id(id)?
101            .is_some()
102        {
103            self.declarations
104                .range_authority()
105                .validate_slot_authority(slot, authority)?;
106        }
107        Ok(())
108    }
109}
110
111///
112/// GenericRangePolicy
113///
114/// Built-in bootstrap policy used by the no-argument default-runtime helpers.
115/// The runtime enforces registered range ownership and internal reservations;
116/// this policy adds no application-specific restrictions. Passing it directly
117/// to allocation validation outside the runtime does not enforce those ranges.
118///
119/// Use with configured bootstrap when the host does not require a custom
120/// policy. It retains the built-in policy identity and does not authorize
121/// replacing a different policy already bound to the runtime.
122///
123pub struct GenericRangePolicy;
124
125impl AllocationPolicy for GenericRangePolicy {
126    type Error = Infallible;
127
128    fn validate_key(&self, _key: &StableKey) -> Result<(), Self::Error> {
129        Ok(())
130    }
131
132    fn validate_slot(
133        &self,
134        _key: &StableKey,
135        _slot: &AllocationSlotDescriptor,
136    ) -> Result<(), Self::Error> {
137        Ok(())
138    }
139
140    fn validate_reserved_slot(
141        &self,
142        _key: &StableKey,
143        _slot: &AllocationSlotDescriptor,
144    ) -> Result<(), Self::Error> {
145        Ok(())
146    }
147}
148
149impl RuntimeBootstrapPolicy for GenericRangePolicy {
150    fn runtime_bootstrap_identity(&self) -> Result<PolicyIdentity, PolicyIdentityError> {
151        PolicyIdentity::new("ic-memory.noop-policy", 1)
152    }
153}