cfx_storage/impls/
state_proof.rs

1// Copyright 2019 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// FIXME: What's the proper way to express: 1) Proof not available;
6// FIXME: 2) What if Intermediate Delta Root is MERKLE_NULL_NODE.
7// TODO: Maybe create a new class for special situation when
8// TODO: a full node does not have full state proof, but it
9// TODO: could provide a shortcut proof with snapshot_proof
10// TODO: at intermediate_epoch_id with delta_proof.
11#[derive(Clone, Debug, Default, PartialEq, RlpEncodable, RlpDecodable)]
12pub struct StateProof {
13    pub delta_proof: Option<TrieProof>,
14    pub intermediate_proof: Option<TrieProof>,
15    pub snapshot_proof: Option<TrieProof>,
16}
17
18impl StateProof {
19    pub fn with_delta(
20        &mut self, maybe_delta_proof: Option<TrieProof>,
21    ) -> &mut Self {
22        self.delta_proof = maybe_delta_proof;
23        self
24    }
25
26    pub fn with_intermediate(
27        &mut self, maybe_intermediate_proof: Option<TrieProof>,
28    ) -> &mut Self {
29        self.intermediate_proof = maybe_intermediate_proof;
30        self
31    }
32
33    pub fn with_snapshot(
34        &mut self, maybe_snapshot_proof: Option<TrieProof>,
35    ) -> &mut Self {
36        self.snapshot_proof = maybe_snapshot_proof;
37        self
38    }
39
40    pub fn is_valid_kv(
41        &self, key: &Vec<u8>, value: Option<&[u8]>, root: StateRoot,
42        maybe_intermediate_padding: Option<DeltaMptKeyPadding>,
43    ) -> bool {
44        // Something is wrong when intermediate_proof exists but we are not able
45        // to get a intermediate padding.
46        if self.intermediate_proof.is_some()
47            && maybe_intermediate_padding.is_none()
48        {
49            return false;
50        }
51
52        let delta_root = &root.delta_root;
53        let intermediate_root = &root.intermediate_delta_root;
54        let snapshot_root = &root.snapshot_root;
55
56        let delta_mpt_padding = StorageKeyWithSpace::delta_mpt_padding(
57            &snapshot_root,
58            &intermediate_root,
59        );
60
61        let storage_key =
62            match StorageKeyWithSpace::from_key_bytes::<CheckInput>(&key) {
63                Ok(k) => k,
64                Err(e) => {
65                    warn!("Checking proof with invalid key: {:?}", e);
66                    return false;
67                }
68            };
69
70        let delta_mpt_key =
71            storage_key.to_delta_mpt_key_bytes(&delta_mpt_padding);
72        let maybe_intermediate_mpt_key = maybe_intermediate_padding
73            .as_ref()
74            .map(|p| storage_key.to_delta_mpt_key_bytes(p));
75
76        let tombstone_value = MptValue::<Box<[u8]>>::TombStone.unwrap();
77        let delta_value = if value.is_some() {
78            // Actual value.
79            value.clone()
80        } else {
81            // Tombstone value.
82            Some(&*tombstone_value)
83        };
84
85        // The delta proof must prove the key-value or key non-existence.
86        match &self.delta_proof {
87            Some(proof) => {
88                // Existence proof.
89                if proof.is_valid_kv(&delta_mpt_key, delta_value, delta_root) {
90                    return true;
91                }
92                // Non-existence proof.
93                if !proof.is_valid_kv(&delta_mpt_key, None, delta_root) {
94                    return false;
95                }
96            }
97            None => {
98                // When delta trie exists, the proof can't be empty.
99                if delta_root.ne(&MERKLE_NULL_NODE) {
100                    return false;
101                }
102            }
103        }
104
105        // Now check intermediate_proof since it's required. Same logic applies.
106        match &self.intermediate_proof {
107            Some(proof) => {
108                if proof.is_valid_kv(
109                    // It's guaranteed that
110                    // maybe_intermediate_mpt_key.is_some().
111                    maybe_intermediate_mpt_key.as_ref().unwrap(),
112                    delta_value,
113                    intermediate_root,
114                ) {
115                    return true;
116                }
117                if !proof.is_valid_kv(
118                    maybe_intermediate_mpt_key.as_ref().unwrap(),
119                    None,
120                    intermediate_root,
121                ) {
122                    return false;
123                }
124            }
125            None => {
126                // When intermediate trie exists, the proof can't be empty.
127                if intermediate_root.ne(&MERKLE_NULL_NODE) {
128                    return false;
129                }
130            }
131        }
132
133        // At last, check snapshot
134        match &self.snapshot_proof {
135            None => false,
136            Some(proof) => proof.is_valid_kv(key, value, snapshot_root),
137        }
138    }
139}
140
141use crate::impls::merkle_patricia_trie::TrieProof;
142use primitives::{
143    CheckInput, DeltaMptKeyPadding, MptValue, StateRoot, StorageKeyWithSpace,
144    MERKLE_NULL_NODE,
145};
146use rlp_derive::{RlpDecodable, RlpEncodable};