cfx_storage/impls/
proof_merger.rs

1// Copyright 2020 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5// `TrieProofMerger` and `StateProofMerger` allow us to combine multiple proofs
6// into a single proof. Any key that can be verified by any of the original
7// proofs can also be verified by the combined proof. While a single proof is
8// usually a path in the MPT from the root to a node, the combined proof is a
9// subtree rooted at the MPT's root.
10
11#[derive(Debug, Default)]
12struct TrieProofMerger {
13    hashes: HashSet<MerkleHash>,
14    nodes: Vec<TrieProofNode>,
15}
16
17impl TrieProofMerger {
18    pub fn merge(&mut self, proof: TrieProof) {
19        for node in proof.into_proof_nodes() {
20            if !self.hashes.contains(&node.get_merkle()) {
21                self.hashes.insert(*node.get_merkle());
22                self.nodes.push(node);
23            }
24        }
25    }
26
27    pub fn finish(self) -> Result<TrieProof> { TrieProof::new(self.nodes) }
28}
29
30#[derive(Debug, Default)]
31pub struct StateProofMerger {
32    delta: Option<TrieProofMerger>,
33    intermediate: Option<TrieProofMerger>,
34    snapshot: Option<TrieProofMerger>,
35}
36
37impl StateProofMerger {
38    pub fn merge(&mut self, proof: StateProof) {
39        let StateProof {
40            delta_proof,
41            intermediate_proof,
42            snapshot_proof,
43        } = proof;
44
45        if let Some(proof) = delta_proof {
46            match self.delta {
47                Some(ref mut merger) => merger.merge(proof),
48                None => {
49                    let mut merger = TrieProofMerger::default();
50                    merger.merge(proof);
51                    self.delta = Some(merger);
52                }
53            }
54        }
55
56        if let Some(proof) = intermediate_proof {
57            match self.intermediate {
58                Some(ref mut merger) => merger.merge(proof),
59                None => {
60                    let mut merger = TrieProofMerger::default();
61                    merger.merge(proof);
62                    self.intermediate = Some(merger);
63                }
64            }
65        }
66
67        if let Some(proof) = snapshot_proof {
68            match self.snapshot {
69                Some(ref mut merger) => merger.merge(proof),
70                None => {
71                    let mut merger = TrieProofMerger::default();
72                    merger.merge(proof);
73                    self.snapshot = Some(merger);
74                }
75            }
76        }
77    }
78
79    pub fn finish(self) -> Result<StateProof> {
80        let mut proof = StateProof::default();
81
82        if let Some(merger) = self.delta {
83            proof.with_delta(Some(merger.finish()?));
84        }
85
86        if let Some(merger) = self.intermediate {
87            proof.with_intermediate(Some(merger.finish()?));
88        }
89
90        if let Some(merger) = self.snapshot {
91            proof.with_snapshot(Some(merger.finish()?));
92        }
93
94        Ok(proof)
95    }
96}
97
98use crate::impls::{
99    errors::*,
100    merkle_patricia_trie::{trie_proof::TrieProofNode, TrieProof},
101    state_proof::StateProof,
102};
103use primitives::MerkleHash;
104use std::collections::HashSet;