radix_substate_store_impls/
state_tree_support.rs1use 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}