1use crate::{
2 declaration::{AllocationDeclaration, DeclarationSnapshot},
3 schema::SchemaMetadata,
4 slot::{
5 IC_MEMORY_AUTHORITY_OWNER, IC_MEMORY_LEDGER_LABEL, IC_MEMORY_LEDGER_STABLE_KEY,
6 MEMORY_MANAGER_LEDGER_ID, is_ic_memory_stable_key,
7 },
8 text::validate_diagnostic_text,
9};
10use serde::{Deserialize, Serialize};
11use std::{borrow::Cow, sync::Arc};
12
13#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
21pub struct MemoryRequest {
22 authority: String,
23 stable_key: crate::StableKey,
24 schema: SchemaMetadata,
25}
26
27impl<'de> Deserialize<'de> for MemoryRequest {
28 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
29 use serde::de::Error as _;
30 #[derive(Deserialize)]
31 #[serde(deny_unknown_fields)]
32 struct Request {
33 authority: String,
34 stable_key: crate::StableKey,
35 schema: SchemaMetadata,
36 }
37 let request = Request::deserialize(deserializer)?;
38 Self::new(
39 request.authority,
40 request.stable_key.as_str(),
41 request.schema,
42 )
43 .map_err(D::Error::custom)
44 }
45}
46
47impl MemoryRequest {
48 pub fn new(
50 authority: impl Into<String>,
51 stable_key: &str,
52 schema: SchemaMetadata,
53 ) -> Result<Self, MemoryDeclarationError> {
54 let authority = authority.into();
55 validate_external_authority(&authority)?;
56 let stable_key =
57 crate::StableKey::parse(stable_key).map_err(crate::DeclarationSnapshotError::Key)?;
58 if is_ic_memory_stable_key(stable_key.as_str()) {
59 return Err(MemoryDeclarationError::ReservedStableKey {
60 stable_key: stable_key.as_str().to_string(),
61 });
62 }
63 Ok(Self {
64 authority,
65 stable_key,
66 schema,
67 })
68 }
69
70 pub(crate) const fn with_schema(mut self, schema: SchemaMetadata) -> Self {
72 self.schema = schema;
73 self
74 }
75
76 #[must_use]
78 pub const fn stable_key(&self) -> &crate::StableKey {
79 &self.stable_key
80 }
81
82 #[must_use]
84 pub const fn schema(&self) -> &SchemaMetadata {
85 &self.schema
86 }
87
88 #[must_use]
90 pub fn authority(&self) -> &str {
91 &self.authority
92 }
93}
94
95#[non_exhaustive]
102#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
103pub enum MemoryDeclarationError {
104 #[error("at most 254 external requests are supported")]
105 TooManyDeclarations,
106 #[error("duplicate requested stable key {stable_key}")]
107 DuplicateRequest { stable_key: crate::StableKey },
108 #[error(transparent)]
110 Declaration(#[from] crate::DeclarationSnapshotError),
111 #[error("authority {reason}")]
113 InvalidAuthority {
114 reason: &'static str,
116 },
117 #[error("authority '{authority}' is reserved for ic-memory runtime internals")]
119 ReservedAuthority {
120 authority: String,
122 },
123 #[error("stable key '{stable_key}' is reserved for ic-memory runtime internals")]
125 ReservedStableKey {
126 stable_key: String,
128 },
129}
130
131#[derive(Clone, Debug, Eq, PartialEq)]
143pub struct SealedDeclarationSnapshot {
144 inner: Arc<SealedDeclarationSnapshotInner>,
145}
146
147#[derive(Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)]
159#[serde(deny_unknown_fields)]
160pub struct SealedDeclarationFingerprint {
161 algorithm_version: u8,
162 value: u64,
163}
164
165impl SealedDeclarationFingerprint {
166 #[must_use]
168 pub const fn algorithm_version(&self) -> u8 {
169 self.algorithm_version
170 }
171
172 #[must_use]
174 pub const fn value(&self) -> u64 {
175 self.value
176 }
177}
178
179#[derive(Debug, Eq, PartialEq)]
180struct SealedDeclarationSnapshotInner {
181 requests: Vec<MemoryRequest>,
182 fingerprint: SealedDeclarationFingerprint,
183}
184
185impl SealedDeclarationSnapshot {
186 pub fn new(mut requests: Vec<MemoryRequest>) -> Result<Self, MemoryDeclarationError> {
189 if requests.len() > 254 {
190 return Err(MemoryDeclarationError::TooManyDeclarations);
191 }
192 crate::sort::sort_unstable_by(&mut requests, |a, b| a.stable_key.cmp(&b.stable_key));
193 for pair in requests.windows(2) {
194 if pair[0].stable_key == pair[1].stable_key {
195 return Err(MemoryDeclarationError::DuplicateRequest {
196 stable_key: pair[1].stable_key.clone(),
197 });
198 }
199 }
200 let fingerprint = sealed_declaration_fingerprint(&requests);
201 Ok(Self {
202 inner: Arc::new(SealedDeclarationSnapshotInner {
203 requests,
204 fingerprint,
205 }),
206 })
207 }
208
209 #[must_use]
211 pub fn requests(&self) -> &[MemoryRequest] {
212 &self.inner.requests
213 }
214
215 pub(crate) fn resolve(
216 &self,
217 ledger: &crate::AllocationLedger,
218 historical: Vec<MemoryRequest>,
219 pool: &crate::MemoryAllocationPool,
220 ) -> Result<DeclarationSnapshot, crate::MemoryResolutionError> {
221 if self.requests().len() + historical.len() > 254 {
222 return Err(MemoryDeclarationError::TooManyDeclarations.into());
223 }
224 let mut declarations = Vec::with_capacity(self.requests().len() + historical.len() + 1);
225 declarations.push(internal_ledger_declaration());
226 let mut occupied = [false; 255];
227 for record in ledger.records() {
228 occupied[usize::from(record.slot().id())] = true;
229 }
230 let mut available_ids = 0..crate::MEMORY_MANAGER_INVALID_ID;
233 for request in self
238 .requests()
239 .iter()
240 .map(Cow::Borrowed)
241 .chain(historical.into_iter().map(Cow::Owned))
242 {
243 let historical = ledger
244 .records()
245 .iter()
246 .find(|record| record.stable_key() == &request.stable_key);
247 pool.validate_authority(&request.stable_key, &request.authority)?;
248 let id = if let Some(record) = historical {
249 pool.validate_id(record.slot().id())?;
252 record.slot().id()
253 } else {
254 available_ids
255 .find(|id| pool.contains(*id) && !occupied[usize::from(*id)])
256 .ok_or_else(|| crate::MemoryResolutionError::Exhausted {
257 stable_key: request.stable_key.clone(),
258 authority: request.authority.clone(),
259 })?
260 };
261 let slot = crate::MemoryManagerSlot::new(id).expect("usable id");
262 let declaration = match request {
267 Cow::Borrowed(request) => AllocationDeclaration {
268 stable_key: request.stable_key.clone(),
269 slot,
270 label: None,
271 schema: request.schema.clone(),
272 },
273 Cow::Owned(request) => AllocationDeclaration {
274 stable_key: request.stable_key,
275 slot,
276 label: None,
277 schema: request.schema,
278 },
279 };
280 declarations.push(declaration);
281 }
282 crate::sort::sort_unstable_by(&mut declarations, |a, b| a.stable_key().cmp(b.stable_key()));
283 Ok(DeclarationSnapshot::new(declarations).map_err(MemoryDeclarationError::from)?)
284 }
285
286 #[must_use]
288 pub fn fingerprint(&self) -> SealedDeclarationFingerprint {
289 self.inner.fingerprint
290 }
291
292 #[cfg(test)]
293 pub(crate) fn shares_storage_with(&self, other: &Self) -> bool {
294 Arc::ptr_eq(&self.inner, &other.inner)
295 }
296}
297
298fn validate_external_authority(value: &str) -> Result<(), MemoryDeclarationError> {
299 reject_internal_authority(value)?;
300 validate_diagnostic_text(value).map_err(|error| MemoryDeclarationError::InvalidAuthority {
301 reason: error.reason(),
302 })
303}
304
305fn reject_internal_authority(value: &str) -> Result<(), MemoryDeclarationError> {
306 if value == IC_MEMORY_AUTHORITY_OWNER {
307 return Err(MemoryDeclarationError::ReservedAuthority {
308 authority: value.to_string(),
309 });
310 }
311 Ok(())
312}
313
314#[derive(Serialize)]
315struct SealedDeclarationFingerprintMaterial<'a> {
316 format: &'static str,
317 requests: &'a [MemoryRequest],
318}
319
320struct FingerprintWriter(u64);
323
324impl std::io::Write for FingerprintWriter {
325 fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
326 self.0 = crate::hash::fnv64(self.0, bytes);
327 Ok(bytes.len())
328 }
329
330 fn flush(&mut self) -> std::io::Result<()> {
331 Ok(())
332 }
333}
334
335fn sealed_declaration_fingerprint(requests: &[MemoryRequest]) -> SealedDeclarationFingerprint {
336 let material = SealedDeclarationFingerprintMaterial {
337 format: "ic-memory.sealed-declaration-fingerprint.v1",
338 requests,
339 };
340 let mut writer = FingerprintWriter(crate::hash::FNV_OFFSET);
341 ciborium::into_writer(&material, &mut writer)
343 .unwrap_or_else(|_| panic!("sealed declaration fingerprint encodes into hash"));
344
345 SealedDeclarationFingerprint {
346 algorithm_version: SEALED_DECLARATION_FINGERPRINT_VERSION,
347 value: writer.0,
348 }
349}
350
351const SEALED_DECLARATION_FINGERPRINT_VERSION: u8 = 1;
352
353fn internal_ledger_declaration() -> AllocationDeclaration {
354 AllocationDeclaration::memory_manager(
355 IC_MEMORY_LEDGER_STABLE_KEY,
356 MEMORY_MANAGER_LEDGER_ID,
357 IC_MEMORY_LEDGER_LABEL,
358 )
359 .unwrap_or_else(|_| unreachable!("built-in ledger declaration constants are valid"))
360}
361
362#[cfg(test)]
363mod tests;