cfx_storage/impls/snapshot_sync/restoration/
full_sync_verifier.rs1pub struct FullSyncVerifier<SnapshotDbManager: SnapshotDbManagerTrait> {
6 number_chunks: usize,
7 merkle_root: MerkleHash,
8 chunk_boundaries: Vec<Vec<u8>>,
9 chunk_boundary_proofs: Vec<TrieProof>,
10 chunk_verified: Vec<bool>,
11 number_incomplete_chunk: usize,
12
13 pending_boundary_nodes: HashMap<CompressedPathRaw, SnapshotMptNode>,
14 boundary_subtree_total_size: HashMap<BoundarySubtreeIndex, u64>,
15 chunk_index_by_upper_key: HashMap<Vec<u8>, usize>,
16
17 temp_snapshot_db: SnapshotDbManager::SnapshotDbWrite,
18}
19
20impl<SnapshotDbManager: SnapshotDbManagerTrait>
21 FullSyncVerifier<SnapshotDbManager>
22{
23 pub fn new(
24 number_chunks: usize, chunk_boundaries: Vec<Vec<u8>>,
25 chunk_boundary_proofs: Vec<TrieProof>, merkle_root: MerkleHash,
26 snapshot_db_manager: &SnapshotDbManager, epoch_id: &EpochId,
27 epoch_height: u64,
28 ) -> Result<Self> {
29 if number_chunks != chunk_boundaries.len() + 1 {
30 bail!(Error::InvalidSnapshotSyncProof)
31 }
32 if number_chunks != chunk_boundary_proofs.len() + 1 {
33 bail!(Error::InvalidSnapshotSyncProof)
34 }
35 let mut chunk_index_by_upper_key = HashMap::new();
36 let mut prev_boundary: Option<&[u8]> = None;
37 for (chunk_index, (chunk_boundary, proof)) in chunk_boundaries
38 .iter()
39 .zip(chunk_boundary_proofs.iter())
40 .enumerate()
41 {
42 if let Some(prev) = prev_boundary {
46 if chunk_boundary.as_slice() <= prev {
47 bail!(Error::InvalidSnapshotSyncProof)
48 }
49 }
50 prev_boundary = Some(chunk_boundary.as_slice());
51 if chunk_boundary.len() > CompressedPathRaw::MAX_PATH_BYTES {
54 bail!(Error::InvalidSnapshotSyncProof)
55 }
56 if merkle_root.ne(proof.get_merkle_root()) {
57 bail!(Error::InvalidSnapshotSyncProof)
58 }
59 if proof.number_leaf_nodes() != 1 {
61 bail!(Error::InvalidSnapshotSyncProof)
62 }
63 if proof.if_proves_key(&*chunk_boundary)
64 != (true, proof.get_proof_nodes().last())
65 {
66 bail!(Error::InvalidSnapshotSyncProof)
67 }
68 chunk_index_by_upper_key
69 .insert(chunk_boundary.clone(), chunk_index);
70 }
71
72 Ok(Self {
73 number_chunks,
74 merkle_root,
75 chunk_boundaries,
76 chunk_boundary_proofs,
77 chunk_verified: vec![false; number_chunks],
78 number_incomplete_chunk: number_chunks,
79 pending_boundary_nodes: Default::default(),
80 boundary_subtree_total_size: Default::default(),
81 chunk_index_by_upper_key,
82 temp_snapshot_db: snapshot_db_manager
83 .new_temp_snapshot_for_full_sync(
84 epoch_id,
85 &merkle_root,
86 epoch_height,
87 )?,
88 })
89 }
90
91 pub fn is_completed(&self) -> bool { self.number_incomplete_chunk == 0 }
92
93 pub fn restore_chunk<Key: Borrow<[u8]> + Debug>(
95 &mut self, chunk_upper_key: &Option<Vec<u8>>, keys: &Vec<Key>,
96 values: Vec<Vec<u8>>,
97 ) -> Result<bool> {
98 let chunk_index = match chunk_upper_key {
99 None => self.number_chunks - 1,
100 Some(upper_key) => {
101 match self.chunk_index_by_upper_key.get(upper_key) {
102 Some(index) => *index,
103 None => {
104 warn!("chunk key {:?} does not match boundaries in manifest", upper_key);
105 return Ok(false);
106 }
107 }
108 }
109 };
110 for key in keys {
113 if key.borrow().len() > CompressedPathRaw::MAX_PATH_BYTES {
114 warn!("chunk contains an over-long key, rejecting chunk");
115 return Ok(false);
116 }
117 }
118
119 if !keys.is_empty() {
121 let mut previous = keys.first().unwrap();
122 for key in &keys[1..] {
123 if key.borrow().le(previous.borrow()) {
124 warn!("chunk key not in order");
125 return Ok(false);
126 }
127 previous = key;
128 }
129 }
130
131 let key_range_left;
132 let maybe_key_range_right_excl;
133 let maybe_left_proof;
134 let maybe_right_proof;
135 if chunk_index == 0 {
136 key_range_left = vec![];
137 maybe_left_proof = None;
138 } else {
139 key_range_left = self.chunk_boundaries[chunk_index - 1].clone();
140 maybe_left_proof = self.chunk_boundary_proofs.get(chunk_index - 1);
141
142 if let Some(first_key) = keys.first() {
144 if first_key.borrow().lt(&*key_range_left) {
145 warn!(
146 "first chunk key {:?} less than left range {:?}",
147 first_key, key_range_left
148 );
149 return Ok(false);
150 }
151 }
152 };
153 if chunk_index == self.number_chunks - 1 {
154 maybe_key_range_right_excl = None;
155 maybe_right_proof = None;
156 } else {
157 let key_range_right_excl =
158 self.chunk_boundaries[chunk_index].clone();
159 maybe_right_proof = self.chunk_boundary_proofs.get(chunk_index);
160
161 if let Some(last_key) = keys.last() {
163 if last_key.borrow().ge(&*key_range_right_excl) {
164 warn!(
165 "last chunk key {:?} larger than left range {:?}",
166 last_key, key_range_right_excl,
167 );
168 return Ok(false);
169 }
170 }
171
172 maybe_key_range_right_excl = Some(key_range_right_excl);
173 }
174
175 let chunk_verifier = MptSliceVerifier::new(
178 maybe_left_proof,
179 &*key_range_left,
180 maybe_right_proof,
181 maybe_key_range_right_excl.as_ref().map(|v| &**v),
182 self.merkle_root.clone(),
183 );
184
185 let chunk_rebuilder = chunk_verifier.restore(keys, &values)?;
186 if chunk_rebuilder.is_valid {
187 self.chunk_verified[chunk_index] = true;
188 self.number_incomplete_chunk -= 1;
189
190 self.temp_snapshot_db.start_transaction()?;
191 for (key, value) in keys.into_iter().zip(values.into_iter()) {
193 self.temp_snapshot_db.put_kv(key.borrow(), &*value)?;
194 }
195
196 let mut snapshot_mpt =
198 self.temp_snapshot_db.open_snapshot_mpt_owned()?;
199 for (path, node) in chunk_rebuilder.inner_nodes_to_write {
200 snapshot_mpt.write_node(&path, &node)?;
201 }
202 drop(snapshot_mpt);
203 self.temp_snapshot_db.commit_transaction()?;
204
205 for (path, node) in chunk_rebuilder.boundary_nodes {
207 let mut children_table = VanillaChildrenTable::default();
208 unsafe {
209 for (child_index, merkle_ref) in
210 node.get_children_table_ref().iter()
211 {
212 *children_table.get_child_mut_unchecked(child_index) =
213 SubtreeMerkleWithSize {
214 merkle: *merkle_ref,
215 subtree_size: 0,
216 delta_subtree_size: 0,
217 }
218 }
219 *children_table.get_children_count_mut() =
220 node.get_children_count();
221 }
222 self.pending_boundary_nodes.insert(
223 path,
224 SnapshotMptNode(VanillaTrieNode::new(
225 node.get_merkle().clone(),
226 children_table,
227 node.value_as_slice()
228 .into_option()
229 .map(|ref_v| ref_v.into()),
230 node.compressed_path_ref().into(),
231 )),
232 );
233 }
234 for (subtree_index, subtree_size) in
235 chunk_rebuilder.boundary_subtree_total_size
236 {
237 *self
238 .boundary_subtree_total_size
239 .entry(subtree_index)
240 .or_default() += subtree_size;
241 }
242 }
243
244 if self.is_completed() {
245 self.finalize()?
246 }
247
248 Ok(chunk_rebuilder.is_valid)
249 }
250
251 pub fn finalize(&mut self) -> Result<()> {
255 self.temp_snapshot_db.start_transaction()?;
256 let mut snapshot_mpt =
257 self.temp_snapshot_db.open_snapshot_mpt_owned()?;
258
259 for (path, mut node) in self.pending_boundary_nodes.drain() {
260 let mut subtree_index = BoundarySubtreeIndex {
261 parent_node: node.get_merkle().clone(),
262 child_index: 0,
263 };
264 for child_index in 0..CHILDREN_COUNT as u8 {
265 subtree_index.child_index = child_index;
266 if let Some(subtree_size) =
267 self.boundary_subtree_total_size.get(&subtree_index)
268 {
269 unsafe {
271 node.get_child_mut_unchecked(child_index)
272 .subtree_size = *subtree_size;
273 }
274 }
275 }
276
277 snapshot_mpt.write_node(&path, &node)?;
278 }
279
280 drop(snapshot_mpt);
281 self.temp_snapshot_db.commit_transaction()?;
282 Ok(())
283 }
284}
285
286use crate::{
287 impls::{
288 errors::*,
289 merkle_patricia_trie::{
290 trie_node::TrieNodeTrait, CompressedPathRaw, VanillaChildrenTable,
291 VanillaTrieNode, CHILDREN_COUNT,
292 },
293 snapshot_sync::restoration::mpt_slice_verifier::{
294 BoundarySubtreeIndex, MptSliceVerifier,
295 },
296 },
297 storage_db::{
298 SnapshotDbManagerTrait, SnapshotDbWriteableTrait, SnapshotMptNode,
299 SnapshotMptTraitRw, SubtreeMerkleWithSize,
300 },
301 TrieProof,
302};
303use primitives::{EpochId, MerkleHash};
304use std::{borrow::Borrow, collections::HashMap, fmt::Debug};