radix_substate_store_impls/
state_tree_support.rs

1use crate::state_tree::tree_store::{TypedInMemoryTreeStore, Version};
2use crate::state_tree::{list_substate_hashes_at_version, put_at_next_version};
3use radix_common::prelude::*;
4use radix_substate_store_interface::interface::*;
5
6#[derive(Debug, PartialEq, Eq, Clone)]
7pub struct StateTreeUpdatingDatabase<D> {
8    underlying: D,
9    tree_store: TypedInMemoryTreeStore,
10    current_version: Version,
11    current_hash: Hash,
12}
13
14impl<D> StateTreeUpdatingDatabase<D> {
15    pub fn new(underlying: D) -> Self {
16        StateTreeUpdatingDatabase {
17            underlying,
18            tree_store: TypedInMemoryTreeStore::new().with_pruning_enabled(),
19            current_version: 0,
20            current_hash: Hash([0; Hash::LENGTH]),
21        }
22    }
23
24    pub fn get_current_root_hash(&self) -> Hash {
25        self.current_hash
26    }
27
28    pub fn get_current_version(&self) -> Version {
29        self.current_version
30    }
31
32    pub fn list_substate_hashes(&self) -> IndexMap<DbPartitionKey, IndexMap<DbSortKey, Hash>> {
33        list_substate_hashes_at_version(&self.tree_store, self.current_version)
34    }
35
36    fn update_with(&mut self, db_updates: &DatabaseUpdates) {
37        self.current_hash = put_at_next_version(
38            &mut self.tree_store,
39            Some(self.current_version).filter(|version| *version > 0),
40            db_updates,
41        );
42        self.current_version += 1;
43    }
44}
45
46impl<D: SubstateDatabase> SubstateDatabase for StateTreeUpdatingDatabase<D> {
47    fn get_raw_substate_by_db_key(
48        &self,
49        partition_key: &DbPartitionKey,
50        sort_key: &DbSortKey,
51    ) -> Option<DbSubstateValue> {
52        self.underlying
53            .get_raw_substate_by_db_key(partition_key, sort_key)
54    }
55
56    fn list_raw_values_from_db_key(
57        &self,
58        partition_key: &DbPartitionKey,
59        from_sort_key: Option<&DbSortKey>,
60    ) -> Box<dyn Iterator<Item = PartitionEntry> + '_> {
61        self.underlying
62            .list_raw_values_from_db_key(partition_key, from_sort_key)
63    }
64}
65
66impl<D: ListableSubstateDatabase> ListableSubstateDatabase for StateTreeUpdatingDatabase<D> {
67    fn list_partition_keys(&self) -> Box<dyn Iterator<Item = DbPartitionKey> + '_> {
68        self.underlying.list_partition_keys()
69    }
70}
71
72impl<D: CommittableSubstateDatabase> CommittableSubstateDatabase for StateTreeUpdatingDatabase<D> {
73    fn commit(&mut self, database_updates: &DatabaseUpdates) {
74        self.underlying.commit(database_updates);
75        self.update_with(database_updates);
76    }
77}
78
79impl<D> StateTreeUpdatingDatabase<D>
80where
81    D: SubstateDatabase + ListableSubstateDatabase,
82{
83    pub fn validate_state_tree_matches_substate_store(
84        &self,
85    ) -> Result<(), StateTreeValidationError> {
86        let hashes_from_tree = self.list_substate_hashes();
87        if hashes_from_tree.keys().cloned().collect::<HashSet<_>>()
88            != self.list_partition_keys().collect::<HashSet<_>>()
89        {
90            return Err(StateTreeValidationError::NotAllPartitionsAreFoundInBothHashesAndDatabase);
91        }
92        for (db_partition_key, by_db_sort_key) in hashes_from_tree {
93            if by_db_sort_key.into_iter().collect::<HashMap<_, _>>()
94                != self
95                    .list_raw_values_from_db_key(&db_partition_key, None)
96                    .map(|(db_sort_key, substate_value)| (db_sort_key, hash(substate_value)))
97                    .collect::<HashMap<_, _>>()
98            {
99                return Err(StateTreeValidationError::MismatchInPartitionSubstates(
100                    db_partition_key.clone(),
101                ));
102            }
103        }
104        Ok(())
105    }
106}
107
108#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
109pub enum StateTreeValidationError {
110    NotAllPartitionsAreFoundInBothHashesAndDatabase,
111    MismatchInPartitionSubstates(DbPartitionKey),
112}