ic_memory/runtime/
admission.rs1use crate::{
2 AllocationDeclaration, AllocationLedger, AllocationRecord, SealedDeclarationSnapshot, StableKey,
3};
4
5#[non_exhaustive]
12#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
13pub enum BootstrapAdmissionError {
14 #[error("historical key {0} is unknown")]
15 Unknown(StableKey),
16 #[error("key {0} is already declared or selected")]
17 Duplicate(StableKey),
18 #[error("completed declarations exceed 254 external allocations")]
19 TooManyDeclarations,
20 #[error(transparent)]
21 Pool(#[from] crate::MemoryAllocationPoolError),
22 #[error(transparent)]
23 Declarations(#[from] crate::MemoryDeclarationError),
24}
25
26pub struct BootstrapAdmission<'a> {
37 ledger: &'a AllocationLedger,
38 declarations: &'a SealedDeclarationSnapshot,
39 pool: &'a crate::MemoryAllocationPool,
40 selected: Vec<AllocationDeclaration>,
41 failure: Option<BootstrapAdmissionError>,
42}
43
44impl<'a> BootstrapAdmission<'a> {
45 pub(super) const fn new(
46 ledger: &'a AllocationLedger,
47 declarations: &'a SealedDeclarationSnapshot,
48 pool: &'a crate::MemoryAllocationPool,
49 ) -> Self {
50 Self {
51 ledger,
52 declarations,
53 pool,
54 selected: Vec::new(),
55 failure: None,
56 }
57 }
58
59 #[must_use]
61 pub const fn declarations(&self) -> &SealedDeclarationSnapshot {
62 self.declarations
63 }
64
65 #[must_use = "recovered allocation metadata is inspected only when the iterator is consumed"]
69 pub fn recovered_allocations(&self) -> impl ExactSizeIterator<Item = &AllocationRecord> {
70 self.ledger.records().iter()
71 }
72
73 #[must_use]
75 pub fn is_declared(&self, key: &StableKey) -> bool {
76 key.as_str() == crate::IC_MEMORY_LEDGER_STABLE_KEY
79 || self
80 .declarations
81 .requests()
82 .binary_search_by(|request| request.stable_key().cmp(key))
83 .is_ok()
84 || self
85 .selected
86 .iter()
87 .any(|declaration| declaration.stable_key() == key)
88 }
89
90 pub fn include_historical(
94 &mut self,
95 authority: &str,
96 stable_key: &str,
97 ) -> Result<(), BootstrapAdmissionError> {
98 if let Some(error) = &self.failure {
99 return Err(error.clone());
100 }
101 let result = self.select(authority, stable_key);
102 if let Err(error) = &result {
103 self.failure = Some(error.clone());
104 }
105 result
106 }
107
108 fn select(&mut self, authority: &str, stable_key: &str) -> Result<(), BootstrapAdmissionError> {
109 let key = crate::requests::checked_request_key(authority, stable_key)?;
112 if self.is_declared(&key) {
113 return Err(BootstrapAdmissionError::Duplicate(key));
114 }
115 if self.declarations.requests().len() + self.selected.len()
116 >= crate::constants::MAX_EXTERNAL_DECLARATIONS
117 {
118 return Err(BootstrapAdmissionError::TooManyDeclarations);
119 }
120 let Some(record) = self.ledger.record_for_key(&key) else {
121 return Err(BootstrapAdmissionError::Unknown(key));
122 };
123 self.pool.validate_authority(&key, authority)?;
124 self.pool.validate_id(record.slot().id())?;
125 self.selected.push(AllocationDeclaration {
126 stable_key: key,
127 slot: record.slot().clone(),
128 });
129 Ok(())
130 }
131
132 pub(super) fn complete(self) -> Result<Vec<AllocationDeclaration>, BootstrapAdmissionError> {
133 if let Some(error) = self.failure {
134 return Err(error);
135 }
136 Ok(self.selected)
137 }
138}