use super::{RuntimeBootstrapError, RuntimePolicyError};
use crate::{
AllocationPolicy, AllocationSlotDescriptor, PolicyIdentity, PolicyIdentityError,
RuntimeBootstrapPolicy, StableKey,
registry::SealedDeclarationSnapshot,
slot::{
IC_MEMORY_AUTHORITY_OWNER, IC_MEMORY_LEDGER_STABLE_KEY, MemoryManagerRangeAuthorityError,
},
};
use std::convert::Infallible;
pub(super) fn runtime_bootstrap_error_from_bootstrap<P>(
err: crate::BootstrapError<RuntimePolicyError<P>>,
) -> RuntimeBootstrapError<P> {
match err {
crate::BootstrapError::Ledger(err) => RuntimeBootstrapError::LedgerCommit(err),
crate::BootstrapError::Validation(err) => RuntimeBootstrapError::Validation(err),
crate::BootstrapError::Staging(err) => RuntimeBootstrapError::Staging(err),
}
}
pub(super) struct RuntimeMemoryManagerPolicy<'a, P> {
pub(super) declarations: &'a SealedDeclarationSnapshot,
pub(super) custom_policy: &'a P,
}
impl<P: AllocationPolicy> AllocationPolicy for RuntimeMemoryManagerPolicy<'_, P> {
type Error = RuntimePolicyError<P::Error>;
fn validate_key(&self, key: &StableKey) -> Result<(), Self::Error> {
let authority = self.declaration_authority(key);
if authority == IC_MEMORY_AUTHORITY_OWNER {
return Ok(());
}
self.custom_policy
.validate_key(key)
.map_err(RuntimePolicyError::Custom)
}
fn validate_slot(
&self,
key: &StableKey,
slot: &AllocationSlotDescriptor,
) -> Result<(), Self::Error> {
let authority = self.declaration_authority(key);
self.validate_runtime_range(authority, slot)?;
if authority == IC_MEMORY_AUTHORITY_OWNER {
return Ok(());
}
self.custom_policy
.validate_slot(key, slot)
.map_err(RuntimePolicyError::Custom)
}
fn validate_reserved_slot(
&self,
key: &StableKey,
slot: &AllocationSlotDescriptor,
) -> Result<(), Self::Error> {
let authority = self.declaration_authority(key);
self.validate_runtime_range(authority, slot)?;
if authority == IC_MEMORY_AUTHORITY_OWNER {
return Ok(());
}
self.custom_policy
.validate_reserved_slot(key, slot)
.map_err(RuntimePolicyError::Custom)
}
}
impl<P: AllocationPolicy> RuntimeMemoryManagerPolicy<'_, P> {
fn declaration_authority(&self, key: &StableKey) -> &str {
if key.as_str() == IC_MEMORY_LEDGER_STABLE_KEY {
return IC_MEMORY_AUTHORITY_OWNER;
}
self.declarations
.registered_declaration(key)
.expect("validated declaration belongs to the resolved snapshot")
.authority()
}
fn validate_runtime_range(
&self,
authority: &str,
slot: &AllocationSlotDescriptor,
) -> Result<(), RuntimePolicyError<P::Error>> {
match self
.declarations
.range_authority()
.validate_slot_authority(slot, authority)
{
Err(MemoryManagerRangeAuthorityError::UnclaimedId { .. })
if authority != IC_MEMORY_AUTHORITY_OWNER
&& !self.declarations.user_ranges_registered() =>
{
Ok(())
}
result => result.map(|_| ()).map_err(RuntimePolicyError::Range),
}
}
}
pub struct GenericRangePolicy;
impl AllocationPolicy for GenericRangePolicy {
type Error = Infallible;
fn validate_key(&self, _key: &StableKey) -> Result<(), Self::Error> {
Ok(())
}
fn validate_slot(
&self,
_key: &StableKey,
_slot: &AllocationSlotDescriptor,
) -> Result<(), Self::Error> {
Ok(())
}
fn validate_reserved_slot(
&self,
_key: &StableKey,
_slot: &AllocationSlotDescriptor,
) -> Result<(), Self::Error> {
Ok(())
}
}
impl RuntimeBootstrapPolicy for GenericRangePolicy {
fn runtime_bootstrap_identity(&self) -> Result<PolicyIdentity, PolicyIdentityError> {
PolicyIdentity::new("ic-memory.noop-policy", 1)
}
}