Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/executor/storage_diff.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2021  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! "Diff" between a trie and the next.
19
//!
20
//! Imagine two `HashMap<Vec<u8>, Vec<u8>>`s representing the content of a trie. This data
21
//! structure contains the difference from one to the other.
22
//!
23
//! This data structure can be used in a variety of circumstances, such as storing the storage
24
//! differences between a block and its child or storing on-going changes while a runtime call is
25
//! being performed. It can also be used to store an entire trie, by representing a diff where
26
//! the base is an empty trie.
27
//!
28
//! # About keys hashing
29
//!
30
//! This data structure internally uses a hash map. This hash map assumes that storage keys are
31
//! already uniformly distributed and doesn't perform any additional hashing.
32
//!
33
//! You should be aware that a malicious runtime could perform hash collision attacks that
34
//! considerably slow down this data structure.
35
//!
36
37
// TODO: is this module properly located?
38
39
// TODO: more docs
40
41
use alloc::{collections::BTreeMap, vec::Vec};
42
use core::{borrow::Borrow, cmp, fmt, ops};
43
use hashbrown::HashMap;
44
45
#[derive(Clone)]
46
pub struct TrieDiff<T = ()> {
47
    /// Contains the same entries as [`TrieDiff::hashmap`], except that values are booleans
48
    /// indicating whether the value updates (`true`) or deletes (`false`) the underlying
49
    /// storage item.
50
    btree: BTreeMap<Vec<u8>, bool>,
51
52
    /// Actual diff. For each key, `Some` if the underlying storage item is updated by this diff,
53
    /// and `None` if it is deleted.
54
    ///
55
    /// A FNV hasher is used because the runtime is supposed to guarantee a uniform distribution
56
    /// of storage keys.
57
    hashmap: HashMap<Vec<u8>, (Option<Vec<u8>>, T), fnv::FnvBuildHasher>,
58
}
59
60
impl<T> TrieDiff<T> {
61
    /// Builds a new empty diff.
62
33.3k
    pub fn empty() -> Self {
63
33.3k
        Self {
64
33.3k
            btree: BTreeMap::default(),
65
33.3k
            // TODO: with_capacity?
66
33.3k
            hashmap: HashMap::with_capacity_and_hasher(0, Default::default()),
67
33.3k
        }
68
33.3k
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyB6_
Line
Count
Source
62
33.2k
    pub fn empty() -> Self {
63
33.2k
        Self {
64
33.2k
            btree: BTreeMap::default(),
65
33.2k
            // TODO: with_capacity?
66
33.2k
            hashmap: HashMap::with_capacity_and_hasher(0, Default::default()),
67
33.2k
        }
68
33.2k
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsDDUKWWCHAU_18smoldot_light_wasm
_RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyB6_
Line
Count
Source
62
126
    pub fn empty() -> Self {
63
126
        Self {
64
126
            btree: BTreeMap::default(),
65
126
            // TODO: with_capacity?
66
126
            hashmap: HashMap::with_capacity_and_hasher(0, Default::default()),
67
126
        }
68
126
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsiLzmwikkc22_14json_rpc_basic
_RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
62
1
    pub fn empty() -> Self {
63
1
        Self {
64
1
            btree: BTreeMap::default(),
65
1
            // TODO: with_capacity?
66
1
            hashmap: HashMap::with_capacity_and_hasher(0, Default::default()),
67
1
        }
68
1
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff5emptyCsibGXYHQB8Ea_25json_rpc_general_requests
69
70
    /// Removes all the entries within this diff.
71
0
    pub fn clear(&mut self) {
72
0
        self.hashmap.clear();
73
0
        self.btree.clear();
74
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5clearB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5clearB6_
75
76
    /// Inserts the given key-value combination in the diff.
77
    ///
78
    /// Returns the value associated to this `key` that was previously in the diff, if any.
79
405k
    pub fn diff_insert(
80
405k
        &mut self,
81
405k
        key: impl Into<Vec<u8>>,
82
405k
        value: impl Into<Vec<u8>>,
83
405k
        user_data: T,
84
405k
    ) -> Option<(Option<Vec<u8>>, T)> {
85
405k
        let key = key.into();
86
405k
        // Note that we clone the key here. This is considered as a tolerable overhead.
87
405k
        let previous = self
88
405k
            .hashmap
89
405k
            .insert(key.clone(), (Some(value.into()), user_data));
90
143k
        match &previous {
91
            Some((Some(_), _)) => {
92
                // No need to update `btree`.
93
69.1k
                debug_assert_eq!(self.btree.get(&key), Some(&true));
94
            }
95
336k
            None | Some((None, _)) => {
96
336k
                self.btree.insert(key, true);
97
336k
            }
98
        }
99
405k
        previous
100
405k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1g_EB7_
Line
Count
Source
79
404k
    pub fn diff_insert(
80
404k
        &mut self,
81
404k
        key: impl Into<Vec<u8>>,
82
404k
        value: impl Into<Vec<u8>>,
83
404k
        user_data: T,
84
404k
    ) -> Option<(Option<Vec<u8>>, T)> {
85
404k
        let key = key.into();
86
404k
        // Note that we clone the key here. This is considered as a tolerable overhead.
87
404k
        let previous = self
88
404k
            .hashmap
89
404k
            .insert(key.clone(), (Some(value.into()), user_data));
90
143k
        match &previous {
91
            Some((Some(_), _)) => {
92
                // No need to update `btree`.
93
68.9k
                debug_assert_eq!(self.btree.get(&key), Some(&true));
94
            }
95
335k
            None | Some((None, _)) => {
96
335k
                self.btree.insert(key, true);
97
335k
            }
98
        }
99
404k
        previous
100
404k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertRShB1g_EB7_
Line
Count
Source
79
304
    pub fn diff_insert(
80
304
        &mut self,
81
304
        key: impl Into<Vec<u8>>,
82
304
        value: impl Into<Vec<u8>>,
83
304
        user_data: T,
84
304
    ) -> Option<(Option<Vec<u8>>, T)> {
85
304
        let key = key.into();
86
304
        // Note that we clone the key here. This is considered as a tolerable overhead.
87
304
        let previous = self
88
304
            .hashmap
89
304
            .insert(key.clone(), (Some(value.into()), user_data));
90
173
        match &previous {
91
            Some((Some(_), _)) => {
92
                // No need to update `btree`.
93
158
                debug_assert_eq!(self.btree.get(&key), Some(&true));
94
            }
95
146
            None | Some((None, _)) => {
96
146
                self.btree.insert(key, true);
97
146
            }
98
        }
99
304
        previous
100
304
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_EB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertRShB1h_EB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff11diff_insertINtNtCsdZExvAaxgia_5alloc3vec3VechEB1h_ECsibGXYHQB8Ea_25json_rpc_general_requests
101
102
    /// Inserts in the diff an entry at the given key that delete the value that is located in
103
    /// the base storage.
104
    ///
105
    /// Returns the value associated to this `key` that was previously in the diff, if any.
106
85.9k
    pub fn diff_insert_erase(
107
85.9k
        &mut self,
108
85.9k
        key: impl Into<Vec<u8>>,
109
85.9k
        user_data: T,
110
85.9k
    ) -> Option<(Option<Vec<u8>>, T)> {
111
85.9k
        let key = key.into();
112
85.9k
        // Note that we clone the key here. This is considered as a tolerable overhead.
113
85.9k
        let previous = self.hashmap.insert(key.clone(), (None, user_data));
114
69.4k
        match &previous {
115
            Some((None, _)) => {
116
                // No need to update `btree`.
117
0
                debug_assert_eq!(self.btree.get(&key), Some(&false));
118
            }
119
85.9k
            None | Some((Some(_), _)) => {
120
85.9k
                self.btree.insert(key, false);
121
85.9k
            }
122
        }
123
85.9k
        previous
124
85.9k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEEB7_
Line
Count
Source
106
85.8k
    pub fn diff_insert_erase(
107
85.8k
        &mut self,
108
85.8k
        key: impl Into<Vec<u8>>,
109
85.8k
        user_data: T,
110
85.8k
    ) -> Option<(Option<Vec<u8>>, T)> {
111
85.8k
        let key = key.into();
112
85.8k
        // Note that we clone the key here. This is considered as a tolerable overhead.
113
85.8k
        let previous = self.hashmap.insert(key.clone(), (None, user_data));
114
69.4k
        match &previous {
115
            Some((None, _)) => {
116
                // No need to update `btree`.
117
0
                debug_assert_eq!(self.btree.get(&key), Some(&false));
118
            }
119
85.8k
            None | Some((Some(_), _)) => {
120
85.8k
                self.btree.insert(key, false);
121
85.8k
            }
122
        }
123
85.8k
        previous
124
85.8k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseRShEB7_
Line
Count
Source
106
71
    pub fn diff_insert_erase(
107
71
        &mut self,
108
71
        key: impl Into<Vec<u8>>,
109
71
        user_data: T,
110
71
    ) -> Option<(Option<Vec<u8>>, T)> {
111
71
        let key = key.into();
112
71
        // Note that we clone the key here. This is considered as a tolerable overhead.
113
71
        let previous = self.hashmap.insert(key.clone(), (None, user_data));
114
52
        match &previous {
115
            Some((None, _)) => {
116
                // No need to update `btree`.
117
0
                debug_assert_eq!(self.btree.get(&key), Some(&false));
118
            }
119
71
            None | Some((Some(_), _)) => {
120
71
                self.btree.insert(key, false);
121
71
            }
122
        }
123
71
        previous
124
71
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseRShEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff17diff_insert_eraseINtNtCsdZExvAaxgia_5alloc3vec3VechEECsibGXYHQB8Ea_25json_rpc_general_requests
125
126
    /// Removes from the diff the entry corresponding to the given `key`.
127
    ///
128
    /// Returns the value associated to this `key` that was previously in the diff, if any.
129
0
    pub fn diff_remove(&mut self, key: impl AsRef<[u8]>) -> Option<(Option<Vec<u8>>, T)> {
130
0
        let previous = self.hashmap.remove(key.as_ref());
131
0
        if let Some(_previous) = &previous {
132
0
            let _in_btree = self.btree.remove(key.as_ref());
133
0
            debug_assert_eq!(_in_btree, Some(_previous.0.is_some()));
134
0
        }
135
0
        previous
136
0
    }
Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB3_8TrieDiffpE11diff_removepEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB3_8TrieDiffpE11diff_removepEB7_
137
138
    /// Returns the diff entry at the given key.
139
    ///
140
    /// Returns `None` if the diff doesn't have any entry for this key, and `Some((None, _))` if
141
    /// the diff has an entry that deletes the storage item.
142
313k
    pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> {
143
313k
        self.hashmap
144
313k
            .get(key)
145
313k
            .map(|(v, ud)| 
(v.as_ref().map(278k
|v|
&v[..]267k
), ud)278k
)
_RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0B8_
Line
Count
Source
145
278k
            .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud))
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff8diff_get0CsibGXYHQB8Ea_25json_rpc_general_requests
_RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00Ba_
Line
Count
Source
145
267k
            .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud))
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff8diff_get00CsibGXYHQB8Ea_25json_rpc_general_requests
146
313k
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getB6_
Line
Count
Source
142
313k
    pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> {
143
313k
        self.hashmap
144
313k
            .get(key)
145
313k
            .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud))
146
313k
    }
_RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getB6_
Line
Count
Source
142
84
    pub fn diff_get(&self, key: &[u8]) -> Option<(Option<&[u8]>, &T)> {
143
84
        self.hashmap
144
84
            .get(key)
145
84
            .map(|(v, ud)| (v.as_ref().map(|v| &v[..]), ud))
146
84
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff8diff_getCsibGXYHQB8Ea_25json_rpc_general_requests
147
148
    /// Returns an iterator to all the entries in the diff.
149
    ///
150
    /// Each value is either `Some` if the diff overwrites this diff, or `None` if it erases the
151
    /// underlying value.
152
0
    pub fn diff_iter_unordered(
153
0
        &self,
154
0
    ) -> impl ExactSizeIterator<Item = (&[u8], Option<&[u8]>, &T)> + Clone {
155
0
        self.hashmap
156
0
            .iter()
157
0
            .map(|(k, (v, ud))| (&k[..], v.as_ref().map(|v| &v[..]), ud))
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE19diff_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff19diff_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff19diff_iter_unordered0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB6_8TrieDiffpE19diff_iter_unordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff19diff_iter_unordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB6_8TrieDiff19diff_iter_unordered00CsiUjFBJteJ7x_17smoldot_full_node
158
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE19diff_iter_unorderedB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff19diff_iter_unorderedB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff19diff_iter_unorderedCsiUjFBJteJ7x_17smoldot_full_node
159
160
    /// Returns an iterator to all the entries in the diff.
161
    ///
162
    /// Each value is either `Some` if the diff overwrites this diff, or `None` if it erases the
163
    /// underlying value.
164
0
    pub fn diff_into_iter_unordered(
165
0
        self,
166
0
    ) -> impl ExactSizeIterator<Item = (Vec<u8>, Option<Vec<u8>>, T)> {
167
0
        self.hashmap.into_iter().map(|(k, (v, ud))| (k, v, ud))
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE24diff_into_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB4_8TrieDiffpE24diff_into_iter_unordered0B8_
168
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE24diff_into_iter_unorderedB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE24diff_into_iter_unorderedB6_
169
170
    /// Returns an iterator to all the entries in the diff within a given range.
171
    ///
172
    /// Each iterator element is the given and a boolean. This boolean is `true` if the diff
173
    /// overwrites this entry, or `false` if it erases the underlying value.
174
5.89M
    pub fn diff_range_ordered<U: ?Sized>(
175
5.89M
        &self,
176
5.89M
        range: impl ops::RangeBounds<U>,
177
5.89M
    ) -> impl Iterator<Item = (&[u8], bool)> + Clone
178
5.89M
    where
179
5.89M
        U: Ord,
180
5.89M
        Vec<u8>: Borrow<U>,
181
5.89M
    {
182
5.89M
        self.btree
183
5.89M
            .range(range)
184
5.89M
            .map(|(k, inserts)| 
(&k[..], *inserts)5.76M
)
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullE0B9_
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1p_EB1s_EE0B9_
Line
Count
Source
184
5.76M
            .map(|(k, inserts)| (&k[..], *inserts))
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1q_EB1t_EE0B9_
185
5.89M
    }
Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullEB7_
_RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1n_EB1q_EEB7_
Line
Count
Source
174
5.89M
    pub fn diff_range_ordered<U: ?Sized>(
175
5.89M
        &self,
176
5.89M
        range: impl ops::RangeBounds<U>,
177
5.89M
    ) -> impl Iterator<Item = (&[u8], bool)> + Clone
178
5.89M
    where
179
5.89M
        U: Ord,
180
5.89M
        Vec<u8>: Borrow<U>,
181
5.89M
    {
182
5.89M
        self.btree
183
5.89M
            .range(range)
184
5.89M
            .map(|(k, inserts)| (&k[..], *inserts))
185
5.89M
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedINtNtCsdZExvAaxgia_5alloc3vec3VechENtNtNtCsaYZPK01V26L_4core3ops5range9RangeFullEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB3_8TrieDiff18diff_range_orderedShTINtNtNtCsaYZPK01V26L_4core3ops5range5BoundRB1o_EB1r_EEB7_
186
187
    /// Returns the storage key that immediately follows the provided `key`. Must be passed the
188
    /// storage key that immediately follows the provided `key` according to the base storage this
189
    /// diff is based upon.
190
    ///
191
    /// If [`StorageNextKey::Found`] is returned, it contains the desired key. If
192
    /// [`StorageNextKey::NextOf`] is returned, then this function should be called again but by
193
    /// passing the `key` found in the [`StorageNextKey::NextOf`] (and of course the corresponding
194
    /// `in_parent_next_key`).
195
    ///
196
    /// # Panic
197
    ///
198
    /// Panics if `in_parent_next_key` is provided and is inferior or equal to `key`.
199
    ///
200
1
    pub fn storage_next_key<'a>(
201
1
        &'a self,
202
1
        key: &'_ [u8],
203
1
        in_parent_next_key: Option<&'a [u8]>,
204
1
        or_equal: bool,
205
1
    ) -> StorageNextKey<'a> {
206
1
        if let Some(in_parent_next_key) = in_parent_next_key {
207
1
            assert!(in_parent_next_key > key);
208
0
        }
209
210
        // Find the diff entry that immediately follows `key`.
211
1
        let in_diff = self
212
1
            .btree
213
1
            .range::<[u8], _>((
214
1
                if or_equal {
215
0
                    ops::Bound::Included(key)
216
                } else {
217
1
                    ops::Bound::Excluded(key)
218
                },
219
1
                ops::Bound::Unbounded,
220
1
            ))
221
1
            .next();
222
1
223
1
        match (in_parent_next_key, in_diff) {
224
0
            (Some(a), Some((b, true))) if a <= &b[..] => StorageNextKey::Found(Some(a)),
225
0
            (Some(a), Some((b, false))) if a < &b[..] => StorageNextKey::Found(Some(a)),
226
0
            (Some(a), Some((b, false))) => {
227
0
                debug_assert!(a >= &b[..]); // We actually expect `a == b` but let's be defensive.
228
0
                debug_assert!(&b[..] > key || or_equal);
229
230
                // The next key according to the parent storage has been erased in this diff. It
231
                // is necessary to ask the user again, this time for the key after the one that
232
                // has been erased.
233
234
                // Note that there is probably something wrong here if `a != b`, but we ignore
235
                // that here.
236
237
0
                StorageNextKey::NextOf(b)
238
            }
239
0
            (Some(a), Some((b, true))) => {
240
0
                debug_assert!(a >= &b[..]);
241
0
                StorageNextKey::Found(Some(&b[..]))
242
            }
243
244
1
            (Some(a), None) => StorageNextKey::Found(Some(a)),
245
0
            (None, Some((b, true))) => StorageNextKey::Found(Some(&b[..])),
246
0
            (None, Some((b, false))) => {
247
0
                debug_assert!(&b[..] > key || or_equal);
248
0
                let found = self
249
0
                    .btree
250
0
                    .range::<[u8], _>((ops::Bound::Excluded(&b[..]), ops::Bound::Unbounded))
251
0
                    .find(|(_, value)| **value)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_key0CsibGXYHQB8Ea_25json_rpc_general_requests
252
0
                    .map(|(key, _)| &key[..]);
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB4_8TrieDiff16storage_next_keys_0CsibGXYHQB8Ea_25json_rpc_general_requests
253
0
                StorageNextKey::Found(found)
254
            }
255
0
            (None, None) => StorageNextKey::Found(None),
256
        }
257
1
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyB6_
Line
Count
Source
200
1
    pub fn storage_next_key<'a>(
201
1
        &'a self,
202
1
        key: &'_ [u8],
203
1
        in_parent_next_key: Option<&'a [u8]>,
204
1
        or_equal: bool,
205
1
    ) -> StorageNextKey<'a> {
206
1
        if let Some(in_parent_next_key) = in_parent_next_key {
207
1
            assert!(in_parent_next_key > key);
208
0
        }
209
210
        // Find the diff entry that immediately follows `key`.
211
1
        let in_diff = self
212
1
            .btree
213
1
            .range::<[u8], _>((
214
1
                if or_equal {
215
0
                    ops::Bound::Included(key)
216
                } else {
217
1
                    ops::Bound::Excluded(key)
218
                },
219
1
                ops::Bound::Unbounded,
220
1
            ))
221
1
            .next();
222
1
223
1
        match (in_parent_next_key, in_diff) {
224
0
            (Some(a), Some((b, true))) if a <= &b[..] => StorageNextKey::Found(Some(a)),
225
0
            (Some(a), Some((b, false))) if a < &b[..] => StorageNextKey::Found(Some(a)),
226
0
            (Some(a), Some((b, false))) => {
227
0
                debug_assert!(a >= &b[..]); // We actually expect `a == b` but let's be defensive.
228
0
                debug_assert!(&b[..] > key || or_equal);
229
230
                // The next key according to the parent storage has been erased in this diff. It
231
                // is necessary to ask the user again, this time for the key after the one that
232
                // has been erased.
233
234
                // Note that there is probably something wrong here if `a != b`, but we ignore
235
                // that here.
236
237
0
                StorageNextKey::NextOf(b)
238
            }
239
0
            (Some(a), Some((b, true))) => {
240
0
                debug_assert!(a >= &b[..]);
241
0
                StorageNextKey::Found(Some(&b[..]))
242
            }
243
244
1
            (Some(a), None) => StorageNextKey::Found(Some(a)),
245
0
            (None, Some((b, true))) => StorageNextKey::Found(Some(&b[..])),
246
0
            (None, Some((b, false))) => {
247
0
                debug_assert!(&b[..] > key || or_equal);
248
0
                let found = self
249
0
                    .btree
250
0
                    .range::<[u8], _>((ops::Bound::Excluded(&b[..]), ops::Bound::Unbounded))
251
0
                    .find(|(_, value)| **value)
252
0
                    .map(|(key, _)| &key[..]);
253
0
                StorageNextKey::Found(found)
254
            }
255
0
            (None, None) => StorageNextKey::Found(None),
256
        }
257
1
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsDDUKWWCHAU_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCscDgN54JpMGG_6author
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB2_8TrieDiff16storage_next_keyCsibGXYHQB8Ea_25json_rpc_general_requests
258
259
    /// Applies the given diff on top of the current one.
260
0
    pub fn merge(&mut self, other: &TrieDiff<T>)
261
0
    where
262
0
        T: Clone,
263
0
    {
264
0
        self.merge_map(other, |v| v.clone())
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB4_8TrieDiffpE5merge0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB4_8TrieDiffpE5merge0B8_
265
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5mergeB6_
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB2_8TrieDiffpE5mergeB6_
266
267
    /// Applies the given diff on top of the current one.
268
    ///
269
    /// Each user data in the other diff is first passed through the map.
270
0
    pub fn merge_map<U>(&mut self, other: &TrieDiff<U>, mut map: impl FnMut(&U) -> T) {
271
        // TODO: provide an alternative method that consumes `other` as well?
272
0
        for (key, (value, user_data)) in &other.hashmap {
273
0
            self.hashmap
274
0
                .insert(key.clone(), (value.clone(), map(user_data)));
275
0
            self.btree.insert(key.clone(), value.is_some());
276
0
        }
277
0
    }
Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffINtB3_8TrieDiffpE9merge_mapppEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8executor12storage_diffINtB3_8TrieDiffpE9merge_mapppEB7_
278
}
279
280
impl<T> fmt::Debug for TrieDiff<T>
281
where
282
    T: fmt::Debug,
283
{
284
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285
0
        // Delegate to `self.inner`
286
0
        fmt::Debug::fmt(&self.hashmap, f)
287
0
    }
Unexecuted instantiation: _RNvXs_NtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB4_8TrieDiffNtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB8_
Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs_0pEINtB5_8TrieDiffpENtNtCsaYZPK01V26L_4core3fmt5Debug3fmtB9_
288
}
289
290
// We implement `PartialEq` manually, because deriving it would mean that both the hash map and
291
// the tree are compared.
292
impl<T, U> cmp::PartialEq<TrieDiff<U>> for TrieDiff<T>
293
where
294
    T: cmp::PartialEq<U>,
295
{
296
0
    fn eq(&self, other: &TrieDiff<U>) -> bool {
297
0
        // As of the writing of this code, HashMap<K, T> doesn't implement
298
0
        // PartialEq<HashMap<K, U>> where T: PartialEq<U>, so we have to implement it manually. The
299
0
        // way this is implemented matches what the underlying implementation of HashMap does.
300
0
        if self.hashmap.len() != other.hashmap.len() {
301
0
            return false;
302
0
        }
303
0
304
0
        self.hashmap.iter().all(|(key, (v1, u1))| {
305
0
            other
306
0
                .hashmap
307
0
                .get(key)
308
0
                .map_or(false, |(v2, u2)| *v1 == *v2 && *u1 == *u2)
Unexecuted instantiation: _RNCNCNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB9_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB13_pEE2eq00Bd_
Unexecuted instantiation: _RNCNCNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB9_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB14_pEE2eq00Bd_
309
0
        })
Unexecuted instantiation: _RNCNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB7_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB11_pEE2eq0Bb_
Unexecuted instantiation: _RNCNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB7_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB12_pEE2eq0Bb_
310
0
    }
Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs0_0ppEINtB5_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIBZ_pEE2eqB9_
Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs0_0ppEINtB5_8TrieDiffpEINtNtCsaYZPK01V26L_4core3cmp9PartialEqIB10_pEE2eqB9_
311
}
312
313
impl<T> cmp::Eq for TrieDiff<T> where T: cmp::Eq {}
314
315
impl<T> Default for TrieDiff<T> {
316
135
    fn default() -> Self {
317
135
        TrieDiff::empty()
318
135
    }
_RNvXs2_NtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultB9_
Line
Count
Source
316
8
    fn default() -> Self {
317
8
        TrieDiff::empty()
318
8
    }
Unexecuted instantiation: _RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultCsDDUKWWCHAU_18smoldot_light_wasm
_RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultB9_
Line
Count
Source
316
126
    fn default() -> Self {
317
126
        TrieDiff::empty()
318
126
    }
_RNvXs2_NtNtCseuYC0Zibziv_7smoldot8executor12storage_diffNtB5_8TrieDiffNtNtCsaYZPK01V26L_4core7default7Default7defaultCsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
316
1
    fn default() -> Self {
317
1
        TrieDiff::empty()
318
1
    }
319
}
320
321
impl<T> FromIterator<(Vec<u8>, Option<Vec<u8>>, T)> for TrieDiff<T> {
322
0
    fn from_iter<I>(iter: I) -> Self
323
0
    where
324
0
        I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>, T)>,
325
0
    {
326
0
        let hashmap = iter
327
0
            .into_iter()
328
0
            .map(|(k, v, ud)| (k, (v, ud)))
Unexecuted instantiation: _RNCINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_6option6OptionB2i_EpEE9from_iterpE0Bc_
Unexecuted instantiation: _RNCINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1r_6option6OptionB2j_EpEE9from_iterpE0Bc_
329
0
            .collect::<HashMap<Vec<u8>, (Option<Vec<u8>>, T), fnv::FnvBuildHasher>>();
330
0
        let btree = hashmap
331
0
            .iter()
332
0
            .map(|(k, (v, _))| (k.clone(), v.is_some()))
Unexecuted instantiation: _RNCINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_6option6OptionB2i_EpEE9from_iterpEs_0Bc_
Unexecuted instantiation: _RNCINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB8_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1r_6option6OptionB2j_EpEE9from_iterpEs_0Bc_
333
0
            .collect();
334
0
335
0
        Self { btree, hashmap }
336
0
    }
Unexecuted instantiation: _RINvXININtNtCsN16ciHI6Qf_7smoldot8executor12storage_diffs3_0pEINtB6_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1o_6option6OptionB2g_EpEE9from_iterpEBa_
Unexecuted instantiation: _RINvXININtNtCseuYC0Zibziv_7smoldot8executor12storage_diffs3_0pEINtB6_8TrieDiffpEINtNtNtNtCsaYZPK01V26L_4core4iter6traits7collect12FromIteratorTINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1p_6option6OptionB2h_EpEE9from_iterpEBa_
337
}
338
339
pub enum StorageNextKey<'a> {
340
    Found(Option<&'a [u8]>),
341
    NextOf(&'a [u8]),
342
}