Skip to main content

ic_memory/ledger/
integrity.rs

1use super::{AllocationLedger, LedgerIntegrityError};
2use std::collections::BTreeSet;
3
4impl AllocationLedger {
5    pub(crate) const fn validate_bounds(&self) -> Result<(), LedgerIntegrityError> {
6        if self.records.len() > crate::constants::MAX_ALLOCATIONS {
7            return Err(LedgerIntegrityError::LimitExceeded {
8                resource: "allocation records",
9                limit: crate::constants::MAX_ALLOCATIONS,
10            });
11        }
12        Ok(())
13    }
14
15    /// Validate count, unique ownership and empty genesis before recovery or commit.
16    /// Checked field types already enforce key, slot and schema invariants.
17    pub fn validate_integrity(&self) -> Result<(), LedgerIntegrityError> {
18        self.validate_bounds()?;
19        let mut stable_keys = BTreeSet::new();
20        let mut slots = [false; crate::constants::MAX_ALLOCATIONS];
21        for record in self.records() {
22            if !stable_keys.insert(record.stable_key()) {
23                return Err(LedgerIntegrityError::DuplicateStableKey {
24                    stable_key: record.stable_key.clone(),
25                });
26            }
27            if slots[usize::from(record.slot.id())] {
28                return Err(LedgerIntegrityError::DuplicateSlot {
29                    slot: record.slot.clone(),
30                });
31            }
32            slots[usize::from(record.slot.id())] = true;
33        }
34        if self.current_generation == 0 && !self.records.is_empty() {
35            return Err(LedgerIntegrityError::NonemptyGenesis);
36        }
37        Ok(())
38    }
39}