tp_state_machine/changes_trie/
prune.rs1use tetsy_hash_db::Hasher;
21use tp_trie::Recorder;
22use log::warn;
23use num_traits::One;
24use crate::proving_backend::ProvingBackendRecorder;
25use crate::trie_backend_essence::TrieBackendEssence;
26use crate::changes_trie::{AnchorBlockId, Storage, BlockNumber};
27use crate::changes_trie::storage::TrieBackendAdapter;
28use crate::changes_trie::input::{ChildIndex, InputKey};
29use codec::{Decode, Codec};
30
31pub fn prune<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
36 storage: &dyn Storage<H, Number>,
37 first: Number,
38 last: Number,
39 current_block: &AnchorBlockId<H::Out, Number>,
40 mut remove_trie_node: F,
41) where H::Out: Codec {
42 let mut block = first;
44 loop {
45 if block >= last.clone() + One::one() {
46 break;
47 }
48
49 let prev_block = block.clone();
50 block += One::one();
51
52 let block = prev_block;
53 let root = match storage.root(current_block, block.clone()) {
54 Ok(Some(root)) => root,
55 Ok(None) => continue,
56 Err(error) => {
57 warn!(target: "trie", "Failed to read changes trie root from DB: {}", error);
59 continue;
60 },
61 };
62 let children_roots = {
63 let trie_storage = TrieBackendEssence::<_, H>::new(
64 crate::changes_trie::TrieBackendStorageAdapter(storage),
65 root,
66 );
67 let child_prefix = ChildIndex::key_neutral_prefix(block.clone());
68 let mut children_roots = Vec::new();
69 trie_storage.for_key_values_with_prefix(&child_prefix, |key, value| {
70 if let Ok(InputKey::ChildIndex::<Number>(_trie_key)) = Decode::decode(&mut &key[..]) {
71 if let Ok(value) = <Vec<u8>>::decode(&mut &value[..]) {
72 let mut trie_root = <H as Hasher>::Out::default();
73 trie_root.as_mut().copy_from_slice(&value[..]);
74 children_roots.push(trie_root);
75 }
76 }
77 });
78
79 children_roots
80 };
81 for root in children_roots.into_iter() {
82 prune_trie(storage, root, &mut remove_trie_node);
83 }
84
85 prune_trie(storage, root, &mut remove_trie_node);
86 }
87}
88
89fn prune_trie<H: Hasher, Number: BlockNumber, F: FnMut(H::Out)>(
91 storage: &dyn Storage<H, Number>,
92 root: H::Out,
93 remove_trie_node: &mut F,
94) where H::Out: Codec {
95
96 let mut proof_recorder: Recorder<H::Out> = Default::default();
99 {
100 let mut trie = ProvingBackendRecorder::<_, H> {
101 backend: &TrieBackendEssence::new(TrieBackendAdapter::new(storage), root),
102 proof_recorder: &mut proof_recorder,
103 };
104 trie.record_all_keys();
105 }
106
107 remove_trie_node(root);
109 for node in proof_recorder.drain().into_iter().map(|n| n.hash) {
110 remove_trie_node(node);
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use std::collections::HashSet;
117 use tp_trie::MemoryDB;
118 use tet_core::H256;
119 use crate::backend::insert_into_memory_db;
120 use crate::changes_trie::storage::InMemoryStorage;
121 use codec::Encode;
122 use tp_runtime::traits::BlakeTwo256;
123 use super::*;
124
125 fn prune_by_collect(
126 storage: &dyn Storage<BlakeTwo256, u64>,
127 first: u64,
128 last: u64,
129 current_block: u64,
130 ) -> HashSet<H256> {
131 let mut pruned_trie_nodes = HashSet::new();
132 let anchor = AnchorBlockId { hash: Default::default(), number: current_block };
133 prune(storage, first, last, &anchor,
134 |node| { pruned_trie_nodes.insert(node); });
135 pruned_trie_nodes
136 }
137
138 #[test]
139 fn prune_works() {
140 fn prepare_storage() -> InMemoryStorage<BlakeTwo256, u64> {
141 let child_info = tet_core::storage::ChildInfo::new_default(&b"1"[..]);
142 let child_key = ChildIndex { block: 67u64, storage_key: child_info.prefixed_storage_key() }.encode();
143 let mut mdb1 = MemoryDB::<BlakeTwo256>::default();
144 let root1 = insert_into_memory_db::<BlakeTwo256, _>(
145 &mut mdb1, vec![(vec![10], vec![20])]).unwrap();
146 let mut mdb2 = MemoryDB::<BlakeTwo256>::default();
147 let root2 = insert_into_memory_db::<BlakeTwo256, _>(
148 &mut mdb2,
149 vec![(vec![11], vec![21]), (vec![12], vec![22])],
150 ).unwrap();
151 let mut mdb3 = MemoryDB::<BlakeTwo256>::default();
152 let ch_root3 = insert_into_memory_db::<BlakeTwo256, _>(
153 &mut mdb3, vec![(vec![110], vec![120])]).unwrap();
154 let root3 = insert_into_memory_db::<BlakeTwo256, _>(&mut mdb3, vec![
155 (vec![13], vec![23]),
156 (vec![14], vec![24]),
157 (child_key, ch_root3.as_ref().encode()),
158 ]).unwrap();
159 let mut mdb4 = MemoryDB::<BlakeTwo256>::default();
160 let root4 = insert_into_memory_db::<BlakeTwo256, _>(
161 &mut mdb4,
162 vec![(vec![15], vec![25])],
163 ).unwrap();
164 let storage = InMemoryStorage::new();
165 storage.insert(65, root1, mdb1);
166 storage.insert(66, root2, mdb2);
167 storage.insert(67, root3, mdb3);
168 storage.insert(68, root4, mdb4);
169
170 storage
171 }
172
173 let storage = prepare_storage();
174 assert!(prune_by_collect(&storage, 20, 30, 90).is_empty());
175 assert!(!storage.into_mdb().drain().is_empty());
176
177 let storage = prepare_storage();
178 let prune60_65 = prune_by_collect(&storage, 60, 65, 90);
179 assert!(!prune60_65.is_empty());
180 storage.remove_from_storage(&prune60_65);
181 assert!(!storage.into_mdb().drain().is_empty());
182
183 let storage = prepare_storage();
184 let prune60_70 = prune_by_collect(&storage, 60, 70, 90);
185 assert!(!prune60_70.is_empty());
186 storage.remove_from_storage(&prune60_70);
187 assert!(storage.into_mdb().drain().is_empty());
188 }
189}