1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright 2019 Conflux Foundation. All rights reserved.
// Conflux is free software and distributed under GNU General Public License.
// See http://www.gnu.org/licenses/

use cfg_if::cfg_if;
cfg_if! {
    if #[cfg(test)] {
        pub const CHECK_LOADED_SNAPSHOT_MPT_NODE: bool = true;
    } else {
        pub const CHECK_LOADED_SNAPSHOT_MPT_NODE: bool = false;
    }
}

pub type SnapshotMptDbValue = Box<[u8]>;
/// We use `VanillaTrieNode<(MerkleHash, i64)>` instead of
/// `(VanillaTrieNode<MerkleHash>, i64)` to make seeking by rlp size position
/// faster.
#[derive(Clone, Default, Debug)]
pub struct SnapshotMptNode(pub VanillaTrieNode<SubtreeMerkleWithSize>);

#[derive(Copy, Clone, PartialEq, Debug, Default)]
pub struct SubtreeMerkleWithSize {
    pub merkle: MerkleHash,
    pub subtree_size: u64,
    // FIXME: delta_subtree_size should be cleared for skipped subtree during
    // FIXME: merge. It's non trivial for in-place update mode, for which we
    // FIXME: need a special subtree mark to be also taken into consideration
    // FIXME: while seeking.
    pub delta_subtree_size: u64,
}

// TODO: The key for SnapshotMpt should be changed to something else because
// TODO: we'd like to use a multi-version snapshot db to manage multiple
// TODO: snapshots.
pub trait SnapshotMptTraitRead: AsSnapshotMptTraitRead {
    fn get_merkle_root(&self) -> MerkleHash;
    fn load_node(
        &mut self, path: &dyn CompressedPathTrait,
    ) -> Result<Option<SnapshotMptNode>>;
}

pub trait AsSnapshotMptTraitRead {
    fn as_readonly(&mut self) -> &mut dyn SnapshotMptTraitRead;
}

impl<T: SnapshotMptTraitRead> AsSnapshotMptTraitRead for T {
    fn as_readonly(&mut self) -> &mut dyn SnapshotMptTraitRead { self }
}

pub trait SnapshotMptTraitReadAndIterate: SnapshotMptTraitRead {
    fn iterate_subtree_trie_nodes_without_root(
        &mut self, path: &dyn CompressedPathTrait,
    ) -> Result<Box<dyn SnapshotMptIteraterTrait + '_>>;
}

pub trait SnapshotMptTraitRw: SnapshotMptTraitReadAndIterate {
    fn delete_node(&mut self, path: &dyn CompressedPathTrait) -> Result<()>;
    fn write_node(
        &mut self, path: &dyn CompressedPathTrait, trie_node: &SnapshotMptNode,
    ) -> Result<()>;
}

// TODO: A snapshot mpt iterator is suitable to work as base_mpt in MptMerger's
// TODO: save-as mode, because MptMerger always access nodes in snapshot mpt in
// TODO: increasing order. we need to make special generalization for MptMerger
// TODO: to take SnapshotMptIteraterTrait as input.
pub trait SnapshotMptIteraterTrait:
    FallibleIterator<Item = (CompressedPathRaw, SnapshotMptNode), Error = Error>
{
}

impl<
        T: FallibleIterator<
            Item = (CompressedPathRaw, SnapshotMptNode),
            Error = Error,
        >,
    > SnapshotMptIteraterTrait for T
{
}

impl SnapshotMptNode {
    pub const NO_CHILD: SubtreeMerkleWithSize = SubtreeMerkleWithSize {
        merkle: MERKLE_NULL_NODE,
        subtree_size: 0,
        delta_subtree_size: 0,
    };

    pub fn is_valid(&self, path_to_node: &dyn CompressedPathTrait) -> bool {
        let mut valid = true;

        let children_merkles = self.get_children_merkles();
        let merkle_hash = self.compute_merkle(
            children_merkles.as_ref(),
            CompressedPathRaw::second_nibble(
                self.compressed_path_ref().path_mask(),
            ) != CompressedPathRaw::NO_MISSING_NIBBLE,
        );
        if self.get_merkle().ne(&merkle_hash) {
            error!(
                "merkle hash mismatch, expected {:?}, got {:?}, path_to_node {:?}",
                merkle_hash, self.get_merkle(), path_to_node,
            );
            valid = false;
        }
        let actual_children_count = children_merkles.as_ref().map_or(0, |v| {
            v.iter().filter(|&x| x.ne(&MERKLE_NULL_NODE)).count()
        });
        if self.get_children_count() as usize != actual_children_count {
            error!(
                "children count is wrong: expected {} got {}",
                actual_children_count,
                self.get_children_count(),
            );
            valid = false;
        }
        if path_to_node.path_size() > 0
            && !self.has_value()
            && self.get_children_count() <= 1
        {
            error!(
                "node should not exists due to path compressing rule, path_to_node {:?}, {:?}",
                path_to_node, self
            );
            valid = false
        }

        valid
    }

    pub fn load_rlp_and_check(
        rlp_bytes: &[u8], path_to_node: &dyn CompressedPathTrait,
    ) -> Result<Self> {
        let node = Self(Rlp::new(rlp_bytes).as_val()?);

        if CHECK_LOADED_SNAPSHOT_MPT_NODE {
            node.is_valid(path_to_node);
        }
        Ok(node)
    }

    pub fn subtree_size(&self, full_path: &dyn CompressedPathTrait) -> u64 {
        Self::initial_subtree_size(&self.0, full_path)
    }

    fn initial_subtree_size(
        node: &VanillaTrieNode<SubtreeMerkleWithSize>,
        full_path: &dyn CompressedPathTrait,
    ) -> u64 {
        let mut size = match node.value_as_slice().into_option() {
            None => 0,
            Some(value) => {
                rlp_key_value_len(full_path.path_size(), value.len())
            }
        };
        for (
            _child_index,
            &SubtreeMerkleWithSize {
                ref subtree_size, ..
            },
        ) in node.get_children_table_ref().iter()
        {
            size += subtree_size;
        }

        size
    }

    pub fn get_children_merkles(&self) -> MaybeMerkleTable {
        if self.get_children_count() > 0 {
            let mut merkle_table = Some(
                [ChildrenTableItem::<MerkleHash>::no_child().clone();
                    CHILDREN_COUNT],
            );
            for (child_index, &SubtreeMerkleWithSize { ref merkle, .. }) in
                self.get_children_table_ref().iter()
            {
                merkle_table.as_mut().unwrap()[child_index as usize] = *merkle;
            }
            merkle_table
        } else {
            None
        }
    }

    pub fn get_merkle_hash_wo_compressed_path(&self) -> MerkleHash {
        compute_node_merkle(
            self.get_children_merkles().as_ref(),
            self.0.value_as_slice().into_option(),
        )
    }
}

impl Decodable for SnapshotMptNode {
    fn decode(rlp: &Rlp) -> std::result::Result<Self, DecoderError> {
        Ok(Self(rlp.as_val()?))
    }
}

impl Deref for SnapshotMptNode {
    type Target = VanillaTrieNode<SubtreeMerkleWithSize>;

    fn deref(&self) -> &Self::Target { &self.0 }
}

impl DerefMut for SnapshotMptNode {
    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl Decodable for SubtreeMerkleWithSize {
    fn decode(rlp: &Rlp) -> std::result::Result<Self, DecoderError> {
        Ok(Self {
            merkle: rlp.val_at(0)?,
            subtree_size: rlp.val_at::<u64>(1)?,
            delta_subtree_size: rlp.val_at::<u64>(2)?,
        })
    }
}

impl Encodable for SubtreeMerkleWithSize {
    fn rlp_append(&self, s: &mut RlpStream) {
        s.begin_list(3)
            .append(&self.merkle)
            .append(&self.subtree_size)
            .append(&self.delta_subtree_size);
    }
}

impl NodeRefTrait for SubtreeMerkleWithSize {}

impl DefaultChildrenItem<SubtreeMerkleWithSize>
    for ChildrenTableItem<SubtreeMerkleWithSize>
{
    fn no_child() -> &'static SubtreeMerkleWithSize {
        &SnapshotMptNode::NO_CHILD
    }
}

use super::super::impls::{
    errors::*,
    merkle_patricia_trie::{
        merkle::{compute_node_merkle, MaybeMerkleTable},
        mpt_cursor::rlp_key_value_len,
        ChildrenTableItem, CompressedPathRaw, CompressedPathTrait,
        DefaultChildrenItem, NodeRefTrait, TrieNodeTrait, VanillaTrieNode,
        CHILDREN_COUNT,
    },
};
use fallible_iterator::FallibleIterator;
use primitives::{MerkleHash, MERKLE_NULL_NODE};
use rlp::*;
use std::ops::{Deref, DerefMut};