Skip to main content

ic_memory/ledger/
integrity.rs

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