cnidarium/
cache.rs

1use std::{any::Any, collections::BTreeMap, sync::Arc};
2
3use tendermint::abci;
4
5use crate::{
6    store::{multistore::MultistoreConfig, substore::SubstoreConfig},
7    StateWrite,
8};
9
10/// A cache of changes to the state of the blockchain.
11///
12/// A [`StateDelta`](crate::StateDelta) is `Cache` above a `StateRead`.
13#[derive(Default, Debug)]
14pub struct Cache {
15    /// Unwritten changes to the consensus-critical state (stored in the JMT).
16    pub(crate) unwritten_changes: BTreeMap<String, Option<Vec<u8>>>,
17    /// Unwritten changes to non-consensus-critical state (stored in the nonverifiable storage).
18    pub(crate) nonverifiable_changes: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
19    /// Unwritten changes to the object store.  A `None` value means a deletion.
20    pub(crate) ephemeral_objects: BTreeMap<&'static str, Option<Box<dyn Any + Send + Sync>>>,
21    /// A list of ABCI events that occurred while building this set of state changes.
22    pub(crate) events: Vec<abci::Event>,
23}
24
25impl Cache {
26    /// Inspect the cache of unwritten changes to the verifiable state.
27    pub fn unwritten_changes(&self) -> &BTreeMap<String, Option<Vec<u8>>> {
28        &self.unwritten_changes
29    }
30
31    /// Inspect the cache of unwritten changes to the nonverifiable state.
32    pub fn nonverifiable_changes(&self) -> &BTreeMap<Vec<u8>, Option<Vec<u8>>> {
33        &self.nonverifiable_changes
34    }
35
36    /// Merge the given cache with this one, taking its writes in place of ours.
37    pub fn merge(&mut self, other: Cache) {
38        // One might ask, why does this exist separately from `apply_to`?  The
39        // answer is that `apply_to` takes a `StateWrite`, so we'd have to have
40        // `Cache: StateWrite`, and that implies `Cache: StateRead`, but the
41        // `StateRead` trait assumes asynchronous access, and in any case, we
42        // probably don't want to be reading directly from a `Cache` (?)
43        self.unwritten_changes.extend(other.unwritten_changes);
44        self.nonverifiable_changes
45            .extend(other.nonverifiable_changes);
46        self.ephemeral_objects.extend(other.ephemeral_objects);
47        self.events.extend(other.events);
48    }
49
50    /// Consume this cache, applying its writes to the given state.
51    pub fn apply_to<S: StateWrite>(self, mut state: S) {
52        for (key, value) in self.unwritten_changes {
53            if let Some(value) = value {
54                state.put_raw(key, value);
55            } else {
56                state.delete(key);
57            }
58        }
59
60        for (key, value) in self.nonverifiable_changes {
61            if let Some(value) = value {
62                state.nonverifiable_put_raw(key, value);
63            } else {
64                state.nonverifiable_delete(key);
65            }
66        }
67
68        // It's important to use object_merge here, so that we don't re-box all
69        // of the objects, causing downcasting to fail.
70        state.object_merge(self.ephemeral_objects);
71
72        for event in self.events {
73            state.record(event);
74        }
75    }
76
77    /// Returns `true` if there are cached writes on top of the snapshot, and `false` otherwise.
78    pub fn is_dirty(&self) -> bool {
79        !(self.unwritten_changes.is_empty()
80            && self.nonverifiable_changes.is_empty()
81            && self.ephemeral_objects.is_empty())
82    }
83
84    /// Extracts and returns the ABCI events contained in this cache.
85    pub fn take_events(&mut self) -> Vec<abci::Event> {
86        std::mem::take(&mut self.events)
87    }
88
89    /// Consumes a `Cache` and returns a map of `SubstoreConfig` to `Cache` that
90    /// corresponds to changes belonging to each substore. The keys in each `Cache`
91    /// are truncated to remove the substore prefix.
92    pub fn shard_by_prefix(
93        self,
94        prefixes: &MultistoreConfig,
95    ) -> BTreeMap<Arc<SubstoreConfig>, Self> {
96        let mut changes_by_substore = BTreeMap::new();
97        for (key, some_value) in self.unwritten_changes.into_iter() {
98            let (truncated_key, substore_config) = prefixes.route_key_str(&key);
99            changes_by_substore
100                .entry(substore_config)
101                .or_insert_with(Cache::default)
102                .unwritten_changes
103                .insert(truncated_key.to_string(), some_value);
104        }
105
106        for (key, some_value) in self.nonverifiable_changes {
107            let (truncated_key, substore_config) = prefixes.route_key_bytes(&key);
108            changes_by_substore
109                .entry(substore_config)
110                .or_insert_with(Cache::default)
111                .nonverifiable_changes
112                .insert(truncated_key.to_vec(), some_value);
113        }
114        changes_by_substore
115    }
116
117    pub(crate) fn clone_changes(&self) -> Self {
118        Self {
119            unwritten_changes: self.unwritten_changes.clone(),
120            nonverifiable_changes: self.nonverifiable_changes.clone(),
121            ephemeral_objects: Default::default(),
122            events: Default::default(),
123        }
124    }
125}