1mod build;
53mod build_cache;
54mod build_iterator;
55mod changes_iterator;
56mod input;
57mod prune;
58mod storage;
59mod surface_iterator;
60
61pub use self::build_cache::{BuildCache, CachedBuildData, CacheAction};
62pub use self::storage::InMemoryStorage;
63pub use self::changes_iterator::{
64 key_changes, key_changes_proof,
65 key_changes_proof_check, key_changes_proof_check_with_db,
66};
67pub use self::prune::prune;
68
69use std::collections::{HashMap, HashSet};
70use std::convert::TryInto;
71use tetsy_hash_db::{Hasher, Prefix};
72use num_traits::{One, Zero};
73use codec::{Decode, Encode};
74use tet_core;
75use tet_core::storage::PrefixedStorageKey;
76use tp_trie::{MemoryDB, DBValue, TrieMut};
77use tp_trie::trie_types::TrieDBMut;
78use crate::{
79 StorageKey,
80 backend::Backend,
81 overlayed_changes::OverlayedChanges,
82 changes_trie::{
83 build::prepare_input,
84 build_cache::{IncompleteCachedBuildData, IncompleteCacheAction},
85 },
86};
87
88pub trait BlockNumber:
90 Send + Sync + 'static +
91 std::fmt::Display +
92 Clone +
93 From<u32> + TryInto<u32> + One + Zero +
94 PartialEq + Ord +
95 std::hash::Hash +
96 std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
97 std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
98 std::ops::Rem<Self, Output=Self> +
99 std::ops::AddAssign<Self> +
100 num_traits::CheckedMul + num_traits::CheckedSub +
101 Decode + Encode
102{}
103
104impl<T> BlockNumber for T where T:
105 Send + Sync + 'static +
106 std::fmt::Display +
107 Clone +
108 From<u32> + TryInto<u32> + One + Zero +
109 PartialEq + Ord +
110 std::hash::Hash +
111 std::ops::Add<Self, Output=Self> + ::std::ops::Sub<Self, Output=Self> +
112 std::ops::Mul<Self, Output=Self> + ::std::ops::Div<Self, Output=Self> +
113 std::ops::Rem<Self, Output=Self> +
114 std::ops::AddAssign<Self> +
115 num_traits::CheckedMul + num_traits::CheckedSub +
116 Decode + Encode,
117{}
118
119#[derive(Debug)]
121pub struct AnchorBlockId<Hash: std::fmt::Debug, Number: BlockNumber> {
122 pub hash: Hash,
124 pub number: Number,
126}
127
128pub struct State<'a, H, Number> {
130 pub config: Configuration,
132 pub zero: Number,
136 pub storage: &'a dyn Storage<H, Number>,
138}
139
140pub trait RootsStorage<H: Hasher, Number: BlockNumber>: Send + Sync {
142 fn build_anchor(&self, hash: H::Out) -> Result<AnchorBlockId<H::Out, Number>, String>;
144 fn root(&self, anchor: &AnchorBlockId<H::Out, Number>, block: Number) -> Result<Option<H::Out>, String>;
147}
148
149pub trait Storage<H: Hasher, Number: BlockNumber>: RootsStorage<H, Number> {
151 fn as_roots_storage(&self) -> &dyn RootsStorage<H, Number>;
153 fn with_cached_changed_keys(
156 &self,
157 root: &H::Out,
158 functor: &mut dyn FnMut(&HashMap<Option<PrefixedStorageKey>, HashSet<StorageKey>>),
159 ) -> bool;
160 fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String>;
162}
163
164pub struct TrieBackendStorageAdapter<'a, H: Hasher, Number: BlockNumber>(pub &'a dyn Storage<H, Number>);
166
167impl<'a, H: Hasher, N: BlockNumber> crate::TrieBackendStorage<H> for TrieBackendStorageAdapter<'a, H, N> {
168 type Overlay = tp_trie::MemoryDB<H>;
169
170 fn get(&self, key: &H::Out, prefix: Prefix) -> Result<Option<DBValue>, String> {
171 self.0.get(key, prefix)
172 }
173}
174
175pub type Configuration = tet_core::ChangesTrieConfiguration;
177
178#[derive(Clone)]
180pub struct ConfigurationRange<'a, N> {
181 pub config: &'a Configuration,
183 pub zero: N,
185 pub end: Option<N>,
187}
188
189impl<'a, H, Number> State<'a, H, Number> {
190 pub fn new(
192 config: Configuration,
193 zero: Number,
194 storage: &'a dyn Storage<H, Number>,
195 ) -> Self {
196 Self {
197 config,
198 zero,
199 storage,
200 }
201 }
202}
203
204impl<'a, H, Number: Clone> Clone for State<'a, H, Number> {
205 fn clone(&self) -> Self {
206 State {
207 config: self.config.clone(),
208 zero: self.zero.clone(),
209 storage: self.storage,
210 }
211 }
212}
213
214pub fn disabled_state<'a, H, Number>() -> Option<State<'a, H, Number>> {
216 None
217}
218
219pub fn build_changes_trie<'a, B: Backend<H>, H: Hasher, Number: BlockNumber>(
224 backend: &B,
225 state: Option<&'a State<'a, H, Number>>,
226 changes: &OverlayedChanges,
227 parent_hash: H::Out,
228 panic_on_storage_error: bool,
229) -> Result<Option<(MemoryDB<H>, H::Out, CacheAction<H::Out, Number>)>, ()>
230 where
231 H::Out: Ord + 'static + Encode,
232{
233 fn maybe_panic<R, E: std::fmt::Debug>(
235 res: std::result::Result<R, E>,
236 panic: bool,
237 ) -> std::result::Result<R, ()> {
238 res.map(Ok)
239 .unwrap_or_else(|e| if panic {
240 panic!("changes trie: storage access is not allowed to fail within runtime: {:?}", e)
241 } else {
242 Err(())
243 })
244 }
245
246 let state = match state {
248 Some(state) => state,
249 None => return Ok(None),
250 };
251
252 let parent = state.storage.build_anchor(parent_hash).map_err(|_| ())?;
254 let block = parent.number.clone() + One::one();
255
256 let is_config_changed = match changes.storage(tet_core::storage::well_known_keys::CHANGES_TRIE_CONFIG) {
259 Some(Some(new_config)) => new_config != &state.config.encode()[..],
260 Some(None) => true,
261 None => false,
262 };
263 let config_range = ConfigurationRange {
264 config: &state.config,
265 zero: state.zero.clone(),
266 end: if is_config_changed { Some(block.clone()) } else { None },
267 };
268
269 let (input_pairs, child_input_pairs, digest_input_blocks) = maybe_panic(
271 prepare_input::<B, H, Number>(
272 backend,
273 state.storage,
274 config_range.clone(),
275 changes,
276 &parent,
277 ),
278 panic_on_storage_error,
279 )?;
280
281 let mut cache_action = prepare_cached_build_data(config_range, block.clone());
283 let needs_changed_keys = cache_action.collects_changed_keys();
284 cache_action = cache_action.set_digest_input_blocks(digest_input_blocks);
285
286 let mut mdb = MemoryDB::default();
287 let mut child_roots = Vec::with_capacity(child_input_pairs.len());
288 for (child_index, input_pairs) in child_input_pairs {
289 let mut not_empty = false;
290 let mut root = Default::default();
291 {
292 let mut trie = TrieDBMut::<H>::new(&mut mdb, &mut root);
293 let mut storage_changed_keys = HashSet::new();
294 for input_pair in input_pairs {
295 if needs_changed_keys {
296 if let Some(key) = input_pair.key() {
297 storage_changed_keys.insert(key.to_vec());
298 }
299 }
300
301 let (key, value) = input_pair.into();
302 not_empty = true;
303 maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
304 }
305
306 cache_action = cache_action.insert(
307 Some(child_index.storage_key.clone()),
308 storage_changed_keys,
309 );
310 }
311 if not_empty {
312 child_roots.push(input::InputPair::ChildIndex(child_index, root.as_ref().to_vec()));
313 }
314 }
315 let mut root = Default::default();
316 {
317 let mut trie = TrieDBMut::<H>::new(&mut mdb, &mut root);
318 for (key, value) in child_roots.into_iter().map(Into::into) {
319 maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
320 }
321
322 let mut storage_changed_keys = HashSet::new();
323 for input_pair in input_pairs {
324 if needs_changed_keys {
325 if let Some(key) = input_pair.key() {
326 storage_changed_keys.insert(key.to_vec());
327 }
328 }
329
330 let (key, value) = input_pair.into();
331 maybe_panic(trie.insert(&key, &value), panic_on_storage_error)?;
332 }
333
334 cache_action = cache_action.insert(
335 None,
336 storage_changed_keys,
337 );
338 }
339
340 let cache_action = cache_action.complete(block, &root);
341 Ok(Some((mdb, root, cache_action)))
342}
343
344fn prepare_cached_build_data<Number: BlockNumber>(
346 config: ConfigurationRange<Number>,
347 block: Number,
348) -> IncompleteCacheAction<Number> {
349 if !config.config.is_digest_build_enabled() {
353 return IncompleteCacheAction::Clear;
354 }
355
356 if config.end.as_ref() == Some(&block) {
359 return IncompleteCacheAction::Clear;
360 }
361
362 match config.config.digest_level_at_block(config.zero.clone(), block) {
366 Some((digest_level, _, _)) if digest_level == config.config.digest_levels => IncompleteCacheAction::Clear,
367 _ => IncompleteCacheAction::CacheBuildData(IncompleteCachedBuildData::new()),
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374
375 #[test]
376 fn cache_is_cleared_when_digests_are_disabled() {
377 let config = Configuration { digest_interval: 0, digest_levels: 0 };
378 let config_range = ConfigurationRange { zero: 0, end: None, config: &config };
379 assert_eq!(prepare_cached_build_data(config_range, 8u32), IncompleteCacheAction::Clear);
380 }
381
382 #[test]
383 fn build_data_is_cached_when_digests_are_enabled() {
384 let config = Configuration { digest_interval: 8, digest_levels: 2 };
385 let config_range = ConfigurationRange { zero: 0, end: None, config: &config };
386 assert!(prepare_cached_build_data(config_range.clone(), 4u32).collects_changed_keys());
387 assert!(prepare_cached_build_data(config_range.clone(), 7u32).collects_changed_keys());
388 assert!(prepare_cached_build_data(config_range, 8u32).collects_changed_keys());
389 }
390
391 #[test]
392 fn cache_is_cleared_when_digests_are_enabled_and_top_level_digest_is_built() {
393 let config = Configuration { digest_interval: 8, digest_levels: 2 };
394 let config_range = ConfigurationRange { zero: 0, end: None, config: &config };
395 assert_eq!(prepare_cached_build_data(config_range, 64u32), IncompleteCacheAction::Clear);
396 }
397
398 #[test]
399 fn cache_is_cleared_when_end_block_of_configuration_is_built() {
400 let config = Configuration { digest_interval: 8, digest_levels: 2 };
401 let config_range = ConfigurationRange { zero: 0, end: Some(4u32), config: &config };
402 assert_eq!(prepare_cached_build_data(config_range.clone(), 4u32), IncompleteCacheAction::Clear);
403 }
404}