1use core::convert::Infallible;
2
3use ics23::CommitmentProof;
4use tendermint::hash::Algorithm;
5use tendermint::Hash;
6use tracing::trace;
7
8use crate::avl::{AsBytes, AvlTree};
9use crate::context::{ProvableStore, Store};
10use crate::types::{Height, Path, RawHeight, State};
11
12#[derive(Debug, Clone, Default)]
18pub struct PrunedVec<T> {
19 vec: Vec<T>,
20 pruned: usize,
23}
24
25impl<T> PrunedVec<T> {
26 pub fn push(&mut self, value: T) {
27 self.vec.push(value);
28 }
29
30 pub fn get(&self, index: usize) -> Option<&T> {
31 self.vec.get(index.checked_sub(self.pruned)?)
32 }
33
34 pub fn last(&self) -> Option<&T> {
35 self.vec.last()
36 }
37
38 pub fn current_length(&self) -> usize {
41 self.vec.len()
42 }
43
44 pub fn pruned_length(&self) -> usize {
47 self.pruned
48 }
49
50 pub fn original_length(&self) -> usize {
54 self.current_length() + self.pruned_length()
55 }
56
57 pub fn prune(&mut self, index: usize) {
62 trace!("pruning at index = {}", index);
63 if index > self.pruned {
64 self.vec.drain(0..index - self.pruned);
65 self.pruned = index;
66 }
67 }
68}
69
70#[derive(Clone, Debug)]
83pub struct InMemoryStore {
84 store: PrunedVec<State>,
86 staged: State,
89 pending: State,
91}
92
93impl InMemoryStore {
94 #[inline]
95 fn get_state(&self, height: Height) -> Option<&State> {
96 match height {
97 Height::Pending => Some(&self.pending),
98 Height::Latest => self.store.last(),
99 Height::Stable(height) => {
100 if height == 0 {
101 None
102 } else {
103 let h = height as usize;
104 self.store.get(h - 1)
105 }
106 }
107 }
108 }
109}
110
111impl Default for InMemoryStore {
112 fn default() -> Self {
114 let genesis_state = AvlTree::new();
115
116 let store = PrunedVec::default();
117 let staged = genesis_state.clone();
118 let pending = genesis_state.clone();
119
120 Self {
121 store,
122 staged,
123 pending,
124 }
125 }
126}
127
128impl Store for InMemoryStore {
129 type Error = Infallible;
130
131 fn set(&mut self, path: Path, value: Vec<u8>) -> Result<Option<Vec<u8>>, Self::Error> {
132 trace!("set at path = {}", path.to_string());
133 Ok(self.pending.insert(path, value))
134 }
135
136 fn get(&self, height: Height, path: &Path) -> Option<Vec<u8>> {
137 trace!(
138 "get at path = {} at height = {:?}",
139 path.to_string(),
140 height
141 );
142 self.get_state(height).and_then(|v| v.get(path).cloned())
143 }
144
145 fn delete(&mut self, path: &Path) {
146 self.pending.remove(path.clone());
147 }
148
149 fn commit(&mut self) -> Result<Vec<u8>, Self::Error> {
150 self.apply()?;
151 trace!("committing height: {}", self.current_height());
152 self.store.push(self.staged.clone());
153 Ok(self.root_hash())
154 }
155
156 fn apply(&mut self) -> Result<(), Self::Error> {
157 trace!("applying height: {}", self.current_height());
158 self.staged = self.pending.clone();
159 Ok(())
160 }
161
162 fn reset(&mut self) {
163 trace!("resetting height: {}", self.current_height());
164 self.pending = self.staged.clone();
165 }
166
167 fn prune(&mut self, height: RawHeight) -> Result<RawHeight, Self::Error> {
168 let h = height as usize;
169 self.store.prune(h);
170 Ok(height)
171 }
172
173 fn current_height(&self) -> u64 {
174 self.store.original_length() as u64
175 }
176
177 fn get_keys(&self, key_prefix: &Path) -> Vec<Path> {
178 let key_prefix = key_prefix.as_bytes();
179 self.pending
180 .get_keys()
181 .into_iter()
182 .filter(|&key| key.as_bytes().as_ref().starts_with(key_prefix.as_ref()))
183 .cloned()
184 .collect()
185 }
186}
187
188impl ProvableStore for InMemoryStore {
189 fn root_hash(&self) -> Vec<u8> {
190 self.get_state(Height::Latest)
191 .and_then(|s| s.root_hash())
192 .unwrap_or(&Hash::from_bytes(Algorithm::Sha256, &[0u8; 32]).unwrap())
193 .as_bytes()
194 .to_vec()
195 }
196
197 fn get_proof(&self, height: Height, key: &Path) -> Option<CommitmentProof> {
198 trace!(
199 "get proof at path = {} at height = {:?}",
200 key.to_string(),
201 height
202 );
203 self.get_state(height).map(|v| v.get_proof(key))
204 }
205}
206
207#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_pruned_vec() {
215 let mut pv = PrunedVec::default();
216 pv.push(1);
217 pv.push(2);
218 pv.push(3);
219 pv.push(4);
220 pv.push(5);
221 assert_eq!(pv.original_length(), 5);
222 pv.prune(2);
223 assert_eq!(pv.original_length(), 5);
224 assert_eq!(pv.pruned_length(), 2);
225 assert_eq!(pv.current_length(), 3);
226 assert_eq!(pv.get(0), None);
227 assert_eq!(pv.get(1), None);
228 assert_eq!(pv.get(2), Some(&3));
229 assert_eq!(pv.get(3), Some(&4));
230 assert_eq!(pv.get(4), Some(&5));
231 assert_eq!(pv.get(5), None);
232 assert_eq!(pv.last(), Some(&5));
233 }
234
235 #[test]
236 fn test_in_memory_store() {
237 let mut store = InMemoryStore::default();
238 assert!(!store.root_hash().is_empty());
239 assert_eq!(store.current_height(), 0);
240
241 let path = Path::from("a".to_owned());
242 let value1 = vec![1, 2, 3];
243 let value2 = vec![4, 5, 6];
244
245 store.set(path.clone(), value1.clone()).unwrap();
246 assert_eq!(store.get(Height::Pending, &path), Some(value1.clone()));
247 assert_eq!(store.get(Height::Latest, &path), None);
248 assert_eq!(store.get(Height::Stable(1), &path), None);
249
250 store.apply().unwrap();
251 store.commit().unwrap();
252
253 assert_eq!(store.get(Height::Pending, &path), Some(value1.clone()));
254 assert_eq!(store.get(Height::Latest, &path), Some(value1.clone()));
255 assert_eq!(store.get(Height::Stable(1), &path), Some(value1.clone()));
256 assert_eq!(store.get(Height::Stable(2), &path), None);
257 assert_eq!(store.current_height(), 1);
258 assert!(!store.root_hash().is_empty());
259
260 store.set(path.clone(), value2.clone()).unwrap();
261 assert_eq!(store.get(Height::Pending, &path), Some(value2.clone()));
262 assert_eq!(store.get(Height::Latest, &path), Some(value1.clone()));
263 assert_eq!(store.get(Height::Stable(1), &path), Some(value1.clone()));
264
265 store.apply().unwrap();
266 store.commit().unwrap();
267
268 assert_eq!(store.get(Height::Pending, &path), Some(value2.clone()));
269 assert_eq!(store.get(Height::Latest, &path), Some(value2.clone()));
270 assert_eq!(store.get(Height::Stable(1), &path), Some(value1.clone()));
271 assert_eq!(store.get(Height::Stable(2), &path), Some(value2.clone()));
272 assert_eq!(store.get(Height::Stable(3), &path), None);
273 assert_eq!(store.current_height(), 2);
274 assert!(!store.root_hash().is_empty());
275 }
276}