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() >= 254 {
116 return Err(BootstrapAdmissionError::TooManyDeclarations);
117 }
118 let Some(record) = self
119 .ledger
120 .records()
121 .iter()
122 .find(|r| r.stable_key() == &key)
123 else {
124 return Err(BootstrapAdmissionError::Unknown(key));
125 };
126 self.pool.validate_authority(&key, authority)?;
127 self.pool.validate_id(record.slot().id())?;
128 self.selected.push(AllocationDeclaration {
129 stable_key: key,
130 slot: record.slot().clone(),
131 });
132 Ok(())
133 }
134
135 pub(super) fn complete(self) -> Result<Vec<AllocationDeclaration>, BootstrapAdmissionError> {
136 if let Some(error) = self.failure {
137 return Err(error);
138 }
139 Ok(self.selected)
140 }
141}