basecoin_store/impls/
revertible.rs1use ics23::CommitmentProof;
2use tracing::trace;
3
4use crate::context::{ProvableStore, Store};
5use crate::types::{Height, Path};
6
7#[deprecated(
20 since = "TBD",
21 note = "RevertibleStore has a bug where using the operation log to revert changes does not guarantee deterministic Merkle root hashes. Use InMemoryStore which implements a correct rollback procedure."
22)]
23#[derive(Clone, Debug)]
24pub struct RevertibleStore<S> {
25 store: S,
27 op_log: Vec<RevertOp>,
29}
30
31#[derive(Clone, Debug)]
32enum RevertOp {
33 Delete(Path),
34 Set(Path, Vec<u8>),
35}
36
37impl<S> RevertibleStore<S>
38where
39 S: Store,
40{
41 pub fn new(store: S) -> Self {
42 Self {
43 store,
44 op_log: vec![],
45 }
46 }
47}
48
49impl<S> Default for RevertibleStore<S>
50where
51 S: Default + Store,
52{
53 fn default() -> Self {
54 Self::new(S::default())
55 }
56}
57
58impl<S> Store for RevertibleStore<S>
59where
60 S: Store,
61{
62 type Error = S::Error;
63
64 #[inline]
65 fn set(&mut self, path: Path, value: Vec<u8>) -> Result<Option<Vec<u8>>, Self::Error> {
66 let old_value = self.store.set(path.clone(), value)?;
67 match old_value {
68 None => self.op_log.push(RevertOp::Delete(path)),
70 Some(ref old_value) => self.op_log.push(RevertOp::Set(path, old_value.clone())),
73 }
74 Ok(old_value)
75 }
76
77 #[inline]
78 fn get(&self, height: Height, path: &Path) -> Option<Vec<u8>> {
79 self.store.get(height, path)
80 }
81
82 #[inline]
83 fn delete(&mut self, path: &Path) {
84 self.store.delete(path)
85 }
86
87 #[inline]
88 fn commit(&mut self) -> Result<Vec<u8>, Self::Error> {
89 self.apply()?;
91 self.store.commit()
92 }
93
94 #[inline]
95 fn apply(&mut self) -> Result<(), Self::Error> {
96 self.op_log.clear();
99 Ok(())
100 }
101
102 #[inline]
109 fn reset(&mut self) {
110 trace!("Rollback operation log changes");
113 while let Some(op) = self.op_log.pop() {
114 match op {
115 RevertOp::Delete(path) => self.delete(&path),
116 RevertOp::Set(path, value) => {
117 self.set(path, value).unwrap(); }
121 }
122 }
123 }
124
125 #[inline]
126 fn current_height(&self) -> u64 {
127 self.store.current_height()
128 }
129
130 #[inline]
131 fn get_keys(&self, key_prefix: &Path) -> Vec<Path> {
132 self.store.get_keys(key_prefix)
133 }
134}
135
136impl<S> ProvableStore for RevertibleStore<S>
137where
138 S: ProvableStore,
139{
140 #[inline]
141 fn root_hash(&self) -> Vec<u8> {
142 self.store.root_hash()
143 }
144
145 #[inline]
146 fn get_proof(&self, height: Height, key: &Path) -> Option<CommitmentProof> {
147 self.store.get_proof(height, key)
148 }
149}