Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/lib/src/database/full_sqlite.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  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
//! Filesystem-backed database containing all the information about a chain.
19
//!
20
//! This module handles the persistent storage of the chain on disk.
21
//!
22
//! # Usage
23
//!
24
//! Use the [`open()`] function to create a new database or open an existing one. [`open()`]
25
//! returns a [`DatabaseOpen`] enum. This enum will contain either a [`SqliteFullDatabase`] object,
26
//! representing an access to the database, or a [`DatabaseEmpty`] if the database didn't exist or
27
//! is empty. If that is the case, use [`DatabaseEmpty::initialize`] in order to populate it and
28
//! obtain a [`SqliteFullDatabase`].
29
//!
30
//! Use [`SqliteFullDatabase::insert`] to insert a new block in the database. The block is assumed
31
//! to have been successfully verified prior to insertion. An error is returned if this block is
32
//! already in the database or isn't a descendant or ancestor of the latest finalized block.
33
//!
34
//! Use [`SqliteFullDatabase::set_finalized`] to mark a block already in the database as finalized.
35
//! Any block that isn't an ancestor or descendant will be removed. Reverting finalization is
36
//! not supported.
37
//!
38
//! In order to minimize disk usage, it is not possible to efficiently retrieve the storage items
39
//! of blocks that are ancestors of the finalized block. When a block is finalized, the storage of
40
//! its ancestors is lost, and the only way to reconstruct it is to execute all blocks starting
41
//! from the genesis to the desired one.
42
//!
43
//! # About errors handling
44
//!
45
//! Most of the functions and methods in this module return a `Result` containing notably an
46
//! [`CorruptedError`]. This kind of errors can happen if the operating system returns an error
47
//! when accessing the file system, or if the database has been corrupted, for example by the user
48
//! manually modifying it.
49
//!
50
//! There isn't much that can be done to properly handle an [`CorruptedError`]. The only
51
//! reasonable solutions are either to stop the program, or to delete the entire database and
52
//! recreate it.
53
//!
54
//! # Schema
55
//!
56
//! The SQL schema of the database, with explanatory comments, can be found in `open.rs`.
57
//!
58
//! # About blocking behavior
59
//!
60
//! This implementation uses the SQLite library, which isn't Rust-asynchronous-compatible. Many
61
//! functions will, with the help of the operating system, put the current thread to sleep while
62
//! waiting for an I/O operation to finish. In the context of asynchronous Rust, this is
63
//! undesirable.
64
//!
65
//! For this reason, you are encouraged to isolate the database in its own threads and never
66
//! access it directly from an asynchronous context.
67
//!
68
69
// TODO: better docs
70
71
#![cfg(feature = "database-sqlite")]
72
#![cfg_attr(docsrs, doc(cfg(feature = "database-sqlite")))]
73
74
use crate::{
75
    chain::chain_information,
76
    executor::{self, host},
77
    header, trie,
78
};
79
80
use alloc::borrow::Cow;
81
use core::{fmt, iter};
82
use parking_lot::Mutex;
83
use rusqlite::OptionalExtension as _;
84
85
pub use open::{open, Config, ConfigTy, DatabaseEmpty, DatabaseOpen};
86
87
mod open;
88
mod tests;
89
90
/// Returns an opaque string representing the version number of the SQLite library this binary
91
/// is using.
92
21
pub fn sqlite_version() -> &'static str {
93
21
    rusqlite::version()
94
21
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14sqlite_version
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14sqlite_version
Line
Count
Source
92
21
pub fn sqlite_version() -> &'static str {
93
21
    rusqlite::version()
94
21
}
95
96
/// An open database. Holds file descriptors.
97
pub struct SqliteFullDatabase {
98
    /// The SQLite connection.
99
    ///
100
    /// The database is constantly within a transaction.
101
    /// When the database is opened, `BEGIN TRANSACTION` is immediately run. We periodically
102
    /// call `COMMIT; BEGIN_TRANSACTION` when deemed necessary. `COMMIT` is basically the
103
    /// equivalent of `fsync`, and must be called carefully in order to not lose too much speed.
104
    database: Mutex<rusqlite::Connection>,
105
106
    /// Number of bytes used to encode the block number.
107
    block_number_bytes: usize,
108
}
109
110
impl SqliteFullDatabase {
111
    /// Returns the hash of the block in the database whose storage is currently accessible.
112
26
    pub fn best_block_hash(&self) -> Result<[u8; 32], CorruptedError> {
113
26
        let connection = self.database.lock();
114
115
26
        let val = meta_get_blob(&connection, "best")
?0
.ok_or(CorruptedError::MissingMetaKey)
?0
;
116
26
        if val.len() == 32 {
117
26
            let mut out = [0; 32];
118
26
            out.copy_from_slice(&val);
119
26
            Ok(out)
120
        } else {
121
0
            Err(CorruptedError::InvalidBlockHashLen)
122
        }
123
26
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase15best_block_hash
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase15best_block_hash
Line
Count
Source
112
26
    pub fn best_block_hash(&self) -> Result<[u8; 32], CorruptedError> {
113
26
        let connection = self.database.lock();
114
115
26
        let val = meta_get_blob(&connection, "best")
?0
.ok_or(CorruptedError::MissingMetaKey)
?0
;
116
26
        if val.len() == 32 {
117
26
            let mut out = [0; 32];
118
26
            out.copy_from_slice(&val);
119
26
            Ok(out)
120
        } else {
121
0
            Err(CorruptedError::InvalidBlockHashLen)
122
        }
123
26
    }
124
125
    /// Returns the hash of the finalized block in the database.
126
1.10k
    pub fn finalized_block_hash(&self) -> Result<[u8; 32], CorruptedError> {
127
1.10k
        let database = self.database.lock();
128
1.10k
        finalized_hash(&database)
129
1.10k
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20finalized_block_hash
Line
Count
Source
126
1.02k
    pub fn finalized_block_hash(&self) -> Result<[u8; 32], CorruptedError> {
127
1.02k
        let database = self.database.lock();
128
1.02k
        finalized_hash(&database)
129
1.02k
    }
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20finalized_block_hash
Line
Count
Source
126
84
    pub fn finalized_block_hash(&self) -> Result<[u8; 32], CorruptedError> {
127
84
        let database = self.database.lock();
128
84
        finalized_hash(&database)
129
84
    }
130
131
    /// Returns the SCALE-encoded header of the given block, or `None` if the block is unknown.
132
    ///
133
    /// > **Note**: If this method is called twice times in a row with the same block hash, it
134
    /// >           is possible for the first time to return `Some` and the second time to return
135
    /// >           `None`, in case the block has since been removed from the database.
136
129
    pub fn block_scale_encoded_header(
137
129
        &self,
138
129
        block_hash: &[u8; 32],
139
129
    ) -> Result<Option<Vec<u8>>, CorruptedError> {
140
129
        let connection = self.database.lock();
141
142
129
        let out = connection
143
129
            .prepare_cached(r#"SELECT header FROM blocks WHERE hash = ?"#)
144
129
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_header0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_header0B8_
145
129
            .query_row((&block_hash[..],), |row| 
row.get::<_, Vec<u8>>(0)128
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_headers_0B8_
_RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_headers_0B8_
Line
Count
Source
145
128
            .query_row((&block_hash[..],), |row| row.get::<_, Vec<u8>>(0))
146
129
            .optional()
147
129
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_headers0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase26block_scale_encoded_headers0_0B8_
148
149
129
        Ok(out)
150
129
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase26block_scale_encoded_header
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase26block_scale_encoded_header
Line
Count
Source
136
129
    pub fn block_scale_encoded_header(
137
129
        &self,
138
129
        block_hash: &[u8; 32],
139
129
    ) -> Result<Option<Vec<u8>>, CorruptedError> {
140
129
        let connection = self.database.lock();
141
142
129
        let out = connection
143
129
            .prepare_cached(r#"SELECT header FROM blocks WHERE hash = ?"#)
144
129
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
145
129
            .query_row((&block_hash[..],), |row| row.get::<_, Vec<u8>>(0))
146
129
            .optional()
147
129
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
148
149
129
        Ok(out)
150
129
    }
151
152
    /// Returns the hash of the parent of the given block, or `None` if the block is unknown.
153
    ///
154
    /// > **Note**: If this method is called twice times in a row with the same block hash, it
155
    /// >           is possible for the first time to return `Some` and the second time to return
156
    /// >           `None`, in case the block has since been removed from the database.
157
0
    pub fn block_parent(&self, block_hash: &[u8; 32]) -> Result<Option<[u8; 32]>, CorruptedError> {
158
0
        let connection = self.database.lock();
159
160
0
        let out = connection
161
0
            .prepare_cached(r#"SELECT parent_hash FROM blocks WHERE hash = ?"#)
162
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parent0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parent0B8_
163
0
            .query_row((&block_hash[..],), |row| row.get::<_, [u8; 32]>(0))
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parents_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parents_0B8_
164
0
            .optional()
165
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parents0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase12block_parents0_0B8_
166
167
0
        Ok(out)
168
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase12block_parent
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase12block_parent
169
170
    /// Returns the list of extrinsics of the given block, or `None` if the block is unknown.
171
    ///
172
    /// > **Note**: The list of extrinsics of a block is also known as its *body*.
173
    ///
174
    /// > **Note**: If this method is called twice times in a row with the same block hash, it
175
    /// >           is possible for the first time to return `Some` and the second time to return
176
    /// >           `None`, in case the block has since been removed from the database.
177
0
    pub fn block_extrinsics(
178
0
        &self,
179
0
        block_hash: &[u8; 32],
180
0
    ) -> Result<Option<impl ExactSizeIterator<Item = Vec<u8>>>, CorruptedError> {
181
0
        let connection = self.database.lock();
182
183
        // TODO: doesn't detect if block is absent
184
185
0
        let result = connection
186
0
            .prepare_cached(r#"SELECT extrinsic FROM blocks_body WHERE hash = ? ORDER BY idx ASC"#)
187
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsics0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsics0B8_
188
0
            .query_map((&block_hash[..],), |row| row.get::<_, Vec<u8>>(0))
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss_0B8_
189
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss0_0B8_
190
0
            .collect::<Result<Vec<_>, _>>()
191
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase16block_extrinsicss1_0B8_
192
193
0
        Ok(Some(result.into_iter()))
194
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase16block_extrinsics
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase16block_extrinsics
195
196
    /// Returns the hashes of the blocks given a block number.
197
45
    pub fn block_hash_by_number(
198
45
        &self,
199
45
        block_number: u64,
200
45
    ) -> Result<impl ExactSizeIterator<Item = [u8; 32]>, CorruptedError> {
201
45
        let connection = self.database.lock();
202
45
        let result = block_hashes_by_number(&connection, block_number)
?0
;
203
45
        Ok(result.into_iter())
204
45
    }
_RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20block_hash_by_number
Line
Count
Source
197
45
    pub fn block_hash_by_number(
198
45
        &self,
199
45
        block_number: u64,
200
45
    ) -> Result<impl ExactSizeIterator<Item = [u8; 32]>, CorruptedError> {
201
45
        let connection = self.database.lock();
202
45
        let result = block_hashes_by_number(&connection, block_number)
?0
;
203
45
        Ok(result.into_iter())
204
45
    }
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20block_hash_by_number
205
206
    /// Returns the hash of the block of the best chain given a block number.
207
1
    pub fn best_block_hash_by_number(
208
1
        &self,
209
1
        block_number: u64,
210
1
    ) -> Result<Option<[u8; 32]>, CorruptedError> {
211
1
        let connection = self.database.lock();
212
213
1
        let block_number = match i64::try_from(block_number) {
214
1
            Ok(n) => n,
215
0
            Err(_) => return Ok(None),
216
        };
217
218
1
        let result = connection
219
1
            .prepare_cached(r#"SELECT hash FROM blocks WHERE number = ? AND is_best_chain = TRUE"#)
220
1
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_number0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_number0B8_
221
1
            .query_row((block_number,), |row| 
row.get::<_, Vec<u8>>(0)0
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers_0B8_
222
1
            .optional()
223
1
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers0_0B8_
224
1
            .and_then(|value| {
225
1
                let Some(
value0
) = value else { return Ok(None) };
226
                Ok(Some(
227
0
                    <[u8; 32]>::try_from(&value[..])
228
0
                        .map_err(|_| CorruptedError::InvalidBlockHashLen)?,
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase25best_block_hash_by_numbers1_00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase25best_block_hash_by_numbers1_00Ba_
229
                ))
230
1
            })
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers1_0B8_
_RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase25best_block_hash_by_numbers1_0B8_
Line
Count
Source
224
1
            .and_then(|value| {
225
1
                let Some(
value0
) = value else { return Ok(None) };
226
                Ok(Some(
227
0
                    <[u8; 32]>::try_from(&value[..])
228
0
                        .map_err(|_| CorruptedError::InvalidBlockHashLen)?,
229
                ))
230
1
            })?;
231
232
1
        Ok(result)
233
1
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase25best_block_hash_by_number
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase25best_block_hash_by_number
Line
Count
Source
207
1
    pub fn best_block_hash_by_number(
208
1
        &self,
209
1
        block_number: u64,
210
1
    ) -> Result<Option<[u8; 32]>, CorruptedError> {
211
1
        let connection = self.database.lock();
212
213
1
        let block_number = match i64::try_from(block_number) {
214
1
            Ok(n) => n,
215
0
            Err(_) => return Ok(None),
216
        };
217
218
1
        let result = connection
219
1
            .prepare_cached(r#"SELECT hash FROM blocks WHERE number = ? AND is_best_chain = TRUE"#)
220
1
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
221
1
            .query_row((block_number,), |row| row.get::<_, Vec<u8>>(0))
222
1
            .optional()
223
1
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
224
1
            .and_then(|value| {
225
                let Some(value) = value else { return Ok(None) };
226
                Ok(Some(
227
                    <[u8; 32]>::try_from(&value[..])
228
                        .map_err(|_| CorruptedError::InvalidBlockHashLen)?,
229
                ))
230
1
            })
?0
;
231
232
1
        Ok(result)
233
1
    }
234
235
    /// Returns a [`chain_information::ChainInformation`] struct containing the information about
236
    /// the current finalized state of the chain.
237
    ///
238
    /// This method is relatively expensive and should preferably not be called repeatedly.
239
    ///
240
    /// In order to avoid race conditions, the known finalized block hash must be passed as
241
    /// parameter. If the finalized block in the database doesn't match the hash passed as
242
    /// parameter, most likely because it has been updated in a parallel thread, a
243
    /// [`StorageAccessError::IncompleteStorage`] error is returned.
244
    // TODO: an IncompleteStorage error doesn't seem appropriate; also, why is it even a problem given that the chain information contains the finalized block anyway
245
21
    pub fn to_chain_information(
246
21
        &self,
247
21
        finalized_block_hash: &[u8; 32],
248
21
    ) -> Result<chain_information::ValidChainInformation, StorageAccessError> {
249
21
        if finalized_hash(&self.database.lock())
?0
!= *finalized_block_hash {
250
0
            return Err(StorageAccessError::IncompleteStorage);
251
21
        }
252
253
21
        let mut builder = chain_information::build::ChainInformationBuild::new(
254
            chain_information::build::Config {
255
                finalized_block_header: chain_information::build::ConfigFinalizedBlockHeader::Any {
256
21
                    scale_encoded_header: self
257
21
                        .block_scale_encoded_header(finalized_block_hash)
?0
258
21
                        .ok_or(StorageAccessError::UnknownBlock)
?0
, // TODO: inappropriate error
259
21
                    known_finality: None,
260
                },
261
                runtime: {
262
21
                    let code = match self.block_storage_get(
263
21
                        finalized_block_hash,
264
21
                        iter::empty::<iter::Empty<_>>(),
265
21
                        trie::bytes_to_nibbles(b":code".iter().copied()).map(u8::from),
266
21
                    )
?0
{
267
21
                        Some((code, _)) => code,
268
0
                        None => todo!(),
269
                    };
270
21
                    let heap_pages = match self.block_storage_get(
271
21
                        &finalized_block_hash,
272
21
                        iter::empty::<iter::Empty<_>>(),
273
21
                        trie::bytes_to_nibbles(b":heappages".iter().copied()).map(u8::from),
274
21
                    )
?0
{
275
0
                        Some((hp, _)) => Some(hp),
276
21
                        None => None,
277
                    };
278
21
                    let Ok(heap_pages) =
279
21
                        executor::storage_heap_pages_to_value(heap_pages.as_deref())
280
                    else {
281
0
                        todo!()
282
                    };
283
21
                    let Ok(runtime) = host::HostVmPrototype::new(host::Config {
284
21
                        module: code,
285
21
                        heap_pages,
286
21
                        exec_hint:
287
21
                            executor::vm::ExecHint::ExecuteOnceWithNonDeterministicValidation,
288
21
                        allow_unresolved_imports: true,
289
21
                    }) else {
290
0
                        todo!()
291
                    };
292
21
                    runtime
293
21
                },
294
21
                block_number_bytes: self.block_number_bytes,
295
            },
296
        );
297
298
        // TODO: this whole code is racy because the database isn't locked
299
        loop {
300
63
            match builder {
301
                chain_information::build::ChainInformationBuild::Finished {
302
21
                    result: Ok(chain_information),
303
21
                    .. // TODO: runtime thrown away
304
21
                } => return Ok(chain_information),
305
                chain_information::build::ChainInformationBuild::Finished {
306
                    result: Err(_),
307
                    .. // TODO: runtime thrown away
308
0
                } => todo!(),
309
                chain_information::build::ChainInformationBuild::InProgress(
310
42
                    chain_information::build::InProgress::StorageGet(val),
311
                ) => {
312
                    // TODO: child trie support
313
42
                    let value = self.block_storage_get(finalized_block_hash, iter::empty::<iter::Empty<_>>(), trie::bytes_to_nibbles(val.key().as_ref().iter().copied()).map(u8::from))
?0
;
314
42
                    let value = match value {
315
42
                        Some((val, vers)) => {
316
42
                            Some((iter::once(val), chain_information::build::TrieEntryVersion::try_from(vers).map_err(|_| 
StorageAccessError::Corrupted(CorruptedError::InvalidTrieEntryVersion)0
)
?0
))
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase20to_chain_information0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase20to_chain_information0B8_
317
                        }
318
0
                        None => None
319
                    };
320
42
                    builder = val.inject_value(value);
321
                }
322
                chain_information::build::ChainInformationBuild::InProgress(
323
0
                    chain_information::build::InProgress::NextKey(val),
324
0
                ) => {
325
0
                    // TODO: child trie support
326
0
                    let nk = self.block_storage_next_key(finalized_block_hash, iter::empty::<iter::Empty<_>>(), val.key().map(u8::from),val.prefix().map(u8::from), val.branch_nodes())?;
327
0
                    builder = val.inject_key(nk.map(|nibbles| nibbles.into_iter().map(|n| trie::Nibble::try_from(n).unwrap())));
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase20to_chain_informations_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase20to_chain_informations_0B8_
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase20to_chain_informations_00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase20to_chain_informations_00Ba_
328
                }
329
                chain_information::build::ChainInformationBuild::InProgress(
330
0
                    chain_information::build::InProgress::ClosestDescendantMerkleValue(val),
331
0
                ) => {
332
0
                    // TODO: child trie support
333
0
                    let mv = self.block_storage_closest_descendant_merkle_value(finalized_block_hash, iter::empty::<iter::Empty<_>>(), val.key().map(u8::from))?;
334
0
                    builder = val.inject_merkle_value(mv.as_deref());
335
                }
336
            }
337
        }
338
21
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20to_chain_information
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase20to_chain_information
Line
Count
Source
245
21
    pub fn to_chain_information(
246
21
        &self,
247
21
        finalized_block_hash: &[u8; 32],
248
21
    ) -> Result<chain_information::ValidChainInformation, StorageAccessError> {
249
21
        if finalized_hash(&self.database.lock())
?0
!= *finalized_block_hash {
250
0
            return Err(StorageAccessError::IncompleteStorage);
251
21
        }
252
253
21
        let mut builder = chain_information::build::ChainInformationBuild::new(
254
            chain_information::build::Config {
255
                finalized_block_header: chain_information::build::ConfigFinalizedBlockHeader::Any {
256
21
                    scale_encoded_header: self
257
21
                        .block_scale_encoded_header(finalized_block_hash)
?0
258
21
                        .ok_or(StorageAccessError::UnknownBlock)
?0
, // TODO: inappropriate error
259
21
                    known_finality: None,
260
                },
261
                runtime: {
262
21
                    let code = match self.block_storage_get(
263
21
                        finalized_block_hash,
264
21
                        iter::empty::<iter::Empty<_>>(),
265
21
                        trie::bytes_to_nibbles(b":code".iter().copied()).map(u8::from),
266
21
                    )
?0
{
267
21
                        Some((code, _)) => code,
268
0
                        None => todo!(),
269
                    };
270
21
                    let heap_pages = match self.block_storage_get(
271
21
                        &finalized_block_hash,
272
21
                        iter::empty::<iter::Empty<_>>(),
273
21
                        trie::bytes_to_nibbles(b":heappages".iter().copied()).map(u8::from),
274
21
                    )
?0
{
275
0
                        Some((hp, _)) => Some(hp),
276
21
                        None => None,
277
                    };
278
21
                    let Ok(heap_pages) =
279
21
                        executor::storage_heap_pages_to_value(heap_pages.as_deref())
280
                    else {
281
0
                        todo!()
282
                    };
283
21
                    let Ok(runtime) = host::HostVmPrototype::new(host::Config {
284
21
                        module: code,
285
21
                        heap_pages,
286
21
                        exec_hint:
287
21
                            executor::vm::ExecHint::ExecuteOnceWithNonDeterministicValidation,
288
21
                        allow_unresolved_imports: true,
289
21
                    }) else {
290
0
                        todo!()
291
                    };
292
21
                    runtime
293
21
                },
294
21
                block_number_bytes: self.block_number_bytes,
295
            },
296
        );
297
298
        // TODO: this whole code is racy because the database isn't locked
299
        loop {
300
63
            match builder {
301
                chain_information::build::ChainInformationBuild::Finished {
302
21
                    result: Ok(chain_information),
303
21
                    .. // TODO: runtime thrown away
304
21
                } => return Ok(chain_information),
305
                chain_information::build::ChainInformationBuild::Finished {
306
                    result: Err(_),
307
                    .. // TODO: runtime thrown away
308
0
                } => todo!(),
309
                chain_information::build::ChainInformationBuild::InProgress(
310
42
                    chain_information::build::InProgress::StorageGet(val),
311
                ) => {
312
                    // TODO: child trie support
313
42
                    let value = self.block_storage_get(finalized_block_hash, iter::empty::<iter::Empty<_>>(), trie::bytes_to_nibbles(val.key().as_ref().iter().copied()).map(u8::from))
?0
;
314
42
                    let value = match value {
315
42
                        Some((val, vers)) => {
316
42
                            Some((iter::once(val), chain_information::build::TrieEntryVersion::try_from(vers).map_err(|_| StorageAccessError::Corrupted(CorruptedError::InvalidTrieEntryVersion))
?0
))
317
                        }
318
0
                        None => None
319
                    };
320
42
                    builder = val.inject_value(value);
321
                }
322
                chain_information::build::ChainInformationBuild::InProgress(
323
0
                    chain_information::build::InProgress::NextKey(val),
324
0
                ) => {
325
0
                    // TODO: child trie support
326
0
                    let nk = self.block_storage_next_key(finalized_block_hash, iter::empty::<iter::Empty<_>>(), val.key().map(u8::from),val.prefix().map(u8::from), val.branch_nodes())?;
327
0
                    builder = val.inject_key(nk.map(|nibbles| nibbles.into_iter().map(|n| trie::Nibble::try_from(n).unwrap())));
328
                }
329
                chain_information::build::ChainInformationBuild::InProgress(
330
0
                    chain_information::build::InProgress::ClosestDescendantMerkleValue(val),
331
0
                ) => {
332
0
                    // TODO: child trie support
333
0
                    let mv = self.block_storage_closest_descendant_merkle_value(finalized_block_hash, iter::empty::<iter::Empty<_>>(), val.key().map(u8::from))?;
334
0
                    builder = val.inject_merkle_value(mv.as_deref());
335
                }
336
            }
337
        }
338
21
    }
339
340
    /// Insert a new block in the database.
341
    ///
342
    /// Must pass the header and body of the block.
343
    ///
344
    /// Blocks must be inserted in the correct order. An error is returned if the parent of the
345
    /// newly-inserted block isn't present in the database.
346
    ///
347
    /// > **Note**: It is not necessary for the newly-inserted block to be a descendant of the
348
    /// >           finalized block, unless `is_new_best` is true.
349
    ///
350
0
    pub fn insert<'a>(
351
0
        &self,
352
0
        scale_encoded_header: &[u8],
353
0
        is_new_best: bool,
354
0
        body: impl ExactSizeIterator<Item = impl AsRef<[u8]>>,
355
0
    ) -> Result<(), InsertError> {
356
0
        // Calculate the hash of the new best block.
357
0
        let block_hash = header::hash_from_scale_encoded_header(scale_encoded_header);
358
359
        // Decode the header, as we will need various information from it.
360
        // TODO: this module shouldn't decode headers
361
0
        let header = header::decode(scale_encoded_header, self.block_number_bytes)
362
0
            .map_err(InsertError::BadHeader)?;
363
364
        // Locking is performed as late as possible.
365
0
        let mut database = self.database.lock();
366
367
        // Start a transaction to insert everything at once.
368
0
        let transaction = database
369
0
            .transaction()
370
0
            .map_err(|err| InsertError::Corrupted(CorruptedError::Internal(InternalError(err))))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EE0CsibGXYHQB8Ea_25json_rpc_general_requests
371
372
        // Make sure that the block to insert isn't already in the database.
373
0
        if has_block(&transaction, &block_hash)? {
374
0
            return Err(InsertError::Duplicate);
375
0
        }
376
0
377
0
        // Make sure that the parent of the block to insert is in the database.
378
0
        if !has_block(&transaction, header.parent_hash)? {
379
0
            return Err(InsertError::MissingParent);
380
0
        }
381
0
382
0
        transaction
383
0
            .prepare_cached(
384
0
                "INSERT INTO blocks(number, hash, parent_hash, state_trie_root_hash, header, is_best_chain, justification) VALUES (?, ?, ?, ?, ?, FALSE, NULL)",
385
0
            )
386
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
387
0
            .execute((
388
0
                i64::try_from(header.number).unwrap(),
389
0
                &block_hash[..],
390
0
                &header.parent_hash[..],
391
0
                &header.state_root[..],
392
0
                scale_encoded_header
393
0
            ))
394
0
            .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
395
396
        {
397
0
            let mut statement = transaction
398
0
                .prepare_cached("INSERT INTO blocks_body(hash, idx, extrinsic) VALUES (?, ?, ?)")
399
0
                .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
400
0
            for (index, item) in body.enumerate() {
401
0
                statement
402
0
                    .execute((
403
0
                        &block_hash[..],
404
0
                        i64::try_from(index).unwrap(),
405
0
                        item.as_ref(),
406
0
                    ))
407
0
                    .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
408
            }
409
        }
410
411
        // Change the best chain to be the new block.
412
0
        if is_new_best {
413
            // It would be illegal to change the best chain to not overlay with the
414
            // finalized chain.
415
0
            if header.number <= finalized_num(&transaction)? {
416
0
                return Err(InsertError::BestNotInFinalizedChain);
417
0
            }
418
0
419
0
            set_best_chain(&transaction, &block_hash)?;
420
0
        }
421
422
        // If everything is successful, we commit.
423
0
        transaction
424
0
            .commit()
425
0
            .map_err(|err| InsertError::Corrupted(CorruptedError::Internal(InternalError(err))))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertppEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1q_9into_iter8IntoIterB1n_EEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
426
427
0
        Ok(())
428
0
    }
Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase6insertppEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase6insertppEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1o_9into_iter8IntoIterB1l_EECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1o_9into_iter8IntoIterB1l_EECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase6insertINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtB1o_9into_iter8IntoIterB1l_EECsibGXYHQB8Ea_25json_rpc_general_requests
429
430
    // TODO: needs documentation
431
    // TODO: should we refuse inserting disjoint storage nodes?
432
1.05k
    pub fn insert_trie_nodes<'a>(
433
1.05k
        &self,
434
1.05k
        new_trie_nodes: impl Iterator<Item = InsertTrieNode<'a>>,
435
1.05k
        trie_entries_version: u8,
436
1.05k
    ) -> Result<(), CorruptedError> {
437
1.05k
        let mut database = self.database.lock();
438
439
1.05k
        let transaction = database
440
1.05k
            .transaction()
441
1.05k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EE0CsibGXYHQB8Ea_25json_rpc_general_requests
442
443
        {
444
            // TODO: should check whether the existing merkle values that are referenced from inserted nodes exist in the parent's storage
445
            // TODO: is it correct to have OR IGNORE everywhere?
446
1.05k
            let mut insert_node_statement = transaction
447
1.05k
                .prepare_cached("INSERT OR IGNORE INTO trie_node(hash, partial_key) VALUES(?, ?)")
448
1.05k
                .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
449
1.05k
            let mut insert_node_storage_statement = transaction
450
1.05k
                .prepare_cached("INSERT OR IGNORE INTO trie_node_storage(node_hash, value, trie_root_ref, trie_entry_version) VALUES(?, ?, ?, ?)")
451
1.05k
                .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
452
1.05k
            let mut insert_child_statement = transaction
453
1.05k
                .prepare_cached(
454
1.05k
                    "INSERT OR IGNORE INTO trie_node_child(hash, child_num, child_hash) VALUES(?, ?, ?)",
455
1.05k
                )
456
1.05k
                .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
457
            // TODO: if the iterator's `next()` function accesses the database, we deadlock
458
4.65k
            for 
trie_node3.59k
in new_trie_nodes {
459
50.2k
                
assert!(trie_node.partial_key_nibbles.iter().all(3.59k
|n| *n < 16
))3.59k
; // TODO: document
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs6_0B9_
Line
Count
Source
459
13
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs6_0B9_
Line
Count
Source
459
4.26k
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs6_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs6_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs6_0CsiLzmwikkc22_14json_rpc_basic
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs6_0CsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
459
4.38k
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs6_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs6_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs6_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs6_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs6_0CsibGXYHQB8Ea_25json_rpc_general_requests
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs6_0CsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
459
41.6k
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
460
3.59k
                insert_node_statement
461
3.59k
                    .execute((&trie_node.merkle_value, trie_node.partial_key_nibbles))
462
3.59k
                    .map_err(|err: rusqlite::Error| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
463
3.59k
                match trie_node.storage_value {
464
                    InsertTrieNodeStorageValue::Value {
465
3.25k
                        value,
466
3.25k
                        references_merkle_value,
467
3.25k
                    } => {
468
3.25k
                        insert_node_storage_statement
469
3.25k
                            .execute((
470
3.25k
                                &trie_node.merkle_value,
471
3.25k
                                if !references_merkle_value {
472
3.25k
                                    Some(&value)
473
                                } else {
474
0
                                    None
475
                                },
476
3.25k
                                if references_merkle_value {
477
0
                                    Some(&value)
478
                                } else {
479
3.25k
                                    None
480
                                },
481
3.25k
                                trie_entries_version,
482
3.25k
                            ))
483
3.25k
                            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
484
                    }
485
342
                    InsertTrieNodeStorageValue::NoValue => {}
486
                }
487
57.5k
                for (child_num, child) in 
trie_node.children_merkle_values.iter().enumerate()3.59k
{
488
57.5k
                    if let Some(
child2.55k
) = child {
489
2.55k
                        let child_num =
490
2.55k
                            vec![u8::try_from(child_num).unwrap_or_else(|_| 
unreachable!()0
)];
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs7_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs7_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs7_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs7_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs7_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs7_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs7_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs7_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs7_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs7_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs7_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs7_0CsibGXYHQB8Ea_25json_rpc_general_requests
491
2.55k
                        insert_child_statement
492
2.55k
                            .execute((&trie_node.merkle_value, child_num, child))
493
2.55k
                            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs4_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs4_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs4_0CsibGXYHQB8Ea_25json_rpc_general_requests
494
55.0k
                    }
495
                }
496
            }
497
        }
498
499
1.05k
        transaction
500
1.05k
            .commit()
501
1.05k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB5_14InsertTrieNodeKj1_EEs5_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNvNtB5_5testss_30empty_database_fill_then_querys0_0EEs5_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodespEs5_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB5_14InsertTrieNodeEEs5_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB5_14InsertTrieNodeEEs5_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB9_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EEs5_0CsibGXYHQB8Ea_25json_rpc_general_requests
502
503
1.05k
        Ok(())
504
1.05k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterNtB3_14InsertTrieNodeKj1_EEB7_
Line
Count
Source
432
7
    pub fn insert_trie_nodes<'a>(
433
7
        &self,
434
7
        new_trie_nodes: impl Iterator<Item = InsertTrieNode<'a>>,
435
7
        trie_entries_version: u8,
436
7
    ) -> Result<(), CorruptedError> {
437
7
        let mut database = self.database.lock();
438
439
7
        let transaction = database
440
7
            .transaction()
441
7
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
442
443
        {
444
            // TODO: should check whether the existing merkle values that are referenced from inserted nodes exist in the parent's storage
445
            // TODO: is it correct to have OR IGNORE everywhere?
446
7
            let mut insert_node_statement = transaction
447
7
                .prepare_cached("INSERT OR IGNORE INTO trie_node(hash, partial_key) VALUES(?, ?)")
448
7
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
449
7
            let mut insert_node_storage_statement = transaction
450
7
                .prepare_cached("INSERT OR IGNORE INTO trie_node_storage(node_hash, value, trie_root_ref, trie_entry_version) VALUES(?, ?, ?, ?)")
451
7
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
452
7
            let mut insert_child_statement = transaction
453
7
                .prepare_cached(
454
7
                    "INSERT OR IGNORE INTO trie_node_child(hash, child_num, child_hash) VALUES(?, ?, ?)",
455
7
                )
456
7
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
457
            // TODO: if the iterator's `next()` function accesses the database, we deadlock
458
14
            for 
trie_node7
in new_trie_nodes {
459
7
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
460
7
                insert_node_statement
461
7
                    .execute((&trie_node.merkle_value, trie_node.partial_key_nibbles))
462
7
                    .map_err(|err: rusqlite::Error| CorruptedError::Internal(InternalError(err)))
?0
;
463
7
                match trie_node.storage_value {
464
                    InsertTrieNodeStorageValue::Value {
465
6
                        value,
466
6
                        references_merkle_value,
467
6
                    } => {
468
6
                        insert_node_storage_statement
469
6
                            .execute((
470
6
                                &trie_node.merkle_value,
471
6
                                if !references_merkle_value {
472
6
                                    Some(&value)
473
                                } else {
474
0
                                    None
475
                                },
476
6
                                if references_merkle_value {
477
0
                                    Some(&value)
478
                                } else {
479
6
                                    None
480
                                },
481
6
                                trie_entries_version,
482
6
                            ))
483
6
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
484
                    }
485
1
                    InsertTrieNodeStorageValue::NoValue => {}
486
                }
487
112
                for (child_num, child) in 
trie_node.children_merkle_values.iter().enumerate()7
{
488
112
                    if let Some(
child4
) = child {
489
4
                        let child_num =
490
4
                            vec![u8::try_from(child_num).unwrap_or_else(|_| unreachable!())];
491
4
                        insert_child_statement
492
4
                            .execute((&trie_node.merkle_value, child_num, child))
493
4
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
494
108
                    }
495
                }
496
            }
497
        }
498
499
7
        transaction
500
7
            .commit()
501
7
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
502
503
7
        Ok(())
504
7
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB7_4trie14trie_structure9NodeIndexENCNvNtB3_5testss_30empty_database_fill_then_querys0_0EEB7_
Line
Count
Source
432
1.02k
    pub fn insert_trie_nodes<'a>(
433
1.02k
        &self,
434
1.02k
        new_trie_nodes: impl Iterator<Item = InsertTrieNode<'a>>,
435
1.02k
        trie_entries_version: u8,
436
1.02k
    ) -> Result<(), CorruptedError> {
437
1.02k
        let mut database = self.database.lock();
438
439
1.02k
        let transaction = database
440
1.02k
            .transaction()
441
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
442
443
        {
444
            // TODO: should check whether the existing merkle values that are referenced from inserted nodes exist in the parent's storage
445
            // TODO: is it correct to have OR IGNORE everywhere?
446
1.02k
            let mut insert_node_statement = transaction
447
1.02k
                .prepare_cached("INSERT OR IGNORE INTO trie_node(hash, partial_key) VALUES(?, ?)")
448
1.02k
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
449
1.02k
            let mut insert_node_storage_statement = transaction
450
1.02k
                .prepare_cached("INSERT OR IGNORE INTO trie_node_storage(node_hash, value, trie_root_ref, trie_entry_version) VALUES(?, ?, ?, ?)")
451
1.02k
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
452
1.02k
            let mut insert_child_statement = transaction
453
1.02k
                .prepare_cached(
454
1.02k
                    "INSERT OR IGNORE INTO trie_node_child(hash, child_num, child_hash) VALUES(?, ?, ?)",
455
1.02k
                )
456
1.02k
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
457
            // TODO: if the iterator's `next()` function accesses the database, we deadlock
458
3.60k
            for 
trie_node2.58k
in new_trie_nodes {
459
2.58k
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
460
2.58k
                insert_node_statement
461
2.58k
                    .execute((&trie_node.merkle_value, trie_node.partial_key_nibbles))
462
2.58k
                    .map_err(|err: rusqlite::Error| CorruptedError::Internal(InternalError(err)))
?0
;
463
2.58k
                match trie_node.storage_value {
464
                    InsertTrieNodeStorageValue::Value {
465
2.51k
                        value,
466
2.51k
                        references_merkle_value,
467
2.51k
                    } => {
468
2.51k
                        insert_node_storage_statement
469
2.51k
                            .execute((
470
2.51k
                                &trie_node.merkle_value,
471
2.51k
                                if !references_merkle_value {
472
2.51k
                                    Some(&value)
473
                                } else {
474
0
                                    None
475
                                },
476
2.51k
                                if references_merkle_value {
477
0
                                    Some(&value)
478
                                } else {
479
2.51k
                                    None
480
                                },
481
2.51k
                                trie_entries_version,
482
2.51k
                            ))
483
2.51k
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
484
                    }
485
68
                    InsertTrieNodeStorageValue::NoValue => {}
486
                }
487
41.3k
                for (child_num, child) in 
trie_node.children_merkle_values.iter().enumerate()2.58k
{
488
41.3k
                    if let Some(
child1.56k
) = child {
489
1.56k
                        let child_num =
490
1.56k
                            vec![u8::try_from(child_num).unwrap_or_else(|_| unreachable!())];
491
1.56k
                        insert_child_statement
492
1.56k
                            .execute((&trie_node.merkle_value, child_num, child))
493
1.56k
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
494
39.7k
                    }
495
                }
496
            }
497
        }
498
499
1.02k
        transaction
500
1.02k
            .commit()
501
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
502
503
1.02k
        Ok(())
504
1.02k
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodespEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB3_14InsertTrieNodeEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB3_14InsertTrieNodeEECsiLzmwikkc22_14json_rpc_basic
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB7_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EECsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
432
2
    pub fn insert_trie_nodes<'a>(
433
2
        &self,
434
2
        new_trie_nodes: impl Iterator<Item = InsertTrieNode<'a>>,
435
2
        trie_entries_version: u8,
436
2
    ) -> Result<(), CorruptedError> {
437
2
        let mut database = self.database.lock();
438
439
2
        let transaction = database
440
2
            .transaction()
441
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
442
443
        {
444
            // TODO: should check whether the existing merkle values that are referenced from inserted nodes exist in the parent's storage
445
            // TODO: is it correct to have OR IGNORE everywhere?
446
2
            let mut insert_node_statement = transaction
447
2
                .prepare_cached("INSERT OR IGNORE INTO trie_node(hash, partial_key) VALUES(?, ?)")
448
2
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
449
2
            let mut insert_node_storage_statement = transaction
450
2
                .prepare_cached("INSERT OR IGNORE INTO trie_node_storage(node_hash, value, trie_root_ref, trie_entry_version) VALUES(?, ?, ?, ?)")
451
2
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
452
2
            let mut insert_child_statement = transaction
453
2
                .prepare_cached(
454
2
                    "INSERT OR IGNORE INTO trie_node_child(hash, child_num, child_hash) VALUES(?, ?, ?)",
455
2
                )
456
2
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
457
            // TODO: if the iterator's `next()` function accesses the database, we deadlock
458
98
            for 
trie_node96
in new_trie_nodes {
459
96
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
460
96
                insert_node_statement
461
96
                    .execute((&trie_node.merkle_value, trie_node.partial_key_nibbles))
462
96
                    .map_err(|err: rusqlite::Error| CorruptedError::Internal(InternalError(err)))
?0
;
463
96
                match trie_node.storage_value {
464
                    InsertTrieNodeStorageValue::Value {
465
70
                        value,
466
70
                        references_merkle_value,
467
70
                    } => {
468
70
                        insert_node_storage_statement
469
70
                            .execute((
470
70
                                &trie_node.merkle_value,
471
70
                                if !references_merkle_value {
472
70
                                    Some(&value)
473
                                } else {
474
0
                                    None
475
                                },
476
70
                                if references_merkle_value {
477
0
                                    Some(&value)
478
                                } else {
479
70
                                    None
480
                                },
481
70
                                trie_entries_version,
482
70
                            ))
483
70
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
484
                    }
485
26
                    InsertTrieNodeStorageValue::NoValue => {}
486
                }
487
1.53k
                for (child_num, child) in 
trie_node.children_merkle_values.iter().enumerate()96
{
488
1.53k
                    if let Some(
child94
) = child {
489
94
                        let child_num =
490
94
                            vec![u8::try_from(child_num).unwrap_or_else(|_| unreachable!())];
491
94
                        insert_child_statement
492
94
                            .execute((&trie_node.merkle_value, child_num, child))
493
94
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
494
1.44k
                    }
495
                }
496
            }
497
        }
498
499
2
        transaction
500
2
            .commit()
501
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
502
503
2
        Ok(())
504
2
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB3_14InsertTrieNodeEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB3_14InsertTrieNodeEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB7_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtB3_14InsertTrieNodeEECsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceNtB3_14InsertTrieNodeEECsibGXYHQB8Ea_25json_rpc_general_requests
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17insert_trie_nodesINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterNtNtNtB7_4trie14trie_structure9NodeIndexENCNCNvCsiUjFBJteJ7x_17smoldot_full_node13open_database0s_0EECsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
432
19
    pub fn insert_trie_nodes<'a>(
433
19
        &self,
434
19
        new_trie_nodes: impl Iterator<Item = InsertTrieNode<'a>>,
435
19
        trie_entries_version: u8,
436
19
    ) -> Result<(), CorruptedError> {
437
19
        let mut database = self.database.lock();
438
439
19
        let transaction = database
440
19
            .transaction()
441
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
442
443
        {
444
            // TODO: should check whether the existing merkle values that are referenced from inserted nodes exist in the parent's storage
445
            // TODO: is it correct to have OR IGNORE everywhere?
446
19
            let mut insert_node_statement = transaction
447
19
                .prepare_cached("INSERT OR IGNORE INTO trie_node(hash, partial_key) VALUES(?, ?)")
448
19
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
449
19
            let mut insert_node_storage_statement = transaction
450
19
                .prepare_cached("INSERT OR IGNORE INTO trie_node_storage(node_hash, value, trie_root_ref, trie_entry_version) VALUES(?, ?, ?, ?)")
451
19
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
452
19
            let mut insert_child_statement = transaction
453
19
                .prepare_cached(
454
19
                    "INSERT OR IGNORE INTO trie_node_child(hash, child_num, child_hash) VALUES(?, ?, ?)",
455
19
                )
456
19
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
457
            // TODO: if the iterator's `next()` function accesses the database, we deadlock
458
931
            for 
trie_node912
in new_trie_nodes {
459
912
                assert!(trie_node.partial_key_nibbles.iter().all(|n| *n < 16)); // TODO: document
460
912
                insert_node_statement
461
912
                    .execute((&trie_node.merkle_value, trie_node.partial_key_nibbles))
462
912
                    .map_err(|err: rusqlite::Error| CorruptedError::Internal(InternalError(err)))
?0
;
463
912
                match trie_node.storage_value {
464
                    InsertTrieNodeStorageValue::Value {
465
665
                        value,
466
665
                        references_merkle_value,
467
665
                    } => {
468
665
                        insert_node_storage_statement
469
665
                            .execute((
470
665
                                &trie_node.merkle_value,
471
665
                                if !references_merkle_value {
472
665
                                    Some(&value)
473
                                } else {
474
0
                                    None
475
                                },
476
665
                                if references_merkle_value {
477
0
                                    Some(&value)
478
                                } else {
479
665
                                    None
480
                                },
481
665
                                trie_entries_version,
482
665
                            ))
483
665
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
484
                    }
485
247
                    InsertTrieNodeStorageValue::NoValue => {}
486
                }
487
14.5k
                for (child_num, child) in 
trie_node.children_merkle_values.iter().enumerate()912
{
488
14.5k
                    if let Some(
child893
) = child {
489
893
                        let child_num =
490
893
                            vec![u8::try_from(child_num).unwrap_or_else(|_| unreachable!())];
491
893
                        insert_child_statement
492
893
                            .execute((&trie_node.merkle_value, child_num, child))
493
893
                            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
494
13.6k
                    }
495
                }
496
            }
497
        }
498
499
19
        transaction
500
19
            .commit()
501
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
502
503
19
        Ok(())
504
19
    }
505
506
    /// Returns a list of trie nodes that are missing from the database and that belong to the
507
    /// state of a block whose number is superior or equal to the finalized block.
508
    ///
509
    /// The ordering of the returned trie nodes is unspecified.
510
    ///
511
    /// > **Note**: This function call is relatively expensive, and the API user is expected to
512
    /// >           cache the return value.
513
42
    pub fn finalized_and_above_missing_trie_nodes_unordered(
514
42
        &self,
515
42
    ) -> Result<Vec<MissingTrieNode>, CorruptedError> {
516
42
        let database = self.database.lock();
517
518
42
        let mut statement = database
519
42
            .prepare_cached(
520
42
                r#"
521
42
            WITH RECURSIVE
522
42
                -- List of all block hashes that are equal to the finalized block or above.
523
42
                finalized_and_above_blocks(block_hash) AS (
524
42
                    SELECT blocks.hash
525
42
                    FROM blocks
526
42
                    JOIN meta ON meta.key = "finalized"
527
42
                    WHERE blocks.number >= meta.value_number
528
42
                ),
529
42
530
42
                -- List of all trie nodes for these blocks.
531
42
                trie_nodes(block_hash, node_hash, node_key, is_present) AS (
532
42
                    SELECT  blocks.hash, blocks.state_trie_root_hash,
533
42
                            CASE WHEN trie_node.partial_key IS NULL THEN X'' ELSE trie_node.partial_key END,
534
42
                            trie_node.hash IS NOT NULL
535
42
                        FROM blocks
536
42
                        JOIN finalized_and_above_blocks
537
42
                            ON blocks.hash = finalized_and_above_blocks.block_hash
538
42
                        LEFT JOIN trie_node
539
42
                            ON trie_node.hash = blocks.state_trie_root_hash
540
42
541
42
                    UNION ALL
542
42
                    SELECT  trie_nodes.block_hash, trie_node_child.child_hash,
543
42
                            CASE WHEN trie_node.hash IS NULL THEN CAST(trie_nodes.node_key || trie_node_child.child_num AS BLOB)
544
42
                            ELSE CAST(trie_nodes.node_key || trie_node_child.child_num || trie_node.partial_key AS BLOB) END,
545
42
                            trie_node.hash IS NOT NULL
546
42
                        FROM trie_nodes
547
42
                        JOIN trie_node_child
548
42
                            ON trie_nodes.node_hash = trie_node_child.hash
549
42
                        LEFT JOIN trie_node
550
42
                            ON trie_node.hash = trie_node_child.child_hash
551
42
                        WHERE trie_nodes.is_present
552
42
553
42
                    UNION ALL
554
42
                    SELECT  trie_nodes.block_hash, trie_node_storage.trie_root_ref,
555
42
                            CASE WHEN trie_node.hash IS NULL THEN CAST(trie_nodes.node_key || X'10' AS BLOB)
556
42
                            ELSE CAST(trie_nodes.node_key || X'10' || trie_node.partial_key AS BLOB) END,
557
42
                            trie_node.hash IS NOT NULL
558
42
                        FROM trie_nodes
559
42
                        JOIN trie_node_storage
560
42
                            ON trie_nodes.node_hash = trie_node_storage.node_hash AND trie_node_storage.trie_root_ref IS NOT NULL
561
42
                        LEFT JOIN trie_node
562
42
                            ON trie_node.hash = trie_node_storage.trie_root_ref
563
42
                        WHERE trie_nodes.is_present
564
42
                )
565
42
566
42
            SELECT group_concat(HEX(trie_nodes.block_hash)), group_concat(CAST(blocks.number as TEXT)), trie_nodes.node_hash, group_concat(HEX(trie_nodes.node_key))
567
42
            FROM trie_nodes
568
42
            JOIN blocks ON blocks.hash = trie_nodes.block_hash
569
42
            WHERE is_present = false
570
42
            GROUP BY trie_nodes.node_hash
571
42
            "#)
572
42
            .map_err(|err| {
573
0
                CorruptedError::Internal(
574
0
                    InternalError(err),
575
0
                )
576
42
            })
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordered0B8_
577
578
42
        let results = statement
579
42
            .query_map((), |row| 
{0
580
0
                let block_hashes = row.get::<_, String>(0)?;
581
0
                let block_numbers = row.get::<_, String>(1)?;
582
0
                let node_hash = row.get::<_, Vec<u8>>(2)?;
583
0
                let node_keys = row.get::<_, String>(3)?;
584
0
                Ok((block_hashes, block_numbers, node_hash, node_keys))
585
42
            
}0
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds_0B8_
586
42
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds0_0B8_
587
42
            .map(|row| 
{0
588
0
                let (block_hashes, block_numbers, trie_node_hash, node_keys) = match row {
589
0
                    Ok(r) => r,
590
0
                    Err(err) => return Err(CorruptedError::Internal(InternalError(err))),
591
                };
592
593
                // The SQL query above uses `group_concat` and `hex` to convert a list of blobs
594
                // into a string containing all these blobs. We now convert them back into lists
595
                // of blobs.
596
                // A panic here indicates a bug in SQLite.
597
0
                let mut block_hashes_iter = block_hashes
598
0
                    .split(',')
599
0
                    .map(|hash| hex::decode(hash).unwrap_or_else(|_| unreachable!()));
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_00Ba_
Unexecuted instantiation: _RNCNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_000Bc_
Unexecuted instantiation: _RNCNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_000Bc_
600
0
                let mut block_numbers_iter = block_numbers.split(',').map(|n| {
601
0
                    <u64 as core::str::FromStr>::from_str(n).unwrap_or_else(|_| unreachable!())
Unexecuted instantiation: _RNCNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s_00Bc_
Unexecuted instantiation: _RNCNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s_00Bc_
602
0
                });
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s_0Ba_
603
0
                let mut node_keys_iter = node_keys
604
0
                    .split(',')
605
0
                    .map(|hash| hex::decode(hash).unwrap_or_else(|_| unreachable!()));
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s0_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s0_0Ba_
Unexecuted instantiation: _RNCNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s0_00Bc_
Unexecuted instantiation: _RNCNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB8_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s0_00Bc_
606
0
607
0
                let mut blocks = Vec::with_capacity(32);
608
                loop {
609
                    match (
610
0
                        block_hashes_iter.next(),
611
0
                        block_numbers_iter.next(),
612
0
                        node_keys_iter.next(),
613
                    ) {
614
0
                        (Some(hash), Some(number), Some(node_key)) => {
615
0
                            let hash = <[u8; 32]>::try_from(hash)
616
0
                                .map_err(|_| CorruptedError::InvalidBlockHashLen)?;
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s1_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s1_0Ba_
617
0
                            let mut trie_node_key_nibbles = Vec::with_capacity(node_key.len());
618
0
                            let mut parent_tries_paths_nibbles = Vec::with_capacity(node_key.len());
619
0
                            for nibble in node_key {
620
0
                                debug_assert!(nibble <= 16);
621
0
                                if nibble == 16 {
622
0
                                    parent_tries_paths_nibbles.push(trie_node_key_nibbles.clone());
623
0
                                    trie_node_key_nibbles.clear();
624
0
                                } else {
625
0
                                    trie_node_key_nibbles.push(nibble);
626
0
                                }
627
                            }
628
629
0
                            blocks.push(MissingTrieNodeBlock {
630
0
                                hash,
631
0
                                number,
632
0
                                parent_tries_paths_nibbles,
633
0
                                trie_node_key_nibbles,
634
0
                            })
635
                        }
636
0
                        (None, None, None) => break,
637
                        _ => {
638
                            // The iterators are supposed to have the same number of elements.
639
0
                            debug_assert!(false);
640
0
                            break;
641
                        }
642
                    }
643
                }
644
645
0
                let trie_node_hash = <[u8; 32]>::try_from(trie_node_hash)
646
0
                    .map_err(|_| CorruptedError::InvalidTrieHashLen)?;
Unexecuted instantiation: _RNCNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s2_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB6_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0s2_0Ba_
647
648
0
                debug_assert!(!blocks.is_empty());
649
650
0
                Ok(MissingTrieNode {
651
0
                    blocks,
652
0
                    trie_node_hash,
653
0
                })
654
42
            
}0
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordereds1_0B8_
655
42
            .collect::<Result<Vec<_>, _>>()
?0
;
656
657
42
        Ok(results)
658
42
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordered
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase48finalized_and_above_missing_trie_nodes_unordered
Line
Count
Source
513
42
    pub fn finalized_and_above_missing_trie_nodes_unordered(
514
42
        &self,
515
42
    ) -> Result<Vec<MissingTrieNode>, CorruptedError> {
516
42
        let database = self.database.lock();
517
518
42
        let mut statement = database
519
42
            .prepare_cached(
520
42
                r#"
521
42
            WITH RECURSIVE
522
42
                -- List of all block hashes that are equal to the finalized block or above.
523
42
                finalized_and_above_blocks(block_hash) AS (
524
42
                    SELECT blocks.hash
525
42
                    FROM blocks
526
42
                    JOIN meta ON meta.key = "finalized"
527
42
                    WHERE blocks.number >= meta.value_number
528
42
                ),
529
42
530
42
                -- List of all trie nodes for these blocks.
531
42
                trie_nodes(block_hash, node_hash, node_key, is_present) AS (
532
42
                    SELECT  blocks.hash, blocks.state_trie_root_hash,
533
42
                            CASE WHEN trie_node.partial_key IS NULL THEN X'' ELSE trie_node.partial_key END,
534
42
                            trie_node.hash IS NOT NULL
535
42
                        FROM blocks
536
42
                        JOIN finalized_and_above_blocks
537
42
                            ON blocks.hash = finalized_and_above_blocks.block_hash
538
42
                        LEFT JOIN trie_node
539
42
                            ON trie_node.hash = blocks.state_trie_root_hash
540
42
541
42
                    UNION ALL
542
42
                    SELECT  trie_nodes.block_hash, trie_node_child.child_hash,
543
42
                            CASE WHEN trie_node.hash IS NULL THEN CAST(trie_nodes.node_key || trie_node_child.child_num AS BLOB)
544
42
                            ELSE CAST(trie_nodes.node_key || trie_node_child.child_num || trie_node.partial_key AS BLOB) END,
545
42
                            trie_node.hash IS NOT NULL
546
42
                        FROM trie_nodes
547
42
                        JOIN trie_node_child
548
42
                            ON trie_nodes.node_hash = trie_node_child.hash
549
42
                        LEFT JOIN trie_node
550
42
                            ON trie_node.hash = trie_node_child.child_hash
551
42
                        WHERE trie_nodes.is_present
552
42
553
42
                    UNION ALL
554
42
                    SELECT  trie_nodes.block_hash, trie_node_storage.trie_root_ref,
555
42
                            CASE WHEN trie_node.hash IS NULL THEN CAST(trie_nodes.node_key || X'10' AS BLOB)
556
42
                            ELSE CAST(trie_nodes.node_key || X'10' || trie_node.partial_key AS BLOB) END,
557
42
                            trie_node.hash IS NOT NULL
558
42
                        FROM trie_nodes
559
42
                        JOIN trie_node_storage
560
42
                            ON trie_nodes.node_hash = trie_node_storage.node_hash AND trie_node_storage.trie_root_ref IS NOT NULL
561
42
                        LEFT JOIN trie_node
562
42
                            ON trie_node.hash = trie_node_storage.trie_root_ref
563
42
                        WHERE trie_nodes.is_present
564
42
                )
565
42
566
42
            SELECT group_concat(HEX(trie_nodes.block_hash)), group_concat(CAST(blocks.number as TEXT)), trie_nodes.node_hash, group_concat(HEX(trie_nodes.node_key))
567
42
            FROM trie_nodes
568
42
            JOIN blocks ON blocks.hash = trie_nodes.block_hash
569
42
            WHERE is_present = false
570
42
            GROUP BY trie_nodes.node_hash
571
42
            "#)
572
42
            .map_err(|err| {
573
                CorruptedError::Internal(
574
                    InternalError(err),
575
                )
576
42
            })
?0
;
577
578
42
        let results = statement
579
42
            .query_map((), |row| {
580
                let block_hashes = row.get::<_, String>(0)?;
581
                let block_numbers = row.get::<_, String>(1)?;
582
                let node_hash = row.get::<_, Vec<u8>>(2)?;
583
                let node_keys = row.get::<_, String>(3)?;
584
                Ok((block_hashes, block_numbers, node_hash, node_keys))
585
42
            })
586
42
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
587
42
            .map(|row| {
588
                let (block_hashes, block_numbers, trie_node_hash, node_keys) = match row {
589
                    Ok(r) => r,
590
                    Err(err) => return Err(CorruptedError::Internal(InternalError(err))),
591
                };
592
593
                // The SQL query above uses `group_concat` and `hex` to convert a list of blobs
594
                // into a string containing all these blobs. We now convert them back into lists
595
                // of blobs.
596
                // A panic here indicates a bug in SQLite.
597
                let mut block_hashes_iter = block_hashes
598
                    .split(',')
599
                    .map(|hash| hex::decode(hash).unwrap_or_else(|_| unreachable!()));
600
                let mut block_numbers_iter = block_numbers.split(',').map(|n| {
601
                    <u64 as core::str::FromStr>::from_str(n).unwrap_or_else(|_| unreachable!())
602
                });
603
                let mut node_keys_iter = node_keys
604
                    .split(',')
605
                    .map(|hash| hex::decode(hash).unwrap_or_else(|_| unreachable!()));
606
607
                let mut blocks = Vec::with_capacity(32);
608
                loop {
609
                    match (
610
                        block_hashes_iter.next(),
611
                        block_numbers_iter.next(),
612
                        node_keys_iter.next(),
613
                    ) {
614
                        (Some(hash), Some(number), Some(node_key)) => {
615
                            let hash = <[u8; 32]>::try_from(hash)
616
                                .map_err(|_| CorruptedError::InvalidBlockHashLen)?;
617
                            let mut trie_node_key_nibbles = Vec::with_capacity(node_key.len());
618
                            let mut parent_tries_paths_nibbles = Vec::with_capacity(node_key.len());
619
                            for nibble in node_key {
620
                                debug_assert!(nibble <= 16);
621
                                if nibble == 16 {
622
                                    parent_tries_paths_nibbles.push(trie_node_key_nibbles.clone());
623
                                    trie_node_key_nibbles.clear();
624
                                } else {
625
                                    trie_node_key_nibbles.push(nibble);
626
                                }
627
                            }
628
629
                            blocks.push(MissingTrieNodeBlock {
630
                                hash,
631
                                number,
632
                                parent_tries_paths_nibbles,
633
                                trie_node_key_nibbles,
634
                            })
635
                        }
636
                        (None, None, None) => break,
637
                        _ => {
638
                            // The iterators are supposed to have the same number of elements.
639
                            debug_assert!(false);
640
                            break;
641
                        }
642
                    }
643
                }
644
645
                let trie_node_hash = <[u8; 32]>::try_from(trie_node_hash)
646
                    .map_err(|_| CorruptedError::InvalidTrieHashLen)?;
647
648
                debug_assert!(!blocks.is_empty());
649
650
                Ok(MissingTrieNode {
651
                    blocks,
652
                    trie_node_hash,
653
                })
654
42
            })
655
42
            .collect::<Result<Vec<_>, _>>()
?0
;
656
657
42
        Ok(results)
658
42
    }
659
660
    /// Changes the finalized block to the given one.
661
    ///
662
    /// The block must have been previously inserted using [`SqliteFullDatabase::insert`],
663
    /// otherwise an error is returned.
664
    ///
665
    /// Blocks are expected to be valid in context of the chain. Inserting an invalid block can
666
    /// result in the database being corrupted.
667
    ///
668
    /// The block must be a descendant of the current finalized block. Reverting finalization is
669
    /// forbidden, as the database intentionally discards some information when finality is
670
    /// applied.
671
    ///
672
    /// > **Note**: This function doesn't remove any block from the database but simply moves
673
    /// >           the finalized block "cursor".
674
    ///
675
0
    pub fn set_finalized(
676
0
        &self,
677
0
        new_finalized_block_hash: &[u8; 32],
678
0
    ) -> Result<(), SetFinalizedError> {
679
0
        let mut database = self.database.lock();
680
681
        // Start a transaction to insert everything at once.
682
0
        let transaction = database.transaction().map_err(|err| {
683
0
            SetFinalizedError::Corrupted(CorruptedError::Internal(InternalError(err)))
684
0
        })?;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase13set_finalized0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase13set_finalized0B8_
685
686
        // Fetch the header of the block to finalize.
687
0
        let new_finalized_header = block_header(&transaction, new_finalized_block_hash)?
688
0
            .ok_or(SetFinalizedError::UnknownBlock)?;
689
0
        let new_finalized_header = header::decode(&new_finalized_header, self.block_number_bytes)
690
0
            .map_err(CorruptedError::BlockHeaderCorrupted)
691
0
            .map_err(SetFinalizedError::Corrupted)?;
692
693
        // Fetch the current finalized block.
694
0
        let current_finalized = finalized_num(&transaction)?;
695
696
        // If the block to finalize is at the same height as the already-finalized
697
        // block, considering that the database only contains one block per height on
698
        // the finalized chain, and that the presence of the block to finalize in
699
        // the database has already been verified, it is guaranteed that the block
700
        // to finalize is already the one already finalized.
701
        // TODO: this comment is obsolete ^, should also compare the block hashes
702
0
        if new_finalized_header.number == current_finalized {
703
0
            return Ok(());
704
0
        }
705
0
706
0
        // Cannot set the finalized block to a past block. The database can't support
707
0
        // reverting finalization.
708
0
        if new_finalized_header.number < current_finalized {
709
0
            return Err(SetFinalizedError::RevertForbidden);
710
0
        }
711
0
712
0
        // At this point, we are sure that the operation will succeed unless the database is
713
0
        // corrupted.
714
0
        // Update the finalized block in meta.
715
0
        meta_set_number(&transaction, "finalized", new_finalized_header.number)?;
716
717
        // It is possible that the best block has been pruned.
718
        // TODO: ^ yeah, how do we handle that exactly ^ ?
719
720
        // If everything went well up to this point, commit the transaction.
721
0
        transaction.commit().map_err(|err| {
722
0
            SetFinalizedError::Corrupted(CorruptedError::Internal(InternalError(err)))
723
0
        })?;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase13set_finalizeds_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase13set_finalizeds_0B8_
724
725
0
        Ok(())
726
0
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase13set_finalized
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase13set_finalized
727
728
    /// Removes from the database all blocks that aren't a descendant of the current finalized
729
    /// block.
730
21
    pub fn purge_finality_orphans(&self) -> Result<(), CorruptedError> {
731
21
        let mut database = self.database.lock();
732
733
        // TODO: untested
734
735
21
        let transaction = database
736
21
            .transaction()
737
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphans0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphans0B8_
738
739
        // Temporarily disable foreign key checks in order to make the insertion easier, as we
740
        // don't have to make sure that trie nodes are sorted.
741
        // Note that this is immediately disabled again when we `COMMIT` later down below.
742
        // TODO: is this really necessary?
743
21
        transaction
744
21
            .execute("PRAGMA defer_foreign_keys = ON", ())
745
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss_0B8_
746
747
21
        let current_finalized = finalized_num(&transaction)
?0
;
748
749
21
        let blocks = transaction
750
21
            .prepare_cached(
751
21
                r#"SELECT hash FROM blocks WHERE number <= ? AND is_best_chain = FALSE"#,
752
21
            )
753
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss0_0B8_
754
21
            .query_map((current_finalized,), |row| 
row.get::<_, Vec<u8>>(0)0
)
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss1_0B8_
755
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss2_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss2_0B8_
756
21
            .collect::<Result<Vec<_>, _>>()
757
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss3_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss3_0B8_
758
759
21
        for 
block0
in blocks {
760
0
            purge_block(&transaction, &block)?;
761
        }
762
763
        // If everything went well up to this point, commit the transaction.
764
21
        transaction
765
21
            .commit()
766
21
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss4_0B8_
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabase22purge_finality_orphanss4_0B8_
767
768
21
        Ok(())
769
21
    }
Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase22purge_finality_orphans
_RNvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB2_18SqliteFullDatabase22purge_finality_orphans
Line
Count
Source
730
21
    pub fn purge_finality_orphans(&self) -> Result<(), CorruptedError> {
731
21
        let mut database = self.database.lock();
732
733
        // TODO: untested
734
735
21
        let transaction = database
736
21
            .transaction()
737
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
738
739
        // Temporarily disable foreign key checks in order to make the insertion easier, as we
740
        // don't have to make sure that trie nodes are sorted.
741
        // Note that this is immediately disabled again when we `COMMIT` later down below.
742
        // TODO: is this really necessary?
743
21
        transaction
744
21
            .execute("PRAGMA defer_foreign_keys = ON", ())
745
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
746
747
21
        let current_finalized = finalized_num(&transaction)
?0
;
748
749
21
        let blocks = transaction
750
21
            .prepare_cached(
751
21
                r#"SELECT hash FROM blocks WHERE number <= ? AND is_best_chain = FALSE"#,
752
21
            )
753
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
754
21
            .query_map((current_finalized,), |row| row.get::<_, Vec<u8>>(0))
755
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
756
21
            .collect::<Result<Vec<_>, _>>()
757
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
758
759
21
        for 
block0
in blocks {
760
0
            purge_block(&transaction, &block)?;
761
        }
762
763
        // If everything went well up to this point, commit the transaction.
764
21
        transaction
765
21
            .commit()
766
21
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
767
768
21
        Ok(())
769
21
    }
770
771
    /// Returns the value associated with a node of the trie of the given block.
772
    ///
773
    /// `parent_tries_paths_nibbles` is a list of keys to follow in order to find the root of the
774
    /// trie into which `key_nibbles` should be searched.
775
    ///
776
    /// Beware that both `parent_tries_paths_nibbles` and `key_nibbles` must yield *nibbles*, in
777
    /// other words values strictly inferior to 16.
778
    ///
779
    /// Returns an error if the block or its storage can't be found in the database.
780
    ///
781
    /// # Panic
782
    ///
783
    /// Panics if any of the values yielded by `parent_tries_paths_nibbles` or `key_nibbles` is
784
    /// superior or equal to 16.
785
    ///
786
1.04M
    pub fn block_storage_get(
787
1.04M
        &self,
788
1.04M
        block_hash: &[u8; 32],
789
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
1.04M
        key_nibbles: impl Iterator<Item = u8>,
791
1.04M
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
793
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
1.04M
        // the database as well.
795
1.04M
        let key_vectored = parent_tries_paths_nibbles
796
1.04M
            .flat_map(|t| 
t.inspect(0
|n|
assert!(*n < 160
)0
).chain(iter::once(0x10))0
)
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0B42_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEE0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEE0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1H_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2I_6copied6CopiedINtNtNtB1J_5slice4iter4IterhEEENvYhINtNtB1J_7convert4FromNtB38_6NibbleE4fromEE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1J_5array4iter8IntoIterhKj0_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1J_5array4iter8IntoIterhKj2_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1J_5array4iter8IntoIterhKj3_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1J_5array4iter8IntoIterhKj4_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1B_B1A_EINtNtNtB1J_5array4iter8IntoIterhKj5_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEENvYhINtNtB1K_7convert4FromNtB39_6NibbleE4fromEE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB43_14SyncBackground12author_block0s_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtB1K_5slice4iter4IterNtNtNtBb_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB37_B5u_EE0s3_00s0_0EE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEENvYhINtNtB1K_7convert4FromNtB39_6NibbleE4fromEE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00B44_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEENvYhINtNtB1K_7convert4FromNtB39_6NibbleE4fromEE00CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEE00CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB43_14SyncBackground12author_block0s_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtB1K_5slice4iter4IterNtNtNtBb_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB37_B5u_EE0s3_00s0_0EE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEENvYhINtNtB1K_7convert4FromNtB39_6NibbleE4fromEE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB43_14SyncBackground12author_block0s_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2A_6option8IntoIterINtB1G_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2w_6copied6CopiedINtNtNtB2A_5slice4iter4IterhEEE00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtB1K_5slice4iter4IterNtNtNtBb_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB37_B5u_EE0s3_00s0_0EE00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterhEEENvYhINtNtB1K_7convert4FromNtB39_6NibbleE4fromEE00CsibGXYHQB8Ea_25json_rpc_general_requests
797
4.19M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEEs_0B9_
Line
Count
Source
797
4.19M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EEs_0B9_
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EEs_0B9_
Line
Count
Source
797
6
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EEs_0B9_
Line
Count
Source
797
9
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EEs_0B9_
Line
Count
Source
797
12
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EEs_0B9_
Line
Count
Source
797
15
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs_0B9_
Line
Count
Source
797
2.81k
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs_0CsiLzmwikkc22_14json_rpc_basic
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs_0CsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
797
60
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0B42_
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs_0CsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
797
60
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEEs_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
797
570
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
1.04M
            .collect::<Vec<_>>();
799
1.04M
800
1.04M
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
1.04M
        let mut statement = connection
806
1.04M
            .prepare_cached(
807
1.04M
                r#"
808
1.04M
            WITH RECURSIVE
809
1.04M
                -- At the end of the recursive statement, `node_with_key` must always contain
810
1.04M
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
1.04M
                -- indicates that we have found a match, while null means that the search has
812
1.04M
                -- been interrupted due to a storage entry not being in the database. If
813
1.04M
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
1.04M
                -- or null in case there is no entry with the requested key. If `search_remain`
815
1.04M
                -- is null, then `node_hash` is irrelevant.
816
1.04M
                --
817
1.04M
                -- In order to properly handle the situation where the key is empty, the initial
818
1.04M
                -- request of the recursive table building must check whether the partial key of
819
1.04M
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
1.04M
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
1.04M
                -- and after the partial key has already been verified to be correct.
822
1.04M
                node_with_key(node_hash, search_remain) AS (
823
1.04M
                        SELECT
824
1.04M
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
1.04M
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
1.04M
                        FROM blocks
827
1.04M
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
1.04M
                        WHERE blocks.hash = :block_hash
829
1.04M
                    UNION ALL
830
1.04M
                    SELECT
831
1.04M
                        CASE
832
1.04M
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
1.04M
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
1.04M
                            ELSE NULL END,
835
1.04M
                        CASE
836
1.04M
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
1.04M
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
1.04M
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
1.04M
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
1.04M
                            ELSE X'' END
841
1.04M
                    FROM node_with_key
842
1.04M
                        LEFT JOIN trie_node_child
843
1.04M
                            ON node_with_key.node_hash = trie_node_child.hash
844
1.04M
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
1.04M
                        LEFT JOIN trie_node
846
1.04M
                            ON trie_node.hash = trie_node_child.child_hash
847
1.04M
                        LEFT JOIN trie_node_storage
848
1.04M
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
1.04M
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
1.04M
                )
851
1.04M
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
1.04M
            FROM blocks
853
1.04M
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
1.04M
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
1.04M
            WHERE blocks.hash = :block_hash;
856
1.04M
            "#)
857
1.04M
            .map_err(|err| {
858
0
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
0
                    InternalError(err),
860
0
                ))
861
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0B42_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs0_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEEs0_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
1.04M
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
1.04M
            .query_row(
892
1.04M
                rusqlite::named_params! {
893
1.04M
                    ":block_hash": &block_hash[..],
894
1.04M
                    ":key": key_vectored,
895
1.04M
                },
896
1.04M
                |row| {
897
1.04M
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
1.04M
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
1.04M
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
1.04M
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEEs1_0B9_
Line
Count
Source
896
1.04M
                |row| {
897
1.04M
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
1.04M
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
1.04M
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
1.04M
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EEs1_0B9_
Line
Count
Source
896
3
                |row| {
897
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
3
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
3
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
3
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EEs1_0B9_
Line
Count
Source
896
3
                |row| {
897
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
3
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
3
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
3
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EEs1_0B9_
Line
Count
Source
896
3
                |row| {
897
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
3
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
3
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
3
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EEs1_0B9_
Line
Count
Source
896
3
                |row| {
897
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
3
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
3
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
3
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EEs1_0B9_
Line
Count
Source
896
3
                |row| {
897
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
3
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
3
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
3
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs1_0B9_
Line
Count
Source
896
84
                |row| {
897
84
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
84
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
84
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
84
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
84
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
84
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs1_0CsiLzmwikkc22_14json_rpc_basic
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs1_0CsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
896
4
                |row| {
897
4
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
4
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
4
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
4
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
4
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
4
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0B42_
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs1_0CsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
896
4
                |row| {
897
4
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
4
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
4
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
4
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
4
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
4
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEEs1_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
896
38
                |row| {
897
38
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
898
38
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
899
38
                    let value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
900
38
                    let trie_entry_version = row.get::<_, Option<i64>>(3)
?0
;
901
38
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
38
                },
903
1.04M
            )
904
1.04M
            .map_err(|err| {
905
0
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0B42_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs2_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEEs2_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
907
908
1.04M
        if !has_block {
909
1
            return Err(StorageAccessError::UnknownBlock);
910
1.04M
        }
911
1.04M
912
1.04M
        if incomplete_storage {
913
7
            return Err(StorageAccessError::IncompleteStorage);
914
1.04M
        }
915
916
1.04M
        let Some(
value209k
) = value else { return
Ok(None)838k
};
917
918
209k
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
209k
            .map_err(|_| 
CorruptedError::InvalidTrieEntryVersion0
)
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1F_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2G_6copied6CopiedINtNtNtB1H_5slice4iter4IterhEEENvYhINtNtB1H_7convert4FromNtB36_6NibbleE4fromEEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj0_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj2_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj3_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj4_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1z_B1y_EINtNtNtB1H_5array4iter8IntoIterhKj5_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0B42_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs3_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEEs3_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB41_14SyncBackground12author_block0s_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2y_6option8IntoIterINtB1E_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2u_6copied6CopiedINtNtNtB2y_5slice4iter4IterhEEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB1I_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB35_B5s_EE0s3_00s0_0EEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1A_B1z_EINtNtNtB1G_8adapters3map3MapINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2H_6copied6CopiedINtNtNtB1I_5slice4iter4IterhEEENvYhINtNtB1I_7convert4FromNtB37_6NibbleE4fromEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
920
209k
            .map_err(StorageAccessError::Corrupted)
?0
;
921
209k
        Ok(Some((value, trie_entry_version)))
922
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1D_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2E_6copied6CopiedINtNtNtB1F_5slice4iter4IterhEEENvYhINtNtB1F_7convert4FromNtB34_6NibbleE4fromEEB7_
Line
Count
Source
786
1.04M
    pub fn block_storage_get(
787
1.04M
        &self,
788
1.04M
        block_hash: &[u8; 32],
789
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
1.04M
        key_nibbles: impl Iterator<Item = u8>,
791
1.04M
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
793
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
1.04M
        // the database as well.
795
1.04M
        let key_vectored = parent_tries_paths_nibbles
796
1.04M
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
1.04M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
1.04M
            .collect::<Vec<_>>();
799
1.04M
800
1.04M
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
1.04M
        let mut statement = connection
806
1.04M
            .prepare_cached(
807
1.04M
                r#"
808
1.04M
            WITH RECURSIVE
809
1.04M
                -- At the end of the recursive statement, `node_with_key` must always contain
810
1.04M
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
1.04M
                -- indicates that we have found a match, while null means that the search has
812
1.04M
                -- been interrupted due to a storage entry not being in the database. If
813
1.04M
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
1.04M
                -- or null in case there is no entry with the requested key. If `search_remain`
815
1.04M
                -- is null, then `node_hash` is irrelevant.
816
1.04M
                --
817
1.04M
                -- In order to properly handle the situation where the key is empty, the initial
818
1.04M
                -- request of the recursive table building must check whether the partial key of
819
1.04M
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
1.04M
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
1.04M
                -- and after the partial key has already been verified to be correct.
822
1.04M
                node_with_key(node_hash, search_remain) AS (
823
1.04M
                        SELECT
824
1.04M
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
1.04M
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
1.04M
                        FROM blocks
827
1.04M
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
1.04M
                        WHERE blocks.hash = :block_hash
829
1.04M
                    UNION ALL
830
1.04M
                    SELECT
831
1.04M
                        CASE
832
1.04M
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
1.04M
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
1.04M
                            ELSE NULL END,
835
1.04M
                        CASE
836
1.04M
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
1.04M
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
1.04M
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
1.04M
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
1.04M
                            ELSE X'' END
841
1.04M
                    FROM node_with_key
842
1.04M
                        LEFT JOIN trie_node_child
843
1.04M
                            ON node_with_key.node_hash = trie_node_child.hash
844
1.04M
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
1.04M
                        LEFT JOIN trie_node
846
1.04M
                            ON trie_node.hash = trie_node_child.child_hash
847
1.04M
                        LEFT JOIN trie_node_storage
848
1.04M
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
1.04M
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
1.04M
                )
851
1.04M
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
1.04M
            FROM blocks
853
1.04M
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
1.04M
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
1.04M
            WHERE blocks.hash = :block_hash;
856
1.04M
            "#)
857
1.04M
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
1.04M
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
1.04M
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
1.04M
            .query_row(
892
1.04M
                rusqlite::named_params! {
893
1.04M
                    ":block_hash": &block_hash[..],
894
1.04M
                    ":key": key_vectored,
895
1.04M
                },
896
1.04M
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
1.04M
                },
903
1.04M
            )
904
1.04M
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
1.04M
            })
?0
;
907
908
1.04M
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
1.04M
        }
911
1.04M
912
1.04M
        if incomplete_storage {
913
0
            return Err(StorageAccessError::IncompleteStorage);
914
1.04M
        }
915
916
1.04M
        let Some(
value209k
) = value else { return
Ok(None)838k
};
917
918
209k
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
209k
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
209k
            .map_err(StorageAccessError::Corrupted)
?0
;
921
209k
        Ok(Some((value, trie_entry_version)))
922
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1F_5array4iter8IntoIterhKj0_EEB7_
Line
Count
Source
786
3
    pub fn block_storage_get(
787
3
        &self,
788
3
        block_hash: &[u8; 32],
789
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
3
        key_nibbles: impl Iterator<Item = u8>,
791
3
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
3
        // Process the iterators at the very beginning and before locking the database, in order
793
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
3
        // the database as well.
795
3
        let key_vectored = parent_tries_paths_nibbles
796
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
3
            .collect::<Vec<_>>();
799
3
800
3
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
3
        let mut statement = connection
806
3
            .prepare_cached(
807
3
                r#"
808
3
            WITH RECURSIVE
809
3
                -- At the end of the recursive statement, `node_with_key` must always contain
810
3
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
3
                -- indicates that we have found a match, while null means that the search has
812
3
                -- been interrupted due to a storage entry not being in the database. If
813
3
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
3
                -- or null in case there is no entry with the requested key. If `search_remain`
815
3
                -- is null, then `node_hash` is irrelevant.
816
3
                --
817
3
                -- In order to properly handle the situation where the key is empty, the initial
818
3
                -- request of the recursive table building must check whether the partial key of
819
3
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
3
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
3
                -- and after the partial key has already been verified to be correct.
822
3
                node_with_key(node_hash, search_remain) AS (
823
3
                        SELECT
824
3
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
3
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
3
                        FROM blocks
827
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
3
                        WHERE blocks.hash = :block_hash
829
3
                    UNION ALL
830
3
                    SELECT
831
3
                        CASE
832
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
3
                            ELSE NULL END,
835
3
                        CASE
836
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
3
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
3
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
3
                            ELSE X'' END
841
3
                    FROM node_with_key
842
3
                        LEFT JOIN trie_node_child
843
3
                            ON node_with_key.node_hash = trie_node_child.hash
844
3
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
3
                        LEFT JOIN trie_node
846
3
                            ON trie_node.hash = trie_node_child.child_hash
847
3
                        LEFT JOIN trie_node_storage
848
3
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
3
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
3
                )
851
3
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
3
            FROM blocks
853
3
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
3
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
3
            WHERE blocks.hash = :block_hash;
856
3
            "#)
857
3
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
3
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
3
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
3
            .query_row(
892
3
                rusqlite::named_params! {
893
3
                    ":block_hash": &block_hash[..],
894
3
                    ":key": key_vectored,
895
3
                },
896
3
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
903
3
            )
904
3
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
3
            })
?0
;
907
908
3
        if !has_block {
909
1
            return Err(StorageAccessError::UnknownBlock);
910
2
        }
911
2
912
2
        if incomplete_storage {
913
1
            return Err(StorageAccessError::IncompleteStorage);
914
1
        }
915
916
1
        let Some(
value0
) = value else { return Ok(None) };
917
918
0
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
0
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
0
            .map_err(StorageAccessError::Corrupted)?;
921
0
        Ok(Some((value, trie_entry_version)))
922
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1F_5array4iter8IntoIterhKj2_EEB7_
Line
Count
Source
786
3
    pub fn block_storage_get(
787
3
        &self,
788
3
        block_hash: &[u8; 32],
789
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
3
        key_nibbles: impl Iterator<Item = u8>,
791
3
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
3
        // Process the iterators at the very beginning and before locking the database, in order
793
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
3
        // the database as well.
795
3
        let key_vectored = parent_tries_paths_nibbles
796
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
3
            .collect::<Vec<_>>();
799
3
800
3
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
3
        let mut statement = connection
806
3
            .prepare_cached(
807
3
                r#"
808
3
            WITH RECURSIVE
809
3
                -- At the end of the recursive statement, `node_with_key` must always contain
810
3
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
3
                -- indicates that we have found a match, while null means that the search has
812
3
                -- been interrupted due to a storage entry not being in the database. If
813
3
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
3
                -- or null in case there is no entry with the requested key. If `search_remain`
815
3
                -- is null, then `node_hash` is irrelevant.
816
3
                --
817
3
                -- In order to properly handle the situation where the key is empty, the initial
818
3
                -- request of the recursive table building must check whether the partial key of
819
3
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
3
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
3
                -- and after the partial key has already been verified to be correct.
822
3
                node_with_key(node_hash, search_remain) AS (
823
3
                        SELECT
824
3
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
3
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
3
                        FROM blocks
827
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
3
                        WHERE blocks.hash = :block_hash
829
3
                    UNION ALL
830
3
                    SELECT
831
3
                        CASE
832
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
3
                            ELSE NULL END,
835
3
                        CASE
836
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
3
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
3
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
3
                            ELSE X'' END
841
3
                    FROM node_with_key
842
3
                        LEFT JOIN trie_node_child
843
3
                            ON node_with_key.node_hash = trie_node_child.hash
844
3
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
3
                        LEFT JOIN trie_node
846
3
                            ON trie_node.hash = trie_node_child.child_hash
847
3
                        LEFT JOIN trie_node_storage
848
3
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
3
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
3
                )
851
3
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
3
            FROM blocks
853
3
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
3
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
3
            WHERE blocks.hash = :block_hash;
856
3
            "#)
857
3
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
3
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
3
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
3
            .query_row(
892
3
                rusqlite::named_params! {
893
3
                    ":block_hash": &block_hash[..],
894
3
                    ":key": key_vectored,
895
3
                },
896
3
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
903
3
            )
904
3
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
3
            })
?0
;
907
908
3
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
3
        }
911
3
912
3
        if incomplete_storage {
913
1
            return Err(StorageAccessError::IncompleteStorage);
914
2
        }
915
916
2
        let Some(value) = value else { return 
Ok(None)0
};
917
918
2
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
2
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
2
            .map_err(StorageAccessError::Corrupted)
?0
;
921
2
        Ok(Some((value, trie_entry_version)))
922
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1F_5array4iter8IntoIterhKj3_EEB7_
Line
Count
Source
786
3
    pub fn block_storage_get(
787
3
        &self,
788
3
        block_hash: &[u8; 32],
789
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
3
        key_nibbles: impl Iterator<Item = u8>,
791
3
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
3
        // Process the iterators at the very beginning and before locking the database, in order
793
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
3
        // the database as well.
795
3
        let key_vectored = parent_tries_paths_nibbles
796
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
3
            .collect::<Vec<_>>();
799
3
800
3
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
3
        let mut statement = connection
806
3
            .prepare_cached(
807
3
                r#"
808
3
            WITH RECURSIVE
809
3
                -- At the end of the recursive statement, `node_with_key` must always contain
810
3
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
3
                -- indicates that we have found a match, while null means that the search has
812
3
                -- been interrupted due to a storage entry not being in the database. If
813
3
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
3
                -- or null in case there is no entry with the requested key. If `search_remain`
815
3
                -- is null, then `node_hash` is irrelevant.
816
3
                --
817
3
                -- In order to properly handle the situation where the key is empty, the initial
818
3
                -- request of the recursive table building must check whether the partial key of
819
3
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
3
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
3
                -- and after the partial key has already been verified to be correct.
822
3
                node_with_key(node_hash, search_remain) AS (
823
3
                        SELECT
824
3
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
3
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
3
                        FROM blocks
827
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
3
                        WHERE blocks.hash = :block_hash
829
3
                    UNION ALL
830
3
                    SELECT
831
3
                        CASE
832
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
3
                            ELSE NULL END,
835
3
                        CASE
836
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
3
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
3
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
3
                            ELSE X'' END
841
3
                    FROM node_with_key
842
3
                        LEFT JOIN trie_node_child
843
3
                            ON node_with_key.node_hash = trie_node_child.hash
844
3
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
3
                        LEFT JOIN trie_node
846
3
                            ON trie_node.hash = trie_node_child.child_hash
847
3
                        LEFT JOIN trie_node_storage
848
3
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
3
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
3
                )
851
3
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
3
            FROM blocks
853
3
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
3
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
3
            WHERE blocks.hash = :block_hash;
856
3
            "#)
857
3
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
3
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
3
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
3
            .query_row(
892
3
                rusqlite::named_params! {
893
3
                    ":block_hash": &block_hash[..],
894
3
                    ":key": key_vectored,
895
3
                },
896
3
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
903
3
            )
904
3
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
3
            })
?0
;
907
908
3
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
3
        }
911
3
912
3
        if incomplete_storage {
913
1
            return Err(StorageAccessError::IncompleteStorage);
914
2
        }
915
916
2
        let Some(
value0
) = value else { return Ok(None) };
917
918
0
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
0
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
0
            .map_err(StorageAccessError::Corrupted)?;
921
0
        Ok(Some((value, trie_entry_version)))
922
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1F_5array4iter8IntoIterhKj4_EEB7_
Line
Count
Source
786
3
    pub fn block_storage_get(
787
3
        &self,
788
3
        block_hash: &[u8; 32],
789
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
3
        key_nibbles: impl Iterator<Item = u8>,
791
3
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
3
        // Process the iterators at the very beginning and before locking the database, in order
793
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
3
        // the database as well.
795
3
        let key_vectored = parent_tries_paths_nibbles
796
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
3
            .collect::<Vec<_>>();
799
3
800
3
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
3
        let mut statement = connection
806
3
            .prepare_cached(
807
3
                r#"
808
3
            WITH RECURSIVE
809
3
                -- At the end of the recursive statement, `node_with_key` must always contain
810
3
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
3
                -- indicates that we have found a match, while null means that the search has
812
3
                -- been interrupted due to a storage entry not being in the database. If
813
3
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
3
                -- or null in case there is no entry with the requested key. If `search_remain`
815
3
                -- is null, then `node_hash` is irrelevant.
816
3
                --
817
3
                -- In order to properly handle the situation where the key is empty, the initial
818
3
                -- request of the recursive table building must check whether the partial key of
819
3
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
3
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
3
                -- and after the partial key has already been verified to be correct.
822
3
                node_with_key(node_hash, search_remain) AS (
823
3
                        SELECT
824
3
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
3
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
3
                        FROM blocks
827
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
3
                        WHERE blocks.hash = :block_hash
829
3
                    UNION ALL
830
3
                    SELECT
831
3
                        CASE
832
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
3
                            ELSE NULL END,
835
3
                        CASE
836
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
3
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
3
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
3
                            ELSE X'' END
841
3
                    FROM node_with_key
842
3
                        LEFT JOIN trie_node_child
843
3
                            ON node_with_key.node_hash = trie_node_child.hash
844
3
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
3
                        LEFT JOIN trie_node
846
3
                            ON trie_node.hash = trie_node_child.child_hash
847
3
                        LEFT JOIN trie_node_storage
848
3
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
3
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
3
                )
851
3
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
3
            FROM blocks
853
3
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
3
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
3
            WHERE blocks.hash = :block_hash;
856
3
            "#)
857
3
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
3
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
3
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
3
            .query_row(
892
3
                rusqlite::named_params! {
893
3
                    ":block_hash": &block_hash[..],
894
3
                    ":key": key_vectored,
895
3
                },
896
3
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
903
3
            )
904
3
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
3
            })
?0
;
907
908
3
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
3
        }
911
3
912
3
        if incomplete_storage {
913
2
            return Err(StorageAccessError::IncompleteStorage);
914
1
        }
915
916
1
        let Some(
value0
) = value else { return Ok(None) };
917
918
0
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
0
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
0
            .map_err(StorageAccessError::Corrupted)?;
921
0
        Ok(Some((value, trie_entry_version)))
922
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1x_B1w_EINtNtNtB1F_5array4iter8IntoIterhKj5_EEB7_
Line
Count
Source
786
3
    pub fn block_storage_get(
787
3
        &self,
788
3
        block_hash: &[u8; 32],
789
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
3
        key_nibbles: impl Iterator<Item = u8>,
791
3
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
3
        // Process the iterators at the very beginning and before locking the database, in order
793
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
3
        // the database as well.
795
3
        let key_vectored = parent_tries_paths_nibbles
796
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
3
            .collect::<Vec<_>>();
799
3
800
3
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
3
        let mut statement = connection
806
3
            .prepare_cached(
807
3
                r#"
808
3
            WITH RECURSIVE
809
3
                -- At the end of the recursive statement, `node_with_key` must always contain
810
3
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
3
                -- indicates that we have found a match, while null means that the search has
812
3
                -- been interrupted due to a storage entry not being in the database. If
813
3
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
3
                -- or null in case there is no entry with the requested key. If `search_remain`
815
3
                -- is null, then `node_hash` is irrelevant.
816
3
                --
817
3
                -- In order to properly handle the situation where the key is empty, the initial
818
3
                -- request of the recursive table building must check whether the partial key of
819
3
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
3
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
3
                -- and after the partial key has already been verified to be correct.
822
3
                node_with_key(node_hash, search_remain) AS (
823
3
                        SELECT
824
3
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
3
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
3
                        FROM blocks
827
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
3
                        WHERE blocks.hash = :block_hash
829
3
                    UNION ALL
830
3
                    SELECT
831
3
                        CASE
832
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
3
                            ELSE NULL END,
835
3
                        CASE
836
3
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
3
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
3
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
3
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
3
                            ELSE X'' END
841
3
                    FROM node_with_key
842
3
                        LEFT JOIN trie_node_child
843
3
                            ON node_with_key.node_hash = trie_node_child.hash
844
3
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
3
                        LEFT JOIN trie_node
846
3
                            ON trie_node.hash = trie_node_child.child_hash
847
3
                        LEFT JOIN trie_node_storage
848
3
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
3
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
3
                )
851
3
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
3
            FROM blocks
853
3
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
3
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
3
            WHERE blocks.hash = :block_hash;
856
3
            "#)
857
3
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
3
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
3
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
3
            .query_row(
892
3
                rusqlite::named_params! {
893
3
                    ":block_hash": &block_hash[..],
894
3
                    ":key": key_vectored,
895
3
                },
896
3
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
3
                },
903
3
            )
904
3
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
3
            })
?0
;
907
908
3
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
3
        }
911
3
912
3
        if incomplete_storage {
913
2
            return Err(StorageAccessError::IncompleteStorage);
914
1
        }
915
916
1
        let Some(value) = value else { return 
Ok(None)0
};
917
918
1
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
1
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
1
            .map_err(StorageAccessError::Corrupted)
?0
;
921
1
        Ok(Some((value, trie_entry_version)))
922
3
    }
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2F_6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEENvYhINtNtB1G_7convert4FromNtB35_6NibbleE4fromEEB7_
Line
Count
Source
786
84
    pub fn block_storage_get(
787
84
        &self,
788
84
        block_hash: &[u8; 32],
789
84
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
84
        key_nibbles: impl Iterator<Item = u8>,
791
84
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
84
        // Process the iterators at the very beginning and before locking the database, in order
793
84
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
84
        // the database as well.
795
84
        let key_vectored = parent_tries_paths_nibbles
796
84
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
84
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
84
            .collect::<Vec<_>>();
799
84
800
84
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
84
        let mut statement = connection
806
84
            .prepare_cached(
807
84
                r#"
808
84
            WITH RECURSIVE
809
84
                -- At the end of the recursive statement, `node_with_key` must always contain
810
84
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
84
                -- indicates that we have found a match, while null means that the search has
812
84
                -- been interrupted due to a storage entry not being in the database. If
813
84
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
84
                -- or null in case there is no entry with the requested key. If `search_remain`
815
84
                -- is null, then `node_hash` is irrelevant.
816
84
                --
817
84
                -- In order to properly handle the situation where the key is empty, the initial
818
84
                -- request of the recursive table building must check whether the partial key of
819
84
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
84
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
84
                -- and after the partial key has already been verified to be correct.
822
84
                node_with_key(node_hash, search_remain) AS (
823
84
                        SELECT
824
84
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
84
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
84
                        FROM blocks
827
84
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
84
                        WHERE blocks.hash = :block_hash
829
84
                    UNION ALL
830
84
                    SELECT
831
84
                        CASE
832
84
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
84
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
84
                            ELSE NULL END,
835
84
                        CASE
836
84
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
84
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
84
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
84
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
84
                            ELSE X'' END
841
84
                    FROM node_with_key
842
84
                        LEFT JOIN trie_node_child
843
84
                            ON node_with_key.node_hash = trie_node_child.hash
844
84
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
84
                        LEFT JOIN trie_node
846
84
                            ON trie_node.hash = trie_node_child.child_hash
847
84
                        LEFT JOIN trie_node_storage
848
84
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
84
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
84
                )
851
84
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
84
            FROM blocks
853
84
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
84
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
84
            WHERE blocks.hash = :block_hash;
856
84
            "#)
857
84
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
84
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
84
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
84
            .query_row(
892
84
                rusqlite::named_params! {
893
84
                    ":block_hash": &block_hash[..],
894
84
                    ":key": key_vectored,
895
84
                },
896
84
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
84
                },
903
84
            )
904
84
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
84
            })
?0
;
907
908
84
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
84
        }
911
84
912
84
        if incomplete_storage {
913
0
            return Err(StorageAccessError::IncompleteStorage);
914
84
        }
915
916
84
        let Some(
value63
) = value else { return
Ok(None)21
};
917
918
63
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
63
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
63
            .map_err(StorageAccessError::Corrupted)
?0
;
921
63
        Ok(Some((value, trie_entry_version)))
922
84
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3Z_14SyncBackground12author_block0s_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB1G_5slice4iter4IterNtNtNtB7_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB33_B5q_EE0s3_00s0_0EECsiLzmwikkc22_14json_rpc_basic
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2F_6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEENvYhINtNtB1G_7convert4FromNtB35_6NibbleE4fromEECsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
786
4
    pub fn block_storage_get(
787
4
        &self,
788
4
        block_hash: &[u8; 32],
789
4
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
4
        key_nibbles: impl Iterator<Item = u8>,
791
4
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
4
        // Process the iterators at the very beginning and before locking the database, in order
793
4
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
4
        // the database as well.
795
4
        let key_vectored = parent_tries_paths_nibbles
796
4
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
4
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
4
            .collect::<Vec<_>>();
799
4
800
4
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
4
        let mut statement = connection
806
4
            .prepare_cached(
807
4
                r#"
808
4
            WITH RECURSIVE
809
4
                -- At the end of the recursive statement, `node_with_key` must always contain
810
4
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
4
                -- indicates that we have found a match, while null means that the search has
812
4
                -- been interrupted due to a storage entry not being in the database. If
813
4
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
4
                -- or null in case there is no entry with the requested key. If `search_remain`
815
4
                -- is null, then `node_hash` is irrelevant.
816
4
                --
817
4
                -- In order to properly handle the situation where the key is empty, the initial
818
4
                -- request of the recursive table building must check whether the partial key of
819
4
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
4
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
4
                -- and after the partial key has already been verified to be correct.
822
4
                node_with_key(node_hash, search_remain) AS (
823
4
                        SELECT
824
4
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
4
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
4
                        FROM blocks
827
4
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
4
                        WHERE blocks.hash = :block_hash
829
4
                    UNION ALL
830
4
                    SELECT
831
4
                        CASE
832
4
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
4
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
4
                            ELSE NULL END,
835
4
                        CASE
836
4
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
4
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
4
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
4
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
4
                            ELSE X'' END
841
4
                    FROM node_with_key
842
4
                        LEFT JOIN trie_node_child
843
4
                            ON node_with_key.node_hash = trie_node_child.hash
844
4
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
4
                        LEFT JOIN trie_node
846
4
                            ON trie_node.hash = trie_node_child.child_hash
847
4
                        LEFT JOIN trie_node_storage
848
4
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
4
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
4
                )
851
4
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
4
            FROM blocks
853
4
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
4
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
4
            WHERE blocks.hash = :block_hash;
856
4
            "#)
857
4
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
4
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
4
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
4
            .query_row(
892
4
                rusqlite::named_params! {
893
4
                    ":block_hash": &block_hash[..],
894
4
                    ":key": key_vectored,
895
4
                },
896
4
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
4
                },
903
4
            )
904
4
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
4
            })
?0
;
907
908
4
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
4
        }
911
4
912
4
        if incomplete_storage {
913
0
            return Err(StorageAccessError::IncompleteStorage);
914
4
        }
915
916
4
        let Some(
value2
) = value else { return
Ok(None)2
};
917
918
2
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
2
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
2
            .map_err(StorageAccessError::Corrupted)
?0
;
921
2
        Ok(Some((value, trie_entry_version)))
922
4
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0s7_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEEB40_
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2F_6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEENvYhINtNtB1G_7convert4FromNtB35_6NibbleE4fromEECsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
786
4
    pub fn block_storage_get(
787
4
        &self,
788
4
        block_hash: &[u8; 32],
789
4
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
4
        key_nibbles: impl Iterator<Item = u8>,
791
4
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
4
        // Process the iterators at the very beginning and before locking the database, in order
793
4
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
4
        // the database as well.
795
4
        let key_vectored = parent_tries_paths_nibbles
796
4
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
4
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
4
            .collect::<Vec<_>>();
799
4
800
4
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
4
        let mut statement = connection
806
4
            .prepare_cached(
807
4
                r#"
808
4
            WITH RECURSIVE
809
4
                -- At the end of the recursive statement, `node_with_key` must always contain
810
4
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
4
                -- indicates that we have found a match, while null means that the search has
812
4
                -- been interrupted due to a storage entry not being in the database. If
813
4
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
4
                -- or null in case there is no entry with the requested key. If `search_remain`
815
4
                -- is null, then `node_hash` is irrelevant.
816
4
                --
817
4
                -- In order to properly handle the situation where the key is empty, the initial
818
4
                -- request of the recursive table building must check whether the partial key of
819
4
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
4
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
4
                -- and after the partial key has already been verified to be correct.
822
4
                node_with_key(node_hash, search_remain) AS (
823
4
                        SELECT
824
4
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
4
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
4
                        FROM blocks
827
4
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
4
                        WHERE blocks.hash = :block_hash
829
4
                    UNION ALL
830
4
                    SELECT
831
4
                        CASE
832
4
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
4
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
4
                            ELSE NULL END,
835
4
                        CASE
836
4
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
4
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
4
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
4
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
4
                            ELSE X'' END
841
4
                    FROM node_with_key
842
4
                        LEFT JOIN trie_node_child
843
4
                            ON node_with_key.node_hash = trie_node_child.hash
844
4
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
4
                        LEFT JOIN trie_node
846
4
                            ON trie_node.hash = trie_node_child.child_hash
847
4
                        LEFT JOIN trie_node_storage
848
4
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
4
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
4
                )
851
4
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
4
            FROM blocks
853
4
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
4
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
4
            WHERE blocks.hash = :block_hash;
856
4
            "#)
857
4
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
4
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
4
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
4
            .query_row(
892
4
                rusqlite::named_params! {
893
4
                    ":block_hash": &block_hash[..],
894
4
                    ":key": key_vectored,
895
4
                },
896
4
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
4
                },
903
4
            )
904
4
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
4
            })
?0
;
907
908
4
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
4
        }
911
4
912
4
        if incomplete_storage {
913
0
            return Err(StorageAccessError::IncompleteStorage);
914
4
        }
915
916
4
        let Some(
value2
) = value else { return
Ok(None)2
};
917
918
2
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
2
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
2
            .map_err(StorageAccessError::Corrupted)
?0
;
921
2
        Ok(Some((value, trie_entry_version)))
922
4
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEECsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3Z_14SyncBackground12author_block0s_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB1G_5slice4iter4IterNtNtNtB7_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB33_B5q_EE0s3_00s0_0EECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2F_6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEENvYhINtNtB1G_7convert4FromNtB35_6NibbleE4fromEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3Z_14SyncBackground12author_block0s_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2w_6option8IntoIterINtB1C_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s0_00EINtNtB2s_6copied6CopiedINtNtNtB2w_5slice4iter4IterhEEECsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB1G_5slice4iter4IterNtNtNtB7_4trie6nibble6NibbleENCNCNCNCINvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service24execute_block_and_insertRINtNtCsdZExvAaxgia_5alloc3vec3VechEIB33_B5q_EE0s3_00s0_0EECsibGXYHQB8Ea_25json_rpc_general_requests
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase17block_storage_getINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1y_B1x_EINtNtNtB1E_8adapters3map3MapINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2F_6copied6CopiedINtNtNtB1G_5slice4iter4IterhEEENvYhINtNtB1G_7convert4FromNtB35_6NibbleE4fromEECsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
786
38
    pub fn block_storage_get(
787
38
        &self,
788
38
        block_hash: &[u8; 32],
789
38
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
790
38
        key_nibbles: impl Iterator<Item = u8>,
791
38
    ) -> Result<Option<(Vec<u8>, u8)>, StorageAccessError> {
792
38
        // Process the iterators at the very beginning and before locking the database, in order
793
38
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
794
38
        // the database as well.
795
38
        let key_vectored = parent_tries_paths_nibbles
796
38
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
797
38
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
798
38
            .collect::<Vec<_>>();
799
38
800
38
        let connection = self.database.lock();
801
802
        // TODO: could be optimized by having a different request when `parent_tries_paths_nibbles` is empty and when it isn't
803
        // TODO: trie_root_ref system untested
804
        // TODO: infinite loop if there's a loop in the trie; detect this
805
38
        let mut statement = connection
806
38
            .prepare_cached(
807
38
                r#"
808
38
            WITH RECURSIVE
809
38
                -- At the end of the recursive statement, `node_with_key` must always contain
810
38
                -- one and exactly one item where `search_remain` is either empty or null. Empty
811
38
                -- indicates that we have found a match, while null means that the search has
812
38
                -- been interrupted due to a storage entry not being in the database. If
813
38
                -- `search_remain` is empty, then `node_hash` is either a hash in case of a match
814
38
                -- or null in case there is no entry with the requested key. If `search_remain`
815
38
                -- is null, then `node_hash` is irrelevant.
816
38
                --
817
38
                -- In order to properly handle the situation where the key is empty, the initial
818
38
                -- request of the recursive table building must check whether the partial key of
819
38
                -- the root matches. In other words, all the entries of `node_with_key` (where
820
38
                -- `node_hash` is non-null) contain entries that are known to be in the database
821
38
                -- and after the partial key has already been verified to be correct.
822
38
                node_with_key(node_hash, search_remain) AS (
823
38
                        SELECT
824
38
                            IIF(COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key, trie_node.hash, NULL),
825
38
                            IIF(trie_node.partial_key IS NULL, NULL, COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X''))
826
38
                        FROM blocks
827
38
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
828
38
                        WHERE blocks.hash = :block_hash
829
38
                    UNION ALL
830
38
                    SELECT
831
38
                        CASE
832
38
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN trie_node_storage.trie_root_ref
833
38
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN trie_node_child.child_hash
834
38
                            ELSE NULL END,
835
38
                        CASE
836
38
                            WHEN HEX(SUBSTR(node_with_key.search_remain, 1, 1)) = '10' THEN SUBSTR(node_with_key.search_remain, 1)
837
38
                            WHEN trie_node_child.child_hash IS NULL THEN X''
838
38
                            WHEN trie_node.partial_key IS NULL THEN NULL
839
38
                            WHEN SUBSTR(node_with_key.search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key THEN SUBSTR(node_with_key.search_remain, 2 + LENGTH(trie_node.partial_key))
840
38
                            ELSE X'' END
841
38
                    FROM node_with_key
842
38
                        LEFT JOIN trie_node_child
843
38
                            ON node_with_key.node_hash = trie_node_child.hash
844
38
                            AND SUBSTR(node_with_key.search_remain, 1, 1) = trie_node_child.child_num
845
38
                        LEFT JOIN trie_node
846
38
                            ON trie_node.hash = trie_node_child.child_hash
847
38
                        LEFT JOIN trie_node_storage
848
38
                            ON node_with_key.node_hash = trie_node_storage.node_hash
849
38
                        WHERE LENGTH(node_with_key.search_remain) >= 1
850
38
                )
851
38
            SELECT COUNT(blocks.hash) >= 1, node_with_key.search_remain IS NULL, COALESCE(trie_node_storage.value, trie_node_storage.trie_root_ref), trie_node_storage.trie_entry_version
852
38
            FROM blocks
853
38
            JOIN node_with_key ON LENGTH(node_with_key.search_remain) = 0 OR node_with_key.search_remain IS NULL
854
38
            LEFT JOIN trie_node_storage ON node_with_key.node_hash = trie_node_storage.node_hash AND node_with_key.search_remain IS NOT NULL
855
38
            WHERE blocks.hash = :block_hash;
856
38
            "#)
857
38
            .map_err(|err| {
858
                StorageAccessError::Corrupted(CorruptedError::Internal(
859
                    InternalError(err),
860
                ))
861
38
            })
?0
;
862
863
        // In order to debug the SQL query above (for example in case of a failing test),
864
        // uncomment this block:
865
        //
866
        /*println!("{:?}", {
867
            let mut statement = connection
868
                    .prepare_cached(
869
                        r#"
870
                    WITH RECURSIVE
871
                        copy-paste the definition of node_with_key here
872
873
                    SELECT * FROM node_with_key"#).unwrap();
874
            statement
875
                .query_map(
876
                    rusqlite::named_params! {
877
                        ":block_hash": &block_hash[..],
878
                        ":key": key_vectored,
879
                    },
880
                    |row| {
881
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
882
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
883
                        Ok((node_hash, search_remain))
884
                    },
885
                )
886
                .unwrap()
887
                .collect::<Vec<_>>()
888
        });*/
889
890
38
        let (has_block, incomplete_storage, value, trie_entry_version) = statement
891
38
            .query_row(
892
38
                rusqlite::named_params! {
893
38
                    ":block_hash": &block_hash[..],
894
38
                    ":key": key_vectored,
895
38
                },
896
38
                |row| {
897
                    let has_block = row.get::<_, i64>(0)? != 0;
898
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
899
                    let value = row.get::<_, Option<Vec<u8>>>(2)?;
900
                    let trie_entry_version = row.get::<_, Option<i64>>(3)?;
901
                    Ok((has_block, incomplete_storage, value, trie_entry_version))
902
38
                },
903
38
            )
904
38
            .map_err(|err| {
905
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
906
38
            })
?0
;
907
908
38
        if !has_block {
909
0
            return Err(StorageAccessError::UnknownBlock);
910
38
        }
911
38
912
38
        if incomplete_storage {
913
0
            return Err(StorageAccessError::IncompleteStorage);
914
38
        }
915
916
38
        let Some(
value19
) = value else { return
Ok(None)19
};
917
918
19
        let trie_entry_version = u8::try_from(trie_entry_version.unwrap())
919
19
            .map_err(|_| CorruptedError::InvalidTrieEntryVersion)
920
19
            .map_err(StorageAccessError::Corrupted)
?0
;
921
19
        Ok(Some((value, trie_entry_version)))
922
38
    }
923
924
    /// Returns the key in the storage that immediately follows or is equal to the key passed as
925
    /// parameter in the storage of the block.
926
    ///
927
    /// `key_nibbles` must be an iterator to the **nibbles** of the key.
928
    ///
929
    /// `prefix_nibbles` must be an iterator to nibbles. If the result of the function wouldn't
930
    /// start with this specific list of bytes, `None` is returned.
931
    ///
932
    /// `parent_tries_paths_nibbles` is a list of keys to follow in order to find the root of the
933
    /// trie into which `key_nibbles` should be searched.
934
    ///
935
    /// Returns `None` if `parent_tries_paths_nibbles` didn't lead to any trie, or if there is no
936
    /// next key.
937
    ///
938
    /// The key is returned in the same format as `key_nibbles`.
939
    ///
940
    /// If `branch_nodes` is `false`, then branch nodes (i.e. nodes with no value associated to
941
    /// them) are ignored during the search.
942
    ///
943
    /// > **Note**: Contrary to many other similar functions in smoldot, there is no `or_equal`
944
    /// >           parameter to this function. Instead, `or_equal` is implicitly `true`, and a
945
    /// >           value of `false` can be easily emulated by appending a `0` at the end
946
    /// >           of `key_nibbles`.
947
    ///
948
    /// # Panics
949
    ///
950
    /// Panics if any of the values yielded by `parent_tries_paths_nibbles`, `key_nibbles`, or
951
    /// `prefix_nibbles` is superior or equal to 16.
952
    ///
953
1.04M
    pub fn block_storage_next_key(
954
1.04M
        &self,
955
1.04M
        block_hash: &[u8; 32],
956
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
1.04M
        key_nibbles: impl Iterator<Item = u8>,
958
1.04M
        prefix_nibbles: impl Iterator<Item = u8>,
959
1.04M
        branch_nodes: bool,
960
1.04M
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
962
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
1.04M
        // the database as well.
964
1.04M
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
1.04M
            .flat_map(|t| 
t.inspect(0
|n|
assert!(*n < 160
)0
).chain(iter::once(0x10))0
)
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_E0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_E0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_E0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_E0B47_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_E0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_E0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_E0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_E0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_E0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1M_8adapters3map3MapINtNtB2N_6copied6CopiedINtNtNtB1O_5slice4iter4IterNtNtNtBb_4trie6nibble6NibbleEENvYhINtNtB1O_7convert4FromB3Y_E4fromEB2I_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj0_EB1F_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj0_EB2I_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj1_EB1F_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj2_EB1F_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj3_EB1F_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj3_EB2I_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1G_B1F_EINtNtNtB1O_5array4iter8IntoIterhKj8_EB1F_E00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1H_B1G_EINtNtNtB1N_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtBb_4trie6nibble14BytesToNibblesINtNtB2O_6copied6CopiedINtNtNtB1P_5slice4iter4IterhEEEIB3c_IB3H_INtNvNtBb_4util11as_ref_iter4IterIB3c_RShINtNvMs5_NtNtNtBb_8executor2vm11interpreterNtB68_11Interpreter11read_memory12AccessOffsetB5W_EEhEEINtNtB2O_7flatten7FlatMapINtNtB2O_5chain5ChainIB2K_IB7A_IB4G_NtNtB6c_20trie_root_calculator14InProgressNodeEIB7Z_INtNtB1L_4once4OnceIB3c_ANtB3J_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9N_EEEINtNtB1P_6option8IntoIterB9H_EENCNvMs3_B8A_NtB8A_5Inner21current_node_full_key0ENcNtIB3c_B9H_Ba3_E4Left0EIB9p_Bc4_EEIB5l_Bcu_B9N_EIB5n_B9N_Bcu_EEEENvYhINtNtB1P_7convert4FromB9N_E4fromEIB2K_IB3c_IB3H_IB5l_IB3c_B5R_B5W_EhEEIB3c_B3b_IB1H_B9N_EEEBd5_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB48_14SyncBackground12author_block0s5_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5H_E00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5i_E00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5L_E00B49_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1H_B1G_EINtNtNtB1N_8adapters6copied6CopiedINtNtNtB1P_5slice4iter4IterhEEB2J_E00CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB48_14SyncBackground12author_block0s5_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5H_E00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5i_E00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB48_14SyncBackground12author_block0s5_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5H_E00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2F_6option8IntoIterINtB1L_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2B_6copied6CopiedINtNtNtB2F_5slice4iter4IterhEEB5i_E00CsibGXYHQB8Ea_25json_rpc_general_requests
966
1.04M
            .collect::<Vec<_>>();
967
1.04M
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
1.04M
        let key_nibbles = {
969
1.04M
            let mut v = parent_tries_paths_nibbles.clone();
970
4.20M
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es_0B9_
Line
Count
Source
970
4.19M
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es_0B9_
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es_0B9_
Line
Count
Source
970
1
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es_0B9_
Line
Count
Source
970
8
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es_0B9_
Line
Count
Source
970
15
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es_0B9_
Line
Count
Source
970
3
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es_0B9_
Line
Count
Source
970
16
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es_0B47_
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es_0CsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
970
4.44k
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es_0CsibGXYHQB8Ea_25json_rpc_general_requests
971
1.04M
            v
972
1.04M
        };
973
1.04M
        let prefix_nibbles = {
974
1.04M
            let mut v = parent_tries_paths_nibbles;
975
4.19M
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es0_0B9_
Line
Count
Source
975
4.19M
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es0_0B9_
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es0_0B9_
Line
Count
Source
975
3
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es0_0B47_
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es0_0CsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
975
16
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es0_0CsibGXYHQB8Ea_25json_rpc_general_requests
976
1.04M
            v
977
1.04M
        };
978
1.04M
979
1.04M
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
1.04M
        let mut statement = connection
992
1.04M
            .prepare_cached(
993
1.04M
                r#"
994
1.04M
            WITH RECURSIVE
995
1.04M
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
1.04M
                -- descend the trie by trying to match entries with `:key`.
997
1.04M
                -- At each iteration, `node_hash` is the root where to continue the search,
998
1.04M
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
1.04M
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
1.04M
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
1.04M
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
1.04M
                -- continue was missing from the database, in which case the values of
1003
1.04M
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
1.04M
                -- `node_full_key` is the "best known key".
1005
1.04M
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
1.04M
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
1.04M
                -- is null or empty and that `node_is_branch` is false.
1008
1.04M
                --
1009
1.04M
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
1.04M
                -- the trie has no next key at all. These two situations need to be differentiated
1011
1.04M
                -- in the final SELECT statement.
1012
1.04M
                --
1013
1.04M
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
1.04M
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
1.04M
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
1.04M
                -- result will be after any equal match.
1017
1.04M
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
1.04M
                -- is something like `2 * depth_in_trie(key)`.
1019
1.04M
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
1.04M
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
1.04M
                --
1022
1.04M
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
1.04M
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
1.04M
                -- reason, it is also not possible to automatically pass NULL values
1025
1.04M
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
1.04M
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
1.04M
                        SELECT
1028
1.04M
                            CASE
1029
1.04M
                                WHEN trie_node.hash IS NULL
1030
1.04M
                                    THEN NULL
1031
1.04M
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
1.04M
                                    THEN trie_node.hash
1033
1.04M
                                ELSE
1034
1.04M
                                    NULL
1035
1.04M
                            END,
1036
1.04M
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
1.04M
                            COALESCE(trie_node.partial_key, X''),
1038
1.04M
                            CASE
1039
1.04M
                                WHEN trie_node.partial_key IS NULL
1040
1.04M
                                    THEN NULL
1041
1.04M
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
1.04M
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
1.04M
                                ELSE
1044
1.04M
                                    X''   -- The partial key is strictly inferior to `:key`
1045
1.04M
                            END
1046
1.04M
                        FROM blocks
1047
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
1.04M
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
1.04M
                        WHERE blocks.hash = :block_hash
1050
1.04M
1051
1.04M
                    UNION ALL
1052
1.04M
                        SELECT
1053
1.04M
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
1.04M
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
1.04M
                            CASE
1056
1.04M
                                WHEN trie_node_child.child_num IS NULL
1057
1.04M
                                    THEN next_key.node_full_key
1058
1.04M
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
1.04M
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
1.04M
                                ELSE
1061
1.04M
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
1.04M
                            END,
1063
1.04M
                            CASE
1064
1.04M
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
1.04M
                                    THEN NULL    -- Child exists but is missing from database
1066
1.04M
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
1.04M
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
1.04M
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
1.04M
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
1.04M
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
1.04M
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
1.04M
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
1.04M
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
1.04M
                                ELSE
1075
1.04M
                                    X''          -- Shouldn't be reachable.
1076
1.04M
                            END
1077
1.04M
                        FROM next_key
1078
1.04M
1079
1.04M
                        LEFT JOIN trie_node_child
1080
1.04M
                            ON next_key.node_hash = trie_node_child.hash
1081
1.04M
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
1.04M
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
1.04M
1085
1.04M
                        -- We want to keep only situations where `trie_node_child` is either
1086
1.04M
                        -- equal to the key, or the first child strictly superior to the key. In
1087
1.04M
                        -- order to do that, we try to find another child that is strictly
1088
1.04M
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
1.04M
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
1.04M
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
1.04M
                            ON next_key.node_hash = trie_node_child_before.hash
1092
1.04M
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
1.04M
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
1.04M
1095
1.04M
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
1.04M
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
1.04M
                        LEFT JOIN trie_node AS trie_node_trieref
1098
1.04M
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
1.04M
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
1.04M
1101
1.04M
                        LEFT JOIN trie_node_storage
1102
1.04M
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
1.04M
1104
1.04M
                        WHERE
1105
1.04M
                            -- Don't pull items that have already finished searching.
1106
1.04M
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
1.04M
                            -- See explanation above.
1108
1.04M
                            AND trie_node_child_before.hash IS NULL
1109
1.04M
                            -- Don't generate an item if there's nowhere to go to.
1110
1.04M
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
1.04M
                            -- Stop iterating if the child's partial key is before the searched key.
1112
1.04M
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
1.04M
                ),
1114
1.04M
1115
1.04M
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
1.04M
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
1.04M
                    SELECT
1118
1.04M
                        CASE
1119
1.04M
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
1.04M
                            ELSE key_search_remain IS NULL
1121
1.04M
                        END,
1122
1.04M
                        node_full_key,
1123
1.04M
                        CASE
1124
1.04M
                            WHEN node_hash IS NULL THEN NULL
1125
1.04M
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
1.04M
                            ELSE NULL
1127
1.04M
                        END
1128
1.04M
                    FROM next_key
1129
1.04M
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
1.04M
                )
1131
1.04M
1132
1.04M
            SELECT
1133
1.04M
                COUNT(blocks.hash) >= 1,
1134
1.04M
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
1.04M
                terminal_next_key.output
1136
1.04M
            FROM blocks
1137
1.04M
            LEFT JOIN terminal_next_key
1138
1.04M
            WHERE blocks.hash = :block_hash
1139
1.04M
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
1.04M
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
1.04M
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
1.04M
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
1.04M
                -- figure out.
1144
1.04M
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
1.04M
            LIMIT 1"#,
1146
1.04M
            )
1147
1.04M
            .map_err(|err| {
1148
0
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
0
                    InternalError(err),
1150
0
                ))
1151
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es1_0B47_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es1_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es1_0CsibGXYHQB8Ea_25json_rpc_general_requests
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
1.04M
        let result = statement
1185
1.04M
            .query_row(
1186
1.04M
                rusqlite::named_params! {
1187
1.04M
                    ":block_hash": &block_hash[..],
1188
1.04M
                    ":key": key_nibbles,
1189
1.04M
                    ":prefix": prefix_nibbles,
1190
1.04M
                    ":skip_branches": !branch_nodes
1191
1.04M
                },
1192
1.04M
                |row| {
1193
1.04M
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
1.04M
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
1.04M
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es2_0B9_
Line
Count
Source
1192
1.04M
                |row| {
1193
1.04M
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
1.04M
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
1.04M
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es2_0B9_
Line
Count
Source
1192
2
                |row| {
1193
2
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
2
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
2
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
2
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es2_0B9_
Line
Count
Source
1192
2
                |row| {
1193
2
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
2
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
2
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
2
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es2_0B9_
Line
Count
Source
1192
1
                |row| {
1193
1
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
1
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
1
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
1
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es2_0B9_
Line
Count
Source
1192
4
                |row| {
1193
4
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
4
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
4
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
4
                    Ok((block_is_known, incomplete_storage, next_key))
1197
4
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es2_0B9_
Line
Count
Source
1192
5
                |row| {
1193
5
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
5
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
5
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
5
                    Ok((block_is_known, incomplete_storage, next_key))
1197
5
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es2_0B9_
Line
Count
Source
1192
1
                |row| {
1193
1
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
1
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
1
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
1
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es2_0B9_
Line
Count
Source
1192
2
                |row| {
1193
2
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
2
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
2
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
2
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es2_0B47_
_RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es2_0CsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
1192
51
                |row| {
1193
51
                    let block_is_known = row.get::<_, i64>(0)
?0
!= 0;
1194
51
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1195
51
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1196
51
                    Ok((block_is_known, incomplete_storage, next_key))
1197
51
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es2_0CsibGXYHQB8Ea_25json_rpc_general_requests
1198
1.04M
            )
1199
1.04M
            .optional()
1200
1.04M
            .map_err(|err| {
1201
0
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es3_0B47_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es3_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es3_0CsibGXYHQB8Ea_25json_rpc_general_requests
1203
1204
1.04M
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
1.04M
        if !block_is_known {
1209
3
            return Err(StorageAccessError::UnknownBlock);
1210
1.04M
        }
1211
1.04M
1212
1.04M
        if incomplete_storage {
1213
6
            return Err(StorageAccessError::IncompleteStorage);
1214
1.04M
        }
1215
1.04M
1216
1.04M
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1K_8adapters3map3MapINtNtB2L_6copied6CopiedINtNtNtB1M_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB1M_7convert4FromB3W_E4fromEB2G_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB1D_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj0_EB2G_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj1_EB1D_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj2_EB1D_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB1D_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj3_EB2G_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1E_B1D_EINtNtNtB1M_5array4iter8IntoIterhKj8_EB1D_Es4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB9_4trie6nibble14BytesToNibblesINtNtB2M_6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEEIB3a_IB3F_INtNvNtB9_4util11as_ref_iter4IterIB3a_RShINtNvMs5_NtNtNtB9_8executor2vm11interpreterNtB66_11Interpreter11read_memory12AccessOffsetB5U_EEhEEINtNtB2M_7flatten7FlatMapINtNtB2M_5chain5ChainIB2I_IB7y_IB4E_NtNtB6a_20trie_root_calculator14InProgressNodeEIB7X_INtNtB1J_4once4OnceIB3a_ANtB3H_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9L_EEEINtNtB1N_6option8IntoIterB9F_EENCNvMs3_B8y_NtB8y_5Inner21current_node_full_key0ENcNtIB3a_B9F_Ba1_E4Left0EIB9n_Bc2_EEIB5j_Bcs_B9L_EIB5l_B9L_Bcs_EEEENvYhINtNtB1N_7convert4FromB9L_E4fromEIB2I_IB3a_IB3F_IB5j_IB3a_B5P_B5U_EhEEIB3a_B39_IB1F_B9L_EEEBd3_EEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5J_Es4_0B47_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1F_B1E_EINtNtNtB1L_8adapters6copied6CopiedINtNtNtB1N_5slice4iter4IterhEEB2H_Es4_0CsiUjFBJteJ7x_17smoldot_full_node
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB46_14SyncBackground12author_block0s5_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5F_Es4_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2D_6option8IntoIterINtB1J_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2z_6copied6CopiedINtNtNtB2D_5slice4iter4IterhEEB5g_Es4_0CsibGXYHQB8Ea_25json_rpc_general_requests
1218
1.04M
        }
1219
1220
1.04M
        Ok(next_key)
1221
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1I_8adapters3map3MapINtNtB2J_6copied6CopiedINtNtNtB1K_5slice4iter4IterNtNtNtB7_4trie6nibble6NibbleEENvYhINtNtB1K_7convert4FromB3U_E4fromEB2E_EB7_
Line
Count
Source
953
1.04M
    pub fn block_storage_next_key(
954
1.04M
        &self,
955
1.04M
        block_hash: &[u8; 32],
956
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
1.04M
        key_nibbles: impl Iterator<Item = u8>,
958
1.04M
        prefix_nibbles: impl Iterator<Item = u8>,
959
1.04M
        branch_nodes: bool,
960
1.04M
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
962
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
1.04M
        // the database as well.
964
1.04M
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
1.04M
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
1.04M
            .collect::<Vec<_>>();
967
1.04M
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
1.04M
        let key_nibbles = {
969
1.04M
            let mut v = parent_tries_paths_nibbles.clone();
970
1.04M
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
1.04M
            v
972
1.04M
        };
973
1.04M
        let prefix_nibbles = {
974
1.04M
            let mut v = parent_tries_paths_nibbles;
975
1.04M
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
1.04M
            v
977
1.04M
        };
978
1.04M
979
1.04M
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
1.04M
        let mut statement = connection
992
1.04M
            .prepare_cached(
993
1.04M
                r#"
994
1.04M
            WITH RECURSIVE
995
1.04M
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
1.04M
                -- descend the trie by trying to match entries with `:key`.
997
1.04M
                -- At each iteration, `node_hash` is the root where to continue the search,
998
1.04M
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
1.04M
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
1.04M
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
1.04M
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
1.04M
                -- continue was missing from the database, in which case the values of
1003
1.04M
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
1.04M
                -- `node_full_key` is the "best known key".
1005
1.04M
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
1.04M
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
1.04M
                -- is null or empty and that `node_is_branch` is false.
1008
1.04M
                --
1009
1.04M
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
1.04M
                -- the trie has no next key at all. These two situations need to be differentiated
1011
1.04M
                -- in the final SELECT statement.
1012
1.04M
                --
1013
1.04M
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
1.04M
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
1.04M
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
1.04M
                -- result will be after any equal match.
1017
1.04M
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
1.04M
                -- is something like `2 * depth_in_trie(key)`.
1019
1.04M
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
1.04M
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
1.04M
                --
1022
1.04M
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
1.04M
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
1.04M
                -- reason, it is also not possible to automatically pass NULL values
1025
1.04M
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
1.04M
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
1.04M
                        SELECT
1028
1.04M
                            CASE
1029
1.04M
                                WHEN trie_node.hash IS NULL
1030
1.04M
                                    THEN NULL
1031
1.04M
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
1.04M
                                    THEN trie_node.hash
1033
1.04M
                                ELSE
1034
1.04M
                                    NULL
1035
1.04M
                            END,
1036
1.04M
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
1.04M
                            COALESCE(trie_node.partial_key, X''),
1038
1.04M
                            CASE
1039
1.04M
                                WHEN trie_node.partial_key IS NULL
1040
1.04M
                                    THEN NULL
1041
1.04M
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
1.04M
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
1.04M
                                ELSE
1044
1.04M
                                    X''   -- The partial key is strictly inferior to `:key`
1045
1.04M
                            END
1046
1.04M
                        FROM blocks
1047
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
1.04M
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
1.04M
                        WHERE blocks.hash = :block_hash
1050
1.04M
1051
1.04M
                    UNION ALL
1052
1.04M
                        SELECT
1053
1.04M
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
1.04M
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
1.04M
                            CASE
1056
1.04M
                                WHEN trie_node_child.child_num IS NULL
1057
1.04M
                                    THEN next_key.node_full_key
1058
1.04M
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
1.04M
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
1.04M
                                ELSE
1061
1.04M
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
1.04M
                            END,
1063
1.04M
                            CASE
1064
1.04M
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
1.04M
                                    THEN NULL    -- Child exists but is missing from database
1066
1.04M
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
1.04M
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
1.04M
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
1.04M
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
1.04M
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
1.04M
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
1.04M
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
1.04M
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
1.04M
                                ELSE
1075
1.04M
                                    X''          -- Shouldn't be reachable.
1076
1.04M
                            END
1077
1.04M
                        FROM next_key
1078
1.04M
1079
1.04M
                        LEFT JOIN trie_node_child
1080
1.04M
                            ON next_key.node_hash = trie_node_child.hash
1081
1.04M
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
1.04M
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
1.04M
1085
1.04M
                        -- We want to keep only situations where `trie_node_child` is either
1086
1.04M
                        -- equal to the key, or the first child strictly superior to the key. In
1087
1.04M
                        -- order to do that, we try to find another child that is strictly
1088
1.04M
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
1.04M
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
1.04M
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
1.04M
                            ON next_key.node_hash = trie_node_child_before.hash
1092
1.04M
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
1.04M
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
1.04M
1095
1.04M
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
1.04M
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
1.04M
                        LEFT JOIN trie_node AS trie_node_trieref
1098
1.04M
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
1.04M
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
1.04M
1101
1.04M
                        LEFT JOIN trie_node_storage
1102
1.04M
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
1.04M
1104
1.04M
                        WHERE
1105
1.04M
                            -- Don't pull items that have already finished searching.
1106
1.04M
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
1.04M
                            -- See explanation above.
1108
1.04M
                            AND trie_node_child_before.hash IS NULL
1109
1.04M
                            -- Don't generate an item if there's nowhere to go to.
1110
1.04M
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
1.04M
                            -- Stop iterating if the child's partial key is before the searched key.
1112
1.04M
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
1.04M
                ),
1114
1.04M
1115
1.04M
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
1.04M
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
1.04M
                    SELECT
1118
1.04M
                        CASE
1119
1.04M
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
1.04M
                            ELSE key_search_remain IS NULL
1121
1.04M
                        END,
1122
1.04M
                        node_full_key,
1123
1.04M
                        CASE
1124
1.04M
                            WHEN node_hash IS NULL THEN NULL
1125
1.04M
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
1.04M
                            ELSE NULL
1127
1.04M
                        END
1128
1.04M
                    FROM next_key
1129
1.04M
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
1.04M
                )
1131
1.04M
1132
1.04M
            SELECT
1133
1.04M
                COUNT(blocks.hash) >= 1,
1134
1.04M
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
1.04M
                terminal_next_key.output
1136
1.04M
            FROM blocks
1137
1.04M
            LEFT JOIN terminal_next_key
1138
1.04M
            WHERE blocks.hash = :block_hash
1139
1.04M
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
1.04M
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
1.04M
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
1.04M
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
1.04M
                -- figure out.
1144
1.04M
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
1.04M
            LIMIT 1"#,
1146
1.04M
            )
1147
1.04M
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
1.04M
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
1.04M
        let result = statement
1185
1.04M
            .query_row(
1186
1.04M
                rusqlite::named_params! {
1187
1.04M
                    ":block_hash": &block_hash[..],
1188
1.04M
                    ":key": key_nibbles,
1189
1.04M
                    ":prefix": prefix_nibbles,
1190
1.04M
                    ":skip_branches": !branch_nodes
1191
1.04M
                },
1192
1.04M
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1.04M
                },
1198
1.04M
            )
1199
1.04M
            .optional()
1200
1.04M
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
1.04M
            })
?0
;
1203
1204
1.04M
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
1.04M
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
1.04M
        }
1211
1.04M
1212
1.04M
        if incomplete_storage {
1213
0
            return Err(StorageAccessError::IncompleteStorage);
1214
1.04M
        }
1215
1.04M
1216
1.04M
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
1.04M
        }
1219
1220
1.04M
        Ok(next_key)
1221
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj0_EB1B_EB7_
Line
Count
Source
953
2
    pub fn block_storage_next_key(
954
2
        &self,
955
2
        block_hash: &[u8; 32],
956
2
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
2
        key_nibbles: impl Iterator<Item = u8>,
958
2
        prefix_nibbles: impl Iterator<Item = u8>,
959
2
        branch_nodes: bool,
960
2
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
2
        // Process the iterators at the very beginning and before locking the database, in order
962
2
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
2
        // the database as well.
964
2
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
2
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
2
            .collect::<Vec<_>>();
967
2
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
2
        let key_nibbles = {
969
2
            let mut v = parent_tries_paths_nibbles.clone();
970
2
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
2
            v
972
2
        };
973
2
        let prefix_nibbles = {
974
2
            let mut v = parent_tries_paths_nibbles;
975
2
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
2
            v
977
2
        };
978
2
979
2
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
2
        let mut statement = connection
992
2
            .prepare_cached(
993
2
                r#"
994
2
            WITH RECURSIVE
995
2
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
2
                -- descend the trie by trying to match entries with `:key`.
997
2
                -- At each iteration, `node_hash` is the root where to continue the search,
998
2
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
2
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
2
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
2
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
2
                -- continue was missing from the database, in which case the values of
1003
2
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
2
                -- `node_full_key` is the "best known key".
1005
2
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
2
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
2
                -- is null or empty and that `node_is_branch` is false.
1008
2
                --
1009
2
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
2
                -- the trie has no next key at all. These two situations need to be differentiated
1011
2
                -- in the final SELECT statement.
1012
2
                --
1013
2
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
2
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
2
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
2
                -- result will be after any equal match.
1017
2
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
2
                -- is something like `2 * depth_in_trie(key)`.
1019
2
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
2
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
2
                --
1022
2
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
2
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
2
                -- reason, it is also not possible to automatically pass NULL values
1025
2
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
2
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
2
                        SELECT
1028
2
                            CASE
1029
2
                                WHEN trie_node.hash IS NULL
1030
2
                                    THEN NULL
1031
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
2
                                    THEN trie_node.hash
1033
2
                                ELSE
1034
2
                                    NULL
1035
2
                            END,
1036
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
2
                            COALESCE(trie_node.partial_key, X''),
1038
2
                            CASE
1039
2
                                WHEN trie_node.partial_key IS NULL
1040
2
                                    THEN NULL
1041
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
2
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
2
                                ELSE
1044
2
                                    X''   -- The partial key is strictly inferior to `:key`
1045
2
                            END
1046
2
                        FROM blocks
1047
2
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
2
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
2
                        WHERE blocks.hash = :block_hash
1050
2
1051
2
                    UNION ALL
1052
2
                        SELECT
1053
2
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
2
                            CASE
1056
2
                                WHEN trie_node_child.child_num IS NULL
1057
2
                                    THEN next_key.node_full_key
1058
2
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
2
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
2
                                ELSE
1061
2
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
2
                            END,
1063
2
                            CASE
1064
2
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
2
                                    THEN NULL    -- Child exists but is missing from database
1066
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
2
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
2
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
2
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
2
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
2
                                ELSE
1075
2
                                    X''          -- Shouldn't be reachable.
1076
2
                            END
1077
2
                        FROM next_key
1078
2
1079
2
                        LEFT JOIN trie_node_child
1080
2
                            ON next_key.node_hash = trie_node_child.hash
1081
2
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
2
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
2
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
2
1085
2
                        -- We want to keep only situations where `trie_node_child` is either
1086
2
                        -- equal to the key, or the first child strictly superior to the key. In
1087
2
                        -- order to do that, we try to find another child that is strictly
1088
2
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
2
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
2
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
2
                            ON next_key.node_hash = trie_node_child_before.hash
1092
2
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
2
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
2
1095
2
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
2
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
2
                        LEFT JOIN trie_node AS trie_node_trieref
1098
2
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
2
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
2
1101
2
                        LEFT JOIN trie_node_storage
1102
2
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
2
1104
2
                        WHERE
1105
2
                            -- Don't pull items that have already finished searching.
1106
2
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
2
                            -- See explanation above.
1108
2
                            AND trie_node_child_before.hash IS NULL
1109
2
                            -- Don't generate an item if there's nowhere to go to.
1110
2
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
2
                            -- Stop iterating if the child's partial key is before the searched key.
1112
2
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
2
                ),
1114
2
1115
2
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
2
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
2
                    SELECT
1118
2
                        CASE
1119
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
2
                            ELSE key_search_remain IS NULL
1121
2
                        END,
1122
2
                        node_full_key,
1123
2
                        CASE
1124
2
                            WHEN node_hash IS NULL THEN NULL
1125
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
2
                            ELSE NULL
1127
2
                        END
1128
2
                    FROM next_key
1129
2
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
2
                )
1131
2
1132
2
            SELECT
1133
2
                COUNT(blocks.hash) >= 1,
1134
2
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
2
                terminal_next_key.output
1136
2
            FROM blocks
1137
2
            LEFT JOIN terminal_next_key
1138
2
            WHERE blocks.hash = :block_hash
1139
2
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
2
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
2
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
2
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
2
                -- figure out.
1144
2
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
2
            LIMIT 1"#,
1146
2
            )
1147
2
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
2
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
2
        let result = statement
1185
2
            .query_row(
1186
2
                rusqlite::named_params! {
1187
2
                    ":block_hash": &block_hash[..],
1188
2
                    ":key": key_nibbles,
1189
2
                    ":prefix": prefix_nibbles,
1190
2
                    ":skip_branches": !branch_nodes
1191
2
                },
1192
2
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
1198
2
            )
1199
2
            .optional()
1200
2
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
2
            })
?0
;
1203
1204
2
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
2
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
2
        }
1211
2
1212
2
        if incomplete_storage {
1213
1
            return Err(StorageAccessError::IncompleteStorage);
1214
1
        }
1215
1
1216
1
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
1
        }
1219
1220
1
        Ok(next_key)
1221
2
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj0_EB2E_EB7_
Line
Count
Source
953
2
    pub fn block_storage_next_key(
954
2
        &self,
955
2
        block_hash: &[u8; 32],
956
2
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
2
        key_nibbles: impl Iterator<Item = u8>,
958
2
        prefix_nibbles: impl Iterator<Item = u8>,
959
2
        branch_nodes: bool,
960
2
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
2
        // Process the iterators at the very beginning and before locking the database, in order
962
2
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
2
        // the database as well.
964
2
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
2
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
2
            .collect::<Vec<_>>();
967
2
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
2
        let key_nibbles = {
969
2
            let mut v = parent_tries_paths_nibbles.clone();
970
2
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
2
            v
972
2
        };
973
2
        let prefix_nibbles = {
974
2
            let mut v = parent_tries_paths_nibbles;
975
2
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
2
            v
977
2
        };
978
2
979
2
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
2
        let mut statement = connection
992
2
            .prepare_cached(
993
2
                r#"
994
2
            WITH RECURSIVE
995
2
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
2
                -- descend the trie by trying to match entries with `:key`.
997
2
                -- At each iteration, `node_hash` is the root where to continue the search,
998
2
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
2
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
2
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
2
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
2
                -- continue was missing from the database, in which case the values of
1003
2
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
2
                -- `node_full_key` is the "best known key".
1005
2
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
2
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
2
                -- is null or empty and that `node_is_branch` is false.
1008
2
                --
1009
2
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
2
                -- the trie has no next key at all. These two situations need to be differentiated
1011
2
                -- in the final SELECT statement.
1012
2
                --
1013
2
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
2
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
2
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
2
                -- result will be after any equal match.
1017
2
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
2
                -- is something like `2 * depth_in_trie(key)`.
1019
2
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
2
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
2
                --
1022
2
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
2
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
2
                -- reason, it is also not possible to automatically pass NULL values
1025
2
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
2
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
2
                        SELECT
1028
2
                            CASE
1029
2
                                WHEN trie_node.hash IS NULL
1030
2
                                    THEN NULL
1031
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
2
                                    THEN trie_node.hash
1033
2
                                ELSE
1034
2
                                    NULL
1035
2
                            END,
1036
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
2
                            COALESCE(trie_node.partial_key, X''),
1038
2
                            CASE
1039
2
                                WHEN trie_node.partial_key IS NULL
1040
2
                                    THEN NULL
1041
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
2
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
2
                                ELSE
1044
2
                                    X''   -- The partial key is strictly inferior to `:key`
1045
2
                            END
1046
2
                        FROM blocks
1047
2
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
2
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
2
                        WHERE blocks.hash = :block_hash
1050
2
1051
2
                    UNION ALL
1052
2
                        SELECT
1053
2
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
2
                            CASE
1056
2
                                WHEN trie_node_child.child_num IS NULL
1057
2
                                    THEN next_key.node_full_key
1058
2
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
2
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
2
                                ELSE
1061
2
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
2
                            END,
1063
2
                            CASE
1064
2
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
2
                                    THEN NULL    -- Child exists but is missing from database
1066
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
2
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
2
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
2
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
2
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
2
                                ELSE
1075
2
                                    X''          -- Shouldn't be reachable.
1076
2
                            END
1077
2
                        FROM next_key
1078
2
1079
2
                        LEFT JOIN trie_node_child
1080
2
                            ON next_key.node_hash = trie_node_child.hash
1081
2
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
2
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
2
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
2
1085
2
                        -- We want to keep only situations where `trie_node_child` is either
1086
2
                        -- equal to the key, or the first child strictly superior to the key. In
1087
2
                        -- order to do that, we try to find another child that is strictly
1088
2
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
2
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
2
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
2
                            ON next_key.node_hash = trie_node_child_before.hash
1092
2
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
2
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
2
1095
2
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
2
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
2
                        LEFT JOIN trie_node AS trie_node_trieref
1098
2
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
2
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
2
1101
2
                        LEFT JOIN trie_node_storage
1102
2
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
2
1104
2
                        WHERE
1105
2
                            -- Don't pull items that have already finished searching.
1106
2
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
2
                            -- See explanation above.
1108
2
                            AND trie_node_child_before.hash IS NULL
1109
2
                            -- Don't generate an item if there's nowhere to go to.
1110
2
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
2
                            -- Stop iterating if the child's partial key is before the searched key.
1112
2
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
2
                ),
1114
2
1115
2
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
2
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
2
                    SELECT
1118
2
                        CASE
1119
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
2
                            ELSE key_search_remain IS NULL
1121
2
                        END,
1122
2
                        node_full_key,
1123
2
                        CASE
1124
2
                            WHEN node_hash IS NULL THEN NULL
1125
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
2
                            ELSE NULL
1127
2
                        END
1128
2
                    FROM next_key
1129
2
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
2
                )
1131
2
1132
2
            SELECT
1133
2
                COUNT(blocks.hash) >= 1,
1134
2
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
2
                terminal_next_key.output
1136
2
            FROM blocks
1137
2
            LEFT JOIN terminal_next_key
1138
2
            WHERE blocks.hash = :block_hash
1139
2
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
2
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
2
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
2
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
2
                -- figure out.
1144
2
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
2
            LIMIT 1"#,
1146
2
            )
1147
2
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
2
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
2
        let result = statement
1185
2
            .query_row(
1186
2
                rusqlite::named_params! {
1187
2
                    ":block_hash": &block_hash[..],
1188
2
                    ":key": key_nibbles,
1189
2
                    ":prefix": prefix_nibbles,
1190
2
                    ":skip_branches": !branch_nodes
1191
2
                },
1192
2
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
1198
2
            )
1199
2
            .optional()
1200
2
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
2
            })
?0
;
1203
1204
2
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
2
        if !block_is_known {
1209
2
            return Err(StorageAccessError::UnknownBlock);
1210
0
        }
1211
0
1212
0
        if incomplete_storage {
1213
0
            return Err(StorageAccessError::IncompleteStorage);
1214
0
        }
1215
0
1216
0
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
0
        }
1219
1220
0
        Ok(next_key)
1221
2
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj1_EB1B_EB7_
Line
Count
Source
953
1
    pub fn block_storage_next_key(
954
1
        &self,
955
1
        block_hash: &[u8; 32],
956
1
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
1
        key_nibbles: impl Iterator<Item = u8>,
958
1
        prefix_nibbles: impl Iterator<Item = u8>,
959
1
        branch_nodes: bool,
960
1
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
1
        // Process the iterators at the very beginning and before locking the database, in order
962
1
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
1
        // the database as well.
964
1
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
1
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
1
            .collect::<Vec<_>>();
967
1
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
1
        let key_nibbles = {
969
1
            let mut v = parent_tries_paths_nibbles.clone();
970
1
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
1
            v
972
1
        };
973
1
        let prefix_nibbles = {
974
1
            let mut v = parent_tries_paths_nibbles;
975
1
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
1
            v
977
1
        };
978
1
979
1
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
1
        let mut statement = connection
992
1
            .prepare_cached(
993
1
                r#"
994
1
            WITH RECURSIVE
995
1
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
1
                -- descend the trie by trying to match entries with `:key`.
997
1
                -- At each iteration, `node_hash` is the root where to continue the search,
998
1
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
1
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
1
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
1
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
1
                -- continue was missing from the database, in which case the values of
1003
1
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
1
                -- `node_full_key` is the "best known key".
1005
1
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
1
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
1
                -- is null or empty and that `node_is_branch` is false.
1008
1
                --
1009
1
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
1
                -- the trie has no next key at all. These two situations need to be differentiated
1011
1
                -- in the final SELECT statement.
1012
1
                --
1013
1
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
1
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
1
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
1
                -- result will be after any equal match.
1017
1
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
1
                -- is something like `2 * depth_in_trie(key)`.
1019
1
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
1
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
1
                --
1022
1
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
1
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
1
                -- reason, it is also not possible to automatically pass NULL values
1025
1
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
1
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
1
                        SELECT
1028
1
                            CASE
1029
1
                                WHEN trie_node.hash IS NULL
1030
1
                                    THEN NULL
1031
1
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
1
                                    THEN trie_node.hash
1033
1
                                ELSE
1034
1
                                    NULL
1035
1
                            END,
1036
1
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
1
                            COALESCE(trie_node.partial_key, X''),
1038
1
                            CASE
1039
1
                                WHEN trie_node.partial_key IS NULL
1040
1
                                    THEN NULL
1041
1
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
1
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
1
                                ELSE
1044
1
                                    X''   -- The partial key is strictly inferior to `:key`
1045
1
                            END
1046
1
                        FROM blocks
1047
1
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
1
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
1
                        WHERE blocks.hash = :block_hash
1050
1
1051
1
                    UNION ALL
1052
1
                        SELECT
1053
1
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
1
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
1
                            CASE
1056
1
                                WHEN trie_node_child.child_num IS NULL
1057
1
                                    THEN next_key.node_full_key
1058
1
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
1
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
1
                                ELSE
1061
1
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
1
                            END,
1063
1
                            CASE
1064
1
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
1
                                    THEN NULL    -- Child exists but is missing from database
1066
1
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
1
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
1
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
1
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
1
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
1
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
1
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
1
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
1
                                ELSE
1075
1
                                    X''          -- Shouldn't be reachable.
1076
1
                            END
1077
1
                        FROM next_key
1078
1
1079
1
                        LEFT JOIN trie_node_child
1080
1
                            ON next_key.node_hash = trie_node_child.hash
1081
1
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
1
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
1
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
1
1085
1
                        -- We want to keep only situations where `trie_node_child` is either
1086
1
                        -- equal to the key, or the first child strictly superior to the key. In
1087
1
                        -- order to do that, we try to find another child that is strictly
1088
1
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
1
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
1
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
1
                            ON next_key.node_hash = trie_node_child_before.hash
1092
1
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
1
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
1
1095
1
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
1
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
1
                        LEFT JOIN trie_node AS trie_node_trieref
1098
1
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
1
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
1
1101
1
                        LEFT JOIN trie_node_storage
1102
1
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
1
1104
1
                        WHERE
1105
1
                            -- Don't pull items that have already finished searching.
1106
1
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
1
                            -- See explanation above.
1108
1
                            AND trie_node_child_before.hash IS NULL
1109
1
                            -- Don't generate an item if there's nowhere to go to.
1110
1
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
1
                            -- Stop iterating if the child's partial key is before the searched key.
1112
1
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
1
                ),
1114
1
1115
1
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
1
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
1
                    SELECT
1118
1
                        CASE
1119
1
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
1
                            ELSE key_search_remain IS NULL
1121
1
                        END,
1122
1
                        node_full_key,
1123
1
                        CASE
1124
1
                            WHEN node_hash IS NULL THEN NULL
1125
1
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
1
                            ELSE NULL
1127
1
                        END
1128
1
                    FROM next_key
1129
1
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
1
                )
1131
1
1132
1
            SELECT
1133
1
                COUNT(blocks.hash) >= 1,
1134
1
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
1
                terminal_next_key.output
1136
1
            FROM blocks
1137
1
            LEFT JOIN terminal_next_key
1138
1
            WHERE blocks.hash = :block_hash
1139
1
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
1
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
1
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
1
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
1
                -- figure out.
1144
1
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
1
            LIMIT 1"#,
1146
1
            )
1147
1
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
1
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
1
        let result = statement
1185
1
            .query_row(
1186
1
                rusqlite::named_params! {
1187
1
                    ":block_hash": &block_hash[..],
1188
1
                    ":key": key_nibbles,
1189
1
                    ":prefix": prefix_nibbles,
1190
1
                    ":skip_branches": !branch_nodes
1191
1
                },
1192
1
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1
                },
1198
1
            )
1199
1
            .optional()
1200
1
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
1
            })
?0
;
1203
1204
1
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
1
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
1
        }
1211
1
1212
1
        if incomplete_storage {
1213
0
            return Err(StorageAccessError::IncompleteStorage);
1214
1
        }
1215
1
1216
1
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
1
        }
1219
1220
1
        Ok(next_key)
1221
1
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj2_EB1B_EB7_
Line
Count
Source
953
4
    pub fn block_storage_next_key(
954
4
        &self,
955
4
        block_hash: &[u8; 32],
956
4
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
4
        key_nibbles: impl Iterator<Item = u8>,
958
4
        prefix_nibbles: impl Iterator<Item = u8>,
959
4
        branch_nodes: bool,
960
4
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
4
        // Process the iterators at the very beginning and before locking the database, in order
962
4
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
4
        // the database as well.
964
4
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
4
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
4
            .collect::<Vec<_>>();
967
4
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
4
        let key_nibbles = {
969
4
            let mut v = parent_tries_paths_nibbles.clone();
970
4
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
4
            v
972
4
        };
973
4
        let prefix_nibbles = {
974
4
            let mut v = parent_tries_paths_nibbles;
975
4
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
4
            v
977
4
        };
978
4
979
4
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
4
        let mut statement = connection
992
4
            .prepare_cached(
993
4
                r#"
994
4
            WITH RECURSIVE
995
4
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
4
                -- descend the trie by trying to match entries with `:key`.
997
4
                -- At each iteration, `node_hash` is the root where to continue the search,
998
4
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
4
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
4
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
4
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
4
                -- continue was missing from the database, in which case the values of
1003
4
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
4
                -- `node_full_key` is the "best known key".
1005
4
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
4
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
4
                -- is null or empty and that `node_is_branch` is false.
1008
4
                --
1009
4
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
4
                -- the trie has no next key at all. These two situations need to be differentiated
1011
4
                -- in the final SELECT statement.
1012
4
                --
1013
4
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
4
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
4
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
4
                -- result will be after any equal match.
1017
4
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
4
                -- is something like `2 * depth_in_trie(key)`.
1019
4
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
4
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
4
                --
1022
4
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
4
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
4
                -- reason, it is also not possible to automatically pass NULL values
1025
4
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
4
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
4
                        SELECT
1028
4
                            CASE
1029
4
                                WHEN trie_node.hash IS NULL
1030
4
                                    THEN NULL
1031
4
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
4
                                    THEN trie_node.hash
1033
4
                                ELSE
1034
4
                                    NULL
1035
4
                            END,
1036
4
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
4
                            COALESCE(trie_node.partial_key, X''),
1038
4
                            CASE
1039
4
                                WHEN trie_node.partial_key IS NULL
1040
4
                                    THEN NULL
1041
4
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
4
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
4
                                ELSE
1044
4
                                    X''   -- The partial key is strictly inferior to `:key`
1045
4
                            END
1046
4
                        FROM blocks
1047
4
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
4
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
4
                        WHERE blocks.hash = :block_hash
1050
4
1051
4
                    UNION ALL
1052
4
                        SELECT
1053
4
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
4
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
4
                            CASE
1056
4
                                WHEN trie_node_child.child_num IS NULL
1057
4
                                    THEN next_key.node_full_key
1058
4
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
4
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
4
                                ELSE
1061
4
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
4
                            END,
1063
4
                            CASE
1064
4
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
4
                                    THEN NULL    -- Child exists but is missing from database
1066
4
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
4
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
4
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
4
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
4
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
4
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
4
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
4
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
4
                                ELSE
1075
4
                                    X''          -- Shouldn't be reachable.
1076
4
                            END
1077
4
                        FROM next_key
1078
4
1079
4
                        LEFT JOIN trie_node_child
1080
4
                            ON next_key.node_hash = trie_node_child.hash
1081
4
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
4
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
4
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
4
1085
4
                        -- We want to keep only situations where `trie_node_child` is either
1086
4
                        -- equal to the key, or the first child strictly superior to the key. In
1087
4
                        -- order to do that, we try to find another child that is strictly
1088
4
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
4
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
4
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
4
                            ON next_key.node_hash = trie_node_child_before.hash
1092
4
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
4
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
4
1095
4
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
4
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
4
                        LEFT JOIN trie_node AS trie_node_trieref
1098
4
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
4
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
4
1101
4
                        LEFT JOIN trie_node_storage
1102
4
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
4
1104
4
                        WHERE
1105
4
                            -- Don't pull items that have already finished searching.
1106
4
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
4
                            -- See explanation above.
1108
4
                            AND trie_node_child_before.hash IS NULL
1109
4
                            -- Don't generate an item if there's nowhere to go to.
1110
4
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
4
                            -- Stop iterating if the child's partial key is before the searched key.
1112
4
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
4
                ),
1114
4
1115
4
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
4
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
4
                    SELECT
1118
4
                        CASE
1119
4
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
4
                            ELSE key_search_remain IS NULL
1121
4
                        END,
1122
4
                        node_full_key,
1123
4
                        CASE
1124
4
                            WHEN node_hash IS NULL THEN NULL
1125
4
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
4
                            ELSE NULL
1127
4
                        END
1128
4
                    FROM next_key
1129
4
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
4
                )
1131
4
1132
4
            SELECT
1133
4
                COUNT(blocks.hash) >= 1,
1134
4
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
4
                terminal_next_key.output
1136
4
            FROM blocks
1137
4
            LEFT JOIN terminal_next_key
1138
4
            WHERE blocks.hash = :block_hash
1139
4
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
4
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
4
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
4
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
4
                -- figure out.
1144
4
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
4
            LIMIT 1"#,
1146
4
            )
1147
4
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
4
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
4
        let result = statement
1185
4
            .query_row(
1186
4
                rusqlite::named_params! {
1187
4
                    ":block_hash": &block_hash[..],
1188
4
                    ":key": key_nibbles,
1189
4
                    ":prefix": prefix_nibbles,
1190
4
                    ":skip_branches": !branch_nodes
1191
4
                },
1192
4
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
4
                },
1198
4
            )
1199
4
            .optional()
1200
4
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
4
            })
?0
;
1203
1204
4
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
4
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
4
        }
1211
4
1212
4
        if incomplete_storage {
1213
2
            return Err(StorageAccessError::IncompleteStorage);
1214
2
        }
1215
2
1216
2
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
2
        }
1219
1220
2
        Ok(next_key)
1221
4
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj3_EB1B_EB7_
Line
Count
Source
953
5
    pub fn block_storage_next_key(
954
5
        &self,
955
5
        block_hash: &[u8; 32],
956
5
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
5
        key_nibbles: impl Iterator<Item = u8>,
958
5
        prefix_nibbles: impl Iterator<Item = u8>,
959
5
        branch_nodes: bool,
960
5
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
5
        // Process the iterators at the very beginning and before locking the database, in order
962
5
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
5
        // the database as well.
964
5
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
5
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
5
            .collect::<Vec<_>>();
967
5
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
5
        let key_nibbles = {
969
5
            let mut v = parent_tries_paths_nibbles.clone();
970
5
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
5
            v
972
5
        };
973
5
        let prefix_nibbles = {
974
5
            let mut v = parent_tries_paths_nibbles;
975
5
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
5
            v
977
5
        };
978
5
979
5
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
5
        let mut statement = connection
992
5
            .prepare_cached(
993
5
                r#"
994
5
            WITH RECURSIVE
995
5
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
5
                -- descend the trie by trying to match entries with `:key`.
997
5
                -- At each iteration, `node_hash` is the root where to continue the search,
998
5
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
5
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
5
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
5
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
5
                -- continue was missing from the database, in which case the values of
1003
5
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
5
                -- `node_full_key` is the "best known key".
1005
5
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
5
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
5
                -- is null or empty and that `node_is_branch` is false.
1008
5
                --
1009
5
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
5
                -- the trie has no next key at all. These two situations need to be differentiated
1011
5
                -- in the final SELECT statement.
1012
5
                --
1013
5
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
5
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
5
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
5
                -- result will be after any equal match.
1017
5
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
5
                -- is something like `2 * depth_in_trie(key)`.
1019
5
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
5
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
5
                --
1022
5
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
5
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
5
                -- reason, it is also not possible to automatically pass NULL values
1025
5
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
5
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
5
                        SELECT
1028
5
                            CASE
1029
5
                                WHEN trie_node.hash IS NULL
1030
5
                                    THEN NULL
1031
5
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
5
                                    THEN trie_node.hash
1033
5
                                ELSE
1034
5
                                    NULL
1035
5
                            END,
1036
5
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
5
                            COALESCE(trie_node.partial_key, X''),
1038
5
                            CASE
1039
5
                                WHEN trie_node.partial_key IS NULL
1040
5
                                    THEN NULL
1041
5
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
5
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
5
                                ELSE
1044
5
                                    X''   -- The partial key is strictly inferior to `:key`
1045
5
                            END
1046
5
                        FROM blocks
1047
5
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
5
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
5
                        WHERE blocks.hash = :block_hash
1050
5
1051
5
                    UNION ALL
1052
5
                        SELECT
1053
5
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
5
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
5
                            CASE
1056
5
                                WHEN trie_node_child.child_num IS NULL
1057
5
                                    THEN next_key.node_full_key
1058
5
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
5
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
5
                                ELSE
1061
5
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
5
                            END,
1063
5
                            CASE
1064
5
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
5
                                    THEN NULL    -- Child exists but is missing from database
1066
5
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
5
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
5
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
5
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
5
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
5
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
5
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
5
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
5
                                ELSE
1075
5
                                    X''          -- Shouldn't be reachable.
1076
5
                            END
1077
5
                        FROM next_key
1078
5
1079
5
                        LEFT JOIN trie_node_child
1080
5
                            ON next_key.node_hash = trie_node_child.hash
1081
5
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
5
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
5
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
5
1085
5
                        -- We want to keep only situations where `trie_node_child` is either
1086
5
                        -- equal to the key, or the first child strictly superior to the key. In
1087
5
                        -- order to do that, we try to find another child that is strictly
1088
5
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
5
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
5
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
5
                            ON next_key.node_hash = trie_node_child_before.hash
1092
5
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
5
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
5
1095
5
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
5
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
5
                        LEFT JOIN trie_node AS trie_node_trieref
1098
5
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
5
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
5
1101
5
                        LEFT JOIN trie_node_storage
1102
5
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
5
1104
5
                        WHERE
1105
5
                            -- Don't pull items that have already finished searching.
1106
5
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
5
                            -- See explanation above.
1108
5
                            AND trie_node_child_before.hash IS NULL
1109
5
                            -- Don't generate an item if there's nowhere to go to.
1110
5
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
5
                            -- Stop iterating if the child's partial key is before the searched key.
1112
5
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
5
                ),
1114
5
1115
5
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
5
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
5
                    SELECT
1118
5
                        CASE
1119
5
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
5
                            ELSE key_search_remain IS NULL
1121
5
                        END,
1122
5
                        node_full_key,
1123
5
                        CASE
1124
5
                            WHEN node_hash IS NULL THEN NULL
1125
5
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
5
                            ELSE NULL
1127
5
                        END
1128
5
                    FROM next_key
1129
5
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
5
                )
1131
5
1132
5
            SELECT
1133
5
                COUNT(blocks.hash) >= 1,
1134
5
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
5
                terminal_next_key.output
1136
5
            FROM blocks
1137
5
            LEFT JOIN terminal_next_key
1138
5
            WHERE blocks.hash = :block_hash
1139
5
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
5
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
5
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
5
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
5
                -- figure out.
1144
5
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
5
            LIMIT 1"#,
1146
5
            )
1147
5
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
5
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
5
        let result = statement
1185
5
            .query_row(
1186
5
                rusqlite::named_params! {
1187
5
                    ":block_hash": &block_hash[..],
1188
5
                    ":key": key_nibbles,
1189
5
                    ":prefix": prefix_nibbles,
1190
5
                    ":skip_branches": !branch_nodes
1191
5
                },
1192
5
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
5
                },
1198
5
            )
1199
5
            .optional()
1200
5
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
5
            })
?0
;
1203
1204
5
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
5
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
5
        }
1211
5
1212
5
        if incomplete_storage {
1213
2
            return Err(StorageAccessError::IncompleteStorage);
1214
3
        }
1215
3
1216
3
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
3
        }
1219
1220
3
        Ok(next_key)
1221
5
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj3_EB2E_EB7_
Line
Count
Source
953
1
    pub fn block_storage_next_key(
954
1
        &self,
955
1
        block_hash: &[u8; 32],
956
1
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
1
        key_nibbles: impl Iterator<Item = u8>,
958
1
        prefix_nibbles: impl Iterator<Item = u8>,
959
1
        branch_nodes: bool,
960
1
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
1
        // Process the iterators at the very beginning and before locking the database, in order
962
1
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
1
        // the database as well.
964
1
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
1
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
1
            .collect::<Vec<_>>();
967
1
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
1
        let key_nibbles = {
969
1
            let mut v = parent_tries_paths_nibbles.clone();
970
1
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
1
            v
972
1
        };
973
1
        let prefix_nibbles = {
974
1
            let mut v = parent_tries_paths_nibbles;
975
1
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
1
            v
977
1
        };
978
1
979
1
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
1
        let mut statement = connection
992
1
            .prepare_cached(
993
1
                r#"
994
1
            WITH RECURSIVE
995
1
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
1
                -- descend the trie by trying to match entries with `:key`.
997
1
                -- At each iteration, `node_hash` is the root where to continue the search,
998
1
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
1
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
1
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
1
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
1
                -- continue was missing from the database, in which case the values of
1003
1
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
1
                -- `node_full_key` is the "best known key".
1005
1
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
1
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
1
                -- is null or empty and that `node_is_branch` is false.
1008
1
                --
1009
1
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
1
                -- the trie has no next key at all. These two situations need to be differentiated
1011
1
                -- in the final SELECT statement.
1012
1
                --
1013
1
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
1
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
1
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
1
                -- result will be after any equal match.
1017
1
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
1
                -- is something like `2 * depth_in_trie(key)`.
1019
1
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
1
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
1
                --
1022
1
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
1
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
1
                -- reason, it is also not possible to automatically pass NULL values
1025
1
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
1
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
1
                        SELECT
1028
1
                            CASE
1029
1
                                WHEN trie_node.hash IS NULL
1030
1
                                    THEN NULL
1031
1
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
1
                                    THEN trie_node.hash
1033
1
                                ELSE
1034
1
                                    NULL
1035
1
                            END,
1036
1
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
1
                            COALESCE(trie_node.partial_key, X''),
1038
1
                            CASE
1039
1
                                WHEN trie_node.partial_key IS NULL
1040
1
                                    THEN NULL
1041
1
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
1
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
1
                                ELSE
1044
1
                                    X''   -- The partial key is strictly inferior to `:key`
1045
1
                            END
1046
1
                        FROM blocks
1047
1
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
1
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
1
                        WHERE blocks.hash = :block_hash
1050
1
1051
1
                    UNION ALL
1052
1
                        SELECT
1053
1
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
1
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
1
                            CASE
1056
1
                                WHEN trie_node_child.child_num IS NULL
1057
1
                                    THEN next_key.node_full_key
1058
1
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
1
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
1
                                ELSE
1061
1
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
1
                            END,
1063
1
                            CASE
1064
1
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
1
                                    THEN NULL    -- Child exists but is missing from database
1066
1
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
1
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
1
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
1
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
1
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
1
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
1
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
1
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
1
                                ELSE
1075
1
                                    X''          -- Shouldn't be reachable.
1076
1
                            END
1077
1
                        FROM next_key
1078
1
1079
1
                        LEFT JOIN trie_node_child
1080
1
                            ON next_key.node_hash = trie_node_child.hash
1081
1
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
1
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
1
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
1
1085
1
                        -- We want to keep only situations where `trie_node_child` is either
1086
1
                        -- equal to the key, or the first child strictly superior to the key. In
1087
1
                        -- order to do that, we try to find another child that is strictly
1088
1
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
1
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
1
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
1
                            ON next_key.node_hash = trie_node_child_before.hash
1092
1
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
1
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
1
1095
1
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
1
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
1
                        LEFT JOIN trie_node AS trie_node_trieref
1098
1
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
1
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
1
1101
1
                        LEFT JOIN trie_node_storage
1102
1
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
1
1104
1
                        WHERE
1105
1
                            -- Don't pull items that have already finished searching.
1106
1
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
1
                            -- See explanation above.
1108
1
                            AND trie_node_child_before.hash IS NULL
1109
1
                            -- Don't generate an item if there's nowhere to go to.
1110
1
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
1
                            -- Stop iterating if the child's partial key is before the searched key.
1112
1
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
1
                ),
1114
1
1115
1
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
1
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
1
                    SELECT
1118
1
                        CASE
1119
1
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
1
                            ELSE key_search_remain IS NULL
1121
1
                        END,
1122
1
                        node_full_key,
1123
1
                        CASE
1124
1
                            WHEN node_hash IS NULL THEN NULL
1125
1
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
1
                            ELSE NULL
1127
1
                        END
1128
1
                    FROM next_key
1129
1
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
1
                )
1131
1
1132
1
            SELECT
1133
1
                COUNT(blocks.hash) >= 1,
1134
1
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
1
                terminal_next_key.output
1136
1
            FROM blocks
1137
1
            LEFT JOIN terminal_next_key
1138
1
            WHERE blocks.hash = :block_hash
1139
1
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
1
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
1
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
1
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
1
                -- figure out.
1144
1
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
1
            LIMIT 1"#,
1146
1
            )
1147
1
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
1
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
1
        let result = statement
1185
1
            .query_row(
1186
1
                rusqlite::named_params! {
1187
1
                    ":block_hash": &block_hash[..],
1188
1
                    ":key": key_nibbles,
1189
1
                    ":prefix": prefix_nibbles,
1190
1
                    ":skip_branches": !branch_nodes
1191
1
                },
1192
1
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
1
                },
1198
1
            )
1199
1
            .optional()
1200
1
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
1
            })
?0
;
1203
1204
1
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
1
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
1
        }
1211
1
1212
1
        if incomplete_storage {
1213
0
            return Err(StorageAccessError::IncompleteStorage);
1214
1
        }
1215
1
1216
1
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
1
        }
1219
1220
1
        Ok(next_key)
1221
1
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1C_B1B_EINtNtNtB1K_5array4iter8IntoIterhKj8_EB1B_EB7_
Line
Count
Source
953
2
    pub fn block_storage_next_key(
954
2
        &self,
955
2
        block_hash: &[u8; 32],
956
2
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
2
        key_nibbles: impl Iterator<Item = u8>,
958
2
        prefix_nibbles: impl Iterator<Item = u8>,
959
2
        branch_nodes: bool,
960
2
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
2
        // Process the iterators at the very beginning and before locking the database, in order
962
2
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
2
        // the database as well.
964
2
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
2
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
2
            .collect::<Vec<_>>();
967
2
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
2
        let key_nibbles = {
969
2
            let mut v = parent_tries_paths_nibbles.clone();
970
2
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
2
            v
972
2
        };
973
2
        let prefix_nibbles = {
974
2
            let mut v = parent_tries_paths_nibbles;
975
2
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
2
            v
977
2
        };
978
2
979
2
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
2
        let mut statement = connection
992
2
            .prepare_cached(
993
2
                r#"
994
2
            WITH RECURSIVE
995
2
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
2
                -- descend the trie by trying to match entries with `:key`.
997
2
                -- At each iteration, `node_hash` is the root where to continue the search,
998
2
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
2
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
2
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
2
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
2
                -- continue was missing from the database, in which case the values of
1003
2
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
2
                -- `node_full_key` is the "best known key".
1005
2
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
2
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
2
                -- is null or empty and that `node_is_branch` is false.
1008
2
                --
1009
2
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
2
                -- the trie has no next key at all. These two situations need to be differentiated
1011
2
                -- in the final SELECT statement.
1012
2
                --
1013
2
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
2
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
2
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
2
                -- result will be after any equal match.
1017
2
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
2
                -- is something like `2 * depth_in_trie(key)`.
1019
2
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
2
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
2
                --
1022
2
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
2
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
2
                -- reason, it is also not possible to automatically pass NULL values
1025
2
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
2
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
2
                        SELECT
1028
2
                            CASE
1029
2
                                WHEN trie_node.hash IS NULL
1030
2
                                    THEN NULL
1031
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
2
                                    THEN trie_node.hash
1033
2
                                ELSE
1034
2
                                    NULL
1035
2
                            END,
1036
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
2
                            COALESCE(trie_node.partial_key, X''),
1038
2
                            CASE
1039
2
                                WHEN trie_node.partial_key IS NULL
1040
2
                                    THEN NULL
1041
2
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
2
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
2
                                ELSE
1044
2
                                    X''   -- The partial key is strictly inferior to `:key`
1045
2
                            END
1046
2
                        FROM blocks
1047
2
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
2
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
2
                        WHERE blocks.hash = :block_hash
1050
2
1051
2
                    UNION ALL
1052
2
                        SELECT
1053
2
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
2
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
2
                            CASE
1056
2
                                WHEN trie_node_child.child_num IS NULL
1057
2
                                    THEN next_key.node_full_key
1058
2
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
2
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
2
                                ELSE
1061
2
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
2
                            END,
1063
2
                            CASE
1064
2
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
2
                                    THEN NULL    -- Child exists but is missing from database
1066
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
2
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
2
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
2
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
2
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
2
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
2
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
2
                                ELSE
1075
2
                                    X''          -- Shouldn't be reachable.
1076
2
                            END
1077
2
                        FROM next_key
1078
2
1079
2
                        LEFT JOIN trie_node_child
1080
2
                            ON next_key.node_hash = trie_node_child.hash
1081
2
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
2
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
2
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
2
1085
2
                        -- We want to keep only situations where `trie_node_child` is either
1086
2
                        -- equal to the key, or the first child strictly superior to the key. In
1087
2
                        -- order to do that, we try to find another child that is strictly
1088
2
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
2
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
2
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
2
                            ON next_key.node_hash = trie_node_child_before.hash
1092
2
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
2
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
2
1095
2
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
2
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
2
                        LEFT JOIN trie_node AS trie_node_trieref
1098
2
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
2
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
2
1101
2
                        LEFT JOIN trie_node_storage
1102
2
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
2
1104
2
                        WHERE
1105
2
                            -- Don't pull items that have already finished searching.
1106
2
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
2
                            -- See explanation above.
1108
2
                            AND trie_node_child_before.hash IS NULL
1109
2
                            -- Don't generate an item if there's nowhere to go to.
1110
2
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
2
                            -- Stop iterating if the child's partial key is before the searched key.
1112
2
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
2
                ),
1114
2
1115
2
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
2
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
2
                    SELECT
1118
2
                        CASE
1119
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
2
                            ELSE key_search_remain IS NULL
1121
2
                        END,
1122
2
                        node_full_key,
1123
2
                        CASE
1124
2
                            WHEN node_hash IS NULL THEN NULL
1125
2
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
2
                            ELSE NULL
1127
2
                        END
1128
2
                    FROM next_key
1129
2
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
2
                )
1131
2
1132
2
            SELECT
1133
2
                COUNT(blocks.hash) >= 1,
1134
2
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
2
                terminal_next_key.output
1136
2
            FROM blocks
1137
2
            LEFT JOIN terminal_next_key
1138
2
            WHERE blocks.hash = :block_hash
1139
2
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
2
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
2
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
2
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
2
                -- figure out.
1144
2
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
2
            LIMIT 1"#,
1146
2
            )
1147
2
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
2
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
2
        let result = statement
1185
2
            .query_row(
1186
2
                rusqlite::named_params! {
1187
2
                    ":block_hash": &block_hash[..],
1188
2
                    ":key": key_nibbles,
1189
2
                    ":prefix": prefix_nibbles,
1190
2
                    ":skip_branches": !branch_nodes
1191
2
                },
1192
2
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
2
                },
1198
2
            )
1199
2
            .optional()
1200
2
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
2
            })
?0
;
1203
1204
2
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
2
        if !block_is_known {
1209
0
            return Err(StorageAccessError::UnknownBlock);
1210
2
        }
1211
2
1212
2
        if incomplete_storage {
1213
1
            return Err(StorageAccessError::IncompleteStorage);
1214
1
        }
1215
1
1216
1
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
1
        }
1219
1220
1
        Ok(next_key)
1221
2
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1D_B1C_EINtNtNtB1J_8adapters3map3MapINtCs1qmLyiTSqYF_6either6EitherINtNtNtB7_4trie6nibble14BytesToNibblesINtNtB2K_6copied6CopiedINtNtNtB1L_5slice4iter4IterhEEEIB38_IB3D_INtNvNtB7_4util11as_ref_iter4IterIB38_RShINtNvMs5_NtNtNtB7_8executor2vm11interpreterNtB64_11Interpreter11read_memory12AccessOffsetB5S_EEhEEINtNtB2K_7flatten7FlatMapINtNtB2K_5chain5ChainIB2G_IB7w_IB4C_NtNtB68_20trie_root_calculator14InProgressNodeEIB7V_INtNtB1H_4once4OnceIB38_ANtB3F_6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB9J_EEEINtNtB1L_6option8IntoIterB9D_EENCNvMs3_B8w_NtB8w_5Inner21current_node_full_key0ENcNtIB38_B9D_B9Z_E4Left0EIB9l_Bc0_EEIB5h_Bcq_B9J_EIB5j_B9J_Bcq_EEEENvYhINtNtB1L_7convert4FromB9J_E4fromEIB2G_IB38_IB3D_IB5h_IB38_B5N_B5S_EhEEIB38_B37_IB1D_B9J_EEEBd1_EEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB44_14SyncBackground12author_block0s5_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5D_ECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5e_ECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sd_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5H_EB45_
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1D_B1C_EINtNtNtB1J_8adapters6copied6CopiedINtNtNtB1L_5slice4iter4IterhEEB2F_ECsiUjFBJteJ7x_17smoldot_full_node
Line
Count
Source
953
51
    pub fn block_storage_next_key(
954
51
        &self,
955
51
        block_hash: &[u8; 32],
956
51
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
957
51
        key_nibbles: impl Iterator<Item = u8>,
958
51
        prefix_nibbles: impl Iterator<Item = u8>,
959
51
        branch_nodes: bool,
960
51
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
961
51
        // Process the iterators at the very beginning and before locking the database, in order
962
51
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
963
51
        // the database as well.
964
51
        let parent_tries_paths_nibbles = parent_tries_paths_nibbles
965
51
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
966
51
            .collect::<Vec<_>>();
967
51
        let parent_tries_paths_nibbles_length = parent_tries_paths_nibbles.len();
968
51
        let key_nibbles = {
969
51
            let mut v = parent_tries_paths_nibbles.clone();
970
51
            v.extend(key_nibbles.inspect(|n| assert!(*n < 16)));
971
51
            v
972
51
        };
973
51
        let prefix_nibbles = {
974
51
            let mut v = parent_tries_paths_nibbles;
975
51
            v.extend(prefix_nibbles.inspect(|n| assert!(*n < 16)));
976
51
            v
977
51
        };
978
51
979
51
        let connection = self.database.lock();
980
981
        // Sorry for that extremely complicated SQL statement. While the logic isn't actually very
982
        // complicated, we have to jump through many hoops in order to go around quirks in the
983
        // SQL language.
984
        // If you want to work on this SQL code, there is no miracle: write tests, and if a test
985
        // fails debug the content of `next_key` to find out where the iteration doesn't behave
986
        // as expected.
987
        // TODO: this algorithm relies the fact that leaf nodes always have a storage value, which isn't exactly clear in the schema ; however not relying on this makes it way harder to write
988
        // TODO: trie_root_ref system untested and most likely not working
989
        // TODO: infinite loop if there's a loop in the trie; detect this
990
        // TODO: could also check the prefix while iterating instead of only at the very end, which could maybe save many lookups
991
51
        let mut statement = connection
992
51
            .prepare_cached(
993
51
                r#"
994
51
            WITH RECURSIVE
995
51
                -- We build a temporary table `next_key`, inserting entries one after one as we
996
51
                -- descend the trie by trying to match entries with `:key`.
997
51
                -- At each iteration, `node_hash` is the root where to continue the search,
998
51
                -- `node_is_branch` is true if `node_hash` is a branch node, `node_full_key` is
999
51
                -- the key of `node_hash` (that we build along the way) and serves as the final
1000
51
                -- result, and `key_search_remain` contains the `:key` that remains to be matched.
1001
51
                -- Can also be NULL to indicate that the search ended because the node necessary to
1002
51
                -- continue was missing from the database, in which case the values of
1003
51
                -- `node_hash` and `node_is_branch` have irrelevant values, and the value of
1004
51
                -- `node_full_key` is the "best known key".
1005
51
                -- If `:skip_branches` is false, the search ends when `key_search_remain` is null
1006
51
                -- or empty. If `:skip_branches` is true, the search ends when `key_search_remain`
1007
51
                -- is null or empty and that `node_is_branch` is false.
1008
51
                --
1009
51
                -- `next_key` has zero elements if the block can't be found in the database or if
1010
51
                -- the trie has no next key at all. These two situations need to be differentiated
1011
51
                -- in the final SELECT statement.
1012
51
                --
1013
51
                -- When encountering a node, we follow both the child that exactly matches `:key`
1014
51
                -- and also the first child that is strictly superior to `:key`. This is necessary
1015
51
                -- because `:key` might be equal to something like `ffffffff...`, in which case the
1016
51
                -- result will be after any equal match.
1017
51
                -- This means that the number of entries in `next_key` at the end of the recursion
1018
51
                -- is something like `2 * depth_in_trie(key)`.
1019
51
                -- In order to obtain the final result, we take the entry in `next_key` with the
1020
51
                -- minimal `node_full_key` amongst the ones that have finished the search.
1021
51
                --
1022
51
                -- Note that in the code below we do a lot of `COALESCE(SUBSTR(...), X'')`. This
1023
51
                -- is because, for some reason, `SUBSTR(X'', ...)` always produces `NULL`. For this
1024
51
                -- reason, it is also not possible to automatically pass NULL values
1025
51
                -- through `SUSBTR`, and we have to use CASE/IIFs instead.
1026
51
                next_key(node_hash, node_is_branch, node_full_key, key_search_remain) AS (
1027
51
                        SELECT
1028
51
                            CASE
1029
51
                                WHEN trie_node.hash IS NULL
1030
51
                                    THEN NULL
1031
51
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1032
51
                                    THEN trie_node.hash
1033
51
                                ELSE
1034
51
                                    NULL
1035
51
                            END,
1036
51
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1037
51
                            COALESCE(trie_node.partial_key, X''),
1038
51
                            CASE
1039
51
                                WHEN trie_node.partial_key IS NULL
1040
51
                                    THEN NULL
1041
51
                                WHEN COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') <= trie_node.partial_key
1042
51
                                    THEN COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1043
51
                                ELSE
1044
51
                                    X''   -- The partial key is strictly inferior to `:key`
1045
51
                            END
1046
51
                        FROM blocks
1047
51
                        LEFT JOIN trie_node ON trie_node.hash = blocks.state_trie_root_hash
1048
51
                        LEFT JOIN trie_node_storage ON trie_node_storage.node_hash = trie_node.hash
1049
51
                        WHERE blocks.hash = :block_hash
1050
51
1051
51
                    UNION ALL
1052
51
                        SELECT
1053
51
                            COALESCE(trie_node.hash, trie_node_trieref.hash),
1054
51
                            trie_node_storage.value IS NULL AND trie_node_storage.trie_root_ref IS NULL,
1055
51
                            CASE
1056
51
                                WHEN trie_node_child.child_num IS NULL
1057
51
                                    THEN next_key.node_full_key
1058
51
                                WHEN trie_node.partial_key IS NULL AND trie_node_trieref.partial_key IS NULL
1059
51
                                    THEN CAST(next_key.node_full_key || trie_node_child.child_num AS BLOB)
1060
51
                                ELSE
1061
51
                                    CAST(next_key.node_full_key || trie_node_child.child_num || COALESCE(trie_node.partial_key, trie_node_trieref.partial_key) AS BLOB)
1062
51
                            END,
1063
51
                            CASE
1064
51
                                WHEN trie_node_child.child_num IS NOT NULL AND trie_node.partial_key IS NULL
1065
51
                                    THEN NULL    -- Child exists but is missing from database
1066
51
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND trie_node_trieref.hash IS NULL
1067
51
                                    THEN NULL    -- Trie reference exists but is missing from database
1068
51
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) = trie_node.partial_key
1069
51
                                    THEN SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node.partial_key))    -- Equal match, continue iterating
1070
51
                                WHEN SUBSTR(next_key.key_search_remain, 1, 1) = trie_node_child.child_num AND SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)) < trie_node.partial_key
1071
51
                                    THEN X''     -- Searched key is before the node we are iterating to, thus we cut the search short
1072
51
                                WHEN HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') = trie_node_trieref.partial_key
1073
51
                                    THEN COALESCE(SUBSTR(next_key.key_search_remain, 2 + LENGTH(trie_node_trieref.partial_key)), X'')
1074
51
                                ELSE
1075
51
                                    X''          -- Shouldn't be reachable.
1076
51
                            END
1077
51
                        FROM next_key
1078
51
1079
51
                        LEFT JOIN trie_node_child
1080
51
                            ON next_key.node_hash = trie_node_child.hash
1081
51
                            AND CASE WHEN LENGTH(next_key.key_search_remain) = 0 THEN TRUE
1082
51
                                ELSE SUBSTR(next_key.key_search_remain, 1, 1) <= trie_node_child.child_num END
1083
51
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1084
51
1085
51
                        -- We want to keep only situations where `trie_node_child` is either
1086
51
                        -- equal to the key, or the first child strictly superior to the key. In
1087
51
                        -- order to do that, we try to find another child that is strictly
1088
51
                        -- in-between the key and `trie_node_child`. In the `WHERE` clause at the
1089
51
                        -- bottom, we only keep rows where `trie_node_child_before` is NULL.
1090
51
                        LEFT JOIN trie_node_child AS trie_node_child_before
1091
51
                            ON next_key.node_hash = trie_node_child_before.hash
1092
51
                            AND trie_node_child_before.child_num < trie_node_child.child_num
1093
51
                            AND (next_key.key_search_remain = X'' OR trie_node_child_before.child_num > SUBSTR(next_key.key_search_remain, 1, 1))
1094
51
1095
51
                        LEFT JOIN trie_node_storage AS trie_node_storage_trieref
1096
51
                            ON HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' AND next_key.node_hash = trie_node_storage_trieref.node_hash AND trie_node_storage_trieref.trie_root_ref IS NOT NULL
1097
51
                        LEFT JOIN trie_node AS trie_node_trieref
1098
51
                            ON trie_node_trieref.hash = trie_node_storage_trieref.node_hash
1099
51
                            AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node_trieref.partial_key)), X'') <= trie_node_trieref.partial_key
1100
51
1101
51
                        LEFT JOIN trie_node_storage
1102
51
                            ON trie_node_storage.node_hash = COALESCE(trie_node.hash, trie_node_trieref.hash)
1103
51
1104
51
                        WHERE
1105
51
                            -- Don't pull items that have already finished searching.
1106
51
                            next_key.node_hash IS NOT NULL AND next_key.key_search_remain IS NOT NULL AND (next_key.key_search_remain != X'' OR (next_key.node_is_branch AND :skip_branches))
1107
51
                            -- See explanation above.
1108
51
                            AND trie_node_child_before.hash IS NULL
1109
51
                            -- Don't generate an item if there's nowhere to go to.
1110
51
                            AND (HEX(SUBSTR(next_key.key_search_remain, 1, 1)) = '10' OR trie_node_child.child_num IS NOT NULL)
1111
51
                            -- Stop iterating if the child's partial key is before the searched key.
1112
51
                            AND (trie_node.hash IS NULL OR NOT (COALESCE(SUBSTR(next_key.key_search_remain, 1, 1), X'') = trie_node_child.child_num AND COALESCE(SUBSTR(next_key.key_search_remain, 2, LENGTH(trie_node.partial_key)), X'') > trie_node.partial_key))
1113
51
                ),
1114
51
1115
51
                -- Now keep only the entries of `next_key` which have finished iterating.
1116
51
                terminal_next_key(incomplete_storage, node_full_key, output) AS (
1117
51
                    SELECT
1118
51
                        CASE
1119
51
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') != :prefix THEN FALSE
1120
51
                            ELSE key_search_remain IS NULL
1121
51
                        END,
1122
51
                        node_full_key,
1123
51
                        CASE
1124
51
                            WHEN node_hash IS NULL THEN NULL
1125
51
                            WHEN COALESCE(SUBSTR(node_full_key, 1, LENGTH(:prefix)), X'') = :prefix THEN node_full_key
1126
51
                            ELSE NULL
1127
51
                        END
1128
51
                    FROM next_key
1129
51
                    WHERE key_search_remain IS NULL OR (LENGTH(key_search_remain) = 0 AND (NOT :skip_branches OR NOT node_is_branch))
1130
51
                )
1131
51
1132
51
            SELECT
1133
51
                COUNT(blocks.hash) >= 1,
1134
51
                COALESCE(terminal_next_key.incomplete_storage, FALSE),
1135
51
                terminal_next_key.output
1136
51
            FROM blocks
1137
51
            LEFT JOIN terminal_next_key
1138
51
            WHERE blocks.hash = :block_hash
1139
51
                -- We pick the entry of `terminal_next_key` with the smallest full key. Note that
1140
51
                -- it might seem like a good idea to not using any GROUP BY and instead just do
1141
51
                -- `ORDER BY node_full_key ASC LIMIT 1`, but doing so sometimes leads to SQLite
1142
51
                -- not picking the entry with the smallest full key for a reason I couldn't
1143
51
                -- figure out.
1144
51
                AND (terminal_next_key.node_full_key IS NULL OR terminal_next_key.node_full_key = (SELECT MIN(node_full_key) FROM terminal_next_key))
1145
51
            LIMIT 1"#,
1146
51
            )
1147
51
            .map_err(|err| {
1148
                StorageAccessError::Corrupted(CorruptedError::Internal(
1149
                    InternalError(err),
1150
                ))
1151
51
            })
?0
;
1152
1153
        // In order to debug the SQL query above (for example in case of a failing test),
1154
        // uncomment this block:
1155
        //
1156
        /*println!("{:?}", {
1157
            let mut statement = connection
1158
                    .prepare_cached(
1159
                        r#"
1160
                    WITH RECURSIVE
1161
                        copy-paste the definition of next_key here
1162
1163
                    SELECT * FROM next_key"#).unwrap();
1164
            statement
1165
                .query_map(
1166
                    rusqlite::named_params! {
1167
                        ":block_hash": &block_hash[..],
1168
                        ":key": key_nibbles,
1169
                        //":prefix": prefix_nibbles,
1170
                        ":skip_branches": !branch_nodes
1171
                    },
1172
                    |row| {
1173
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1174
                        let node_is_branch = row.get::<_, Option<i64>>(1)?.map(|n| n != 0);
1175
                        let node_full_key = row.get::<_, Option<Vec<u8>>>(2)?;
1176
                        let search_remain = row.get::<_, Option<Vec<u8>>>(3)?;
1177
                        Ok((node_hash, node_is_branch, node_full_key, search_remain))
1178
                    },
1179
                )
1180
                .unwrap()
1181
                .collect::<Vec<_>>()
1182
        });*/
1183
1184
51
        let result = statement
1185
51
            .query_row(
1186
51
                rusqlite::named_params! {
1187
51
                    ":block_hash": &block_hash[..],
1188
51
                    ":key": key_nibbles,
1189
51
                    ":prefix": prefix_nibbles,
1190
51
                    ":skip_branches": !branch_nodes
1191
51
                },
1192
51
                |row| {
1193
                    let block_is_known = row.get::<_, i64>(0)? != 0;
1194
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1195
                    let next_key = row.get::<_, Option<Vec<u8>>>(2)?;
1196
                    Ok((block_is_known, incomplete_storage, next_key))
1197
51
                },
1198
51
            )
1199
51
            .optional()
1200
51
            .map_err(|err| {
1201
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1202
51
            })
?0
;
1203
1204
51
        let Some((block_is_known, incomplete_storage, mut next_key)) = result else {
1205
0
            return Ok(None);
1206
        };
1207
1208
51
        if !block_is_known {
1209
1
            return Err(StorageAccessError::UnknownBlock);
1210
50
        }
1211
50
1212
50
        if incomplete_storage {
1213
0
            return Err(StorageAccessError::IncompleteStorage);
1214
50
        }
1215
50
1216
50
        if parent_tries_paths_nibbles_length != 0 {
1217
0
            next_key = next_key.map(|nk| nk[parent_tries_paths_nibbles_length..].to_vec());
1218
50
        }
1219
1220
50
        Ok(next_key)
1221
51
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB44_14SyncBackground12author_block0s5_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5D_ECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5e_ECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB44_14SyncBackground12author_block0s5_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5D_ECsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase22block_storage_next_keyINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2B_6option8IntoIterINtB1H_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s6_00EINtNtB2x_6copied6CopiedINtNtNtB2B_5slice4iter4IterhEEB5e_ECsibGXYHQB8Ea_25json_rpc_general_requests
1222
1223
    /// Returns the Merkle value of the trie node in the storage that is the closest descendant
1224
    /// of the provided key.
1225
    ///
1226
    /// `key_nibbles` must be an iterator to the **nibbles** of the key.
1227
    ///
1228
    /// `parent_tries_paths_nibbles` is a list of keys to follow in order to find the root of the
1229
    /// trie into which `key_nibbles` should be searched.
1230
    ///
1231
    /// Returns `None` if `parent_tries_paths_nibbles` didn't lead to any trie, or if there is no
1232
    /// such descendant.
1233
    ///
1234
    /// # Panics
1235
    ///
1236
    /// Panics if any of the values yielded by `parent_tries_paths_nibbles` or `key_nibbles` is
1237
    /// superior or equal to 16.
1238
    ///
1239
1.04M
    pub fn block_storage_closest_descendant_merkle_value(
1240
1.04M
        &self,
1241
1.04M
        block_hash: &[u8; 32],
1242
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
1.04M
        key_nibbles: impl Iterator<Item = u8>,
1244
1.04M
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
1246
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
1.04M
        // the database as well.
1248
1.04M
        let key_vectored = parent_tries_paths_nibbles
1249
1.04M
            .flat_map(|t| 
t.inspect(0
|n|
assert!(*n < 160
)0
).chain(iter::once(0x10))0
)
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB27_8adapters3map3MapINtNtB38_6copied6CopiedINtNtNtB29_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB29_7convert4FromB4j_E4fromEE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj0_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj1_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj2_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj3_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj4_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj5_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj8_EE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB22_B21_EINtNtNtB28_8adapters3map3MapINtNtB39_7flatten7FlatMapIB3x_INtNtNtB2a_5slice4iter4IterNtNtNtB9_8executor20trie_root_calculator14InProgressNodeEINtNtB39_5chain5ChainINtNtB26_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB9_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6w_EEEINtNtB2a_6option8IntoIterB60_EENCNvMs3_B4t_NtB4t_5Inner21current_node_full_key0EINtNvNtB9_4util11as_ref_iter4IterB60_B6w_EIB91_B6w_B60_EENvYhINtNtB2a_7convert4FromB6w_E4fromEE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0B4u_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB29_8adapters3map3MapINtNtB3a_6copied6CopiedINtNtNtB2b_5slice4iter4IterNtNtNtBb_4trie6nibble6NibbleEENvYhINtNtB2b_7convert4FromB4l_E4fromEE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj0_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj1_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj2_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj3_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj4_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj5_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB23_B22_EINtNtNtB2b_5array4iter8IntoIterhKj8_EE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB24_B23_EINtNtNtB2a_8adapters3map3MapINtNtB3b_7flatten7FlatMapIB3z_INtNtNtB2c_5slice4iter4IterNtNtNtBb_8executor20trie_root_calculator14InProgressNodeEINtNtB3b_5chain5ChainINtNtB28_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtBb_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6y_EEEINtNtB2c_6option8IntoIterB62_EENCNvMs3_B4v_NtB4v_5Inner21current_node_full_key0EINtNvNtBb_4util11as_ref_iter4IterB62_B6y_EIB93_B6y_B62_EENvYhINtNtB2c_7convert4FromB6y_E4fromEE00Bb_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4v_14SyncBackground12author_block0s2_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00B4w_
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4v_14SyncBackground12author_block0s2_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4v_14SyncBackground12author_block0s2_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB7_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB32_6option8IntoIterINtB28_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2Y_6copied6CopiedINtNtNtB32_5slice4iter4IterhEEE00CsibGXYHQB8Ea_25json_rpc_general_requests
1250
4.19M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB27_8adapters3map3MapINtNtB38_6copied6CopiedINtNtNtB29_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB29_7convert4FromB4j_E4fromEEs_0B9_
Line
Count
Source
1250
4.19M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj0_EEs_0B9_
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj1_EEs_0B9_
Line
Count
Source
1250
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj2_EEs_0B9_
Line
Count
Source
1250
6
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj3_EEs_0B9_
Line
Count
Source
1250
12
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj4_EEs_0B9_
Line
Count
Source
1250
12
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj5_EEs_0B9_
Line
Count
Source
1250
5
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj8_EEs_0B9_
Line
Count
Source
1250
8
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB22_B21_EINtNtNtB28_8adapters3map3MapINtNtB39_7flatten7FlatMapIB3x_INtNtNtB2a_5slice4iter4IterNtNtNtB9_8executor20trie_root_calculator14InProgressNodeEINtNtB39_5chain5ChainINtNtB26_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB9_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6w_EEEINtNtB2a_6option8IntoIterB60_EENCNvMs3_B4t_NtB4t_5Inner21current_node_full_key0EINtNvNtB9_4util11as_ref_iter4IterB60_B6w_EIB91_B6w_B60_EENvYhINtNtB2a_7convert4FromB6w_E4fromEEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0B4u_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
1251
1.04M
            .collect::<Vec<_>>();
1252
1.04M
1253
1.04M
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
1.04M
        let mut statement = connection
1258
1.04M
            .prepare_cached(
1259
1.04M
                r#"
1260
1.04M
            WITH RECURSIVE
1261
1.04M
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
1.04M
                -- at most one item where `search_remain` is either empty or null. Empty
1263
1.04M
                -- indicates that we have found a match, while null means that the search has
1264
1.04M
                -- been interrupted due to a storage entry not being in the database. If
1265
1.04M
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
1.04M
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
1.04M
                -- or null, then the request key doesn't have any descendant.
1268
1.04M
                closest_descendant(node_hash, search_remain) AS (
1269
1.04M
                    SELECT
1270
1.04M
                            blocks.state_trie_root_hash,
1271
1.04M
                            CASE
1272
1.04M
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
1.04M
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
1.04M
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
1.04M
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
1.04M
                                ELSE
1277
1.04M
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
1.04M
                            END
1279
1.04M
                        FROM blocks
1280
1.04M
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
1.04M
                        WHERE blocks.hash = :block_hash
1282
1.04M
                            AND (
1283
1.04M
                                trie_node.partial_key IS NULL
1284
1.04M
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
1.04M
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
1.04M
                            )
1287
1.04M
1288
1.04M
                    UNION ALL
1289
1.04M
                    SELECT
1290
1.04M
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
1.04M
                            CASE
1292
1.04M
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
1.04M
                                    THEN X''      -- No child matching the key.
1294
1.04M
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
1.04M
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
1.04M
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
1.04M
                                    THEN NULL     -- Descendant node not in trie.
1298
1.04M
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
1.04M
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
1.04M
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
1.04M
                                ELSE
1302
1.04M
                                    X''           -- Unreachable.
1303
1.04M
                            END
1304
1.04M
                        FROM closest_descendant
1305
1.04M
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
1.04M
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
1.04M
                        LEFT JOIN trie_node_storage
1309
1.04M
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
1.04M
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
1.04M
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
1.04M
                        WHERE
1313
1.04M
                            LENGTH(closest_descendant.search_remain) >= 1
1314
1.04M
                            AND (
1315
1.04M
                                trie_node.hash IS NULL
1316
1.04M
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
1.04M
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
1.04M
                            )
1319
1.04M
                )
1320
1.04M
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
1.04M
            FROM blocks
1322
1.04M
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
1.04M
            WHERE blocks.hash = :block_hash
1324
1.04M
            LIMIT 1"#,
1325
1.04M
            )
1326
1.04M
            .map_err(|err| {
1327
0
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
0
                    InternalError(err),
1329
0
                ))
1330
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB27_8adapters3map3MapINtNtB38_6copied6CopiedINtNtNtB29_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB29_7convert4FromB4j_E4fromEEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj0_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj1_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj2_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj3_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj4_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj5_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj8_EEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB22_B21_EINtNtNtB28_8adapters3map3MapINtNtB39_7flatten7FlatMapIB3x_INtNtNtB2a_5slice4iter4IterNtNtNtB9_8executor20trie_root_calculator14InProgressNodeEINtNtB39_5chain5ChainINtNtB26_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB9_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6w_EEEINtNtB2a_6option8IntoIterB60_EENCNvMs3_B4t_NtB4t_5Inner21current_node_full_key0EINtNvNtB9_4util11as_ref_iter4IterB60_B6w_EIB91_B6w_B60_EENvYhINtNtB2a_7convert4FromB6w_E4fromEEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0B4u_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
1.04M
        let (has_block, incomplete_storage, merkle_value) = statement
1360
1.04M
            .query_row(
1361
1.04M
                rusqlite::named_params! {
1362
1.04M
                    ":block_hash": &block_hash[..],
1363
1.04M
                    ":key": key_vectored,
1364
1.04M
                },
1365
1.04M
                |row| {
1366
1.04M
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
1.04M
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
1.04M
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB27_8adapters3map3MapINtNtB38_6copied6CopiedINtNtNtB29_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB29_7convert4FromB4j_E4fromEEs1_0B9_
Line
Count
Source
1365
1.04M
                |row| {
1366
1.04M
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
1.04M
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
1.04M
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
1.04M
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1.04M
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj0_EEs1_0B9_
Line
Count
Source
1365
2
                |row| {
1366
2
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
2
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
2
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
2
                    Ok((has_block, incomplete_storage, merkle_value))
1370
2
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj1_EEs1_0B9_
Line
Count
Source
1365
3
                |row| {
1366
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
3
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
3
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj2_EEs1_0B9_
Line
Count
Source
1365
3
                |row| {
1366
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
3
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
3
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj3_EEs1_0B9_
Line
Count
Source
1365
4
                |row| {
1366
4
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
4
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
4
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
4
                    Ok((has_block, incomplete_storage, merkle_value))
1370
4
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj4_EEs1_0B9_
Line
Count
Source
1365
3
                |row| {
1366
3
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
3
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
3
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
3
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj5_EEs1_0B9_
Line
Count
Source
1365
1
                |row| {
1366
1
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
1
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
1
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
1
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1
                },
_RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj8_EEs1_0B9_
Line
Count
Source
1365
1
                |row| {
1366
1
                    let has_block = row.get::<_, i64>(0)
?0
!= 0;
1367
1
                    let incomplete_storage = row.get::<_, i64>(1)
?0
!= 0;
1368
1
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)
?0
;
1369
1
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1
                },
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB22_B21_EINtNtNtB28_8adapters3map3MapINtNtB39_7flatten7FlatMapIB3x_INtNtNtB2a_5slice4iter4IterNtNtNtB9_8executor20trie_root_calculator14InProgressNodeEINtNtB39_5chain5ChainINtNtB26_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB9_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6w_EEEINtNtB2a_6option8IntoIterB60_EENCNvMs3_B4t_NtB4t_5Inner21current_node_full_key0EINtNvNtB9_4util11as_ref_iter4IterB60_B6w_EIB91_B6w_B60_EENvYhINtNtB2a_7convert4FromB6w_E4fromEEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0B4u_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
1371
1.04M
            )
1372
1.04M
            .map_err(|err| {
1373
0
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
1.04M
            })
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB27_8adapters3map3MapINtNtB38_6copied6CopiedINtNtNtB29_5slice4iter4IterNtNtNtB9_4trie6nibble6NibbleEENvYhINtNtB29_7convert4FromB4j_E4fromEEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj0_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj1_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj2_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj3_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj4_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj5_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB21_B20_EINtNtNtB29_5array4iter8IntoIterhKj8_EEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB22_B21_EINtNtNtB28_8adapters3map3MapINtNtB39_7flatten7FlatMapIB3x_INtNtNtB2a_5slice4iter4IterNtNtNtB9_8executor20trie_root_calculator14InProgressNodeEINtNtB39_5chain5ChainINtNtB26_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB9_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6w_EEEINtNtB2a_6option8IntoIterB60_EENCNvMs3_B4t_NtB4t_5Inner21current_node_full_key0EINtNvNtB9_4util11as_ref_iter4IterB60_B6w_EIB91_B6w_B60_EENvYhINtNtB2a_7convert4FromB6w_E4fromEEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0B4u_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4t_14SyncBackground12author_block0s2_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB30_6option8IntoIterINtB26_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2W_6copied6CopiedINtNtNtB30_5slice4iter4IterhEEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
1375
1376
1.04M
        if !has_block {
1377
1
            return Err(StorageAccessError::UnknownBlock);
1378
1.04M
        }
1379
1.04M
1380
1.04M
        if incomplete_storage {
1381
4
            return Err(StorageAccessError::IncompleteStorage);
1382
1.04M
        }
1383
1.04M
1384
1.04M
        Ok(merkle_value)
1385
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB25_8adapters3map3MapINtNtB36_6copied6CopiedINtNtNtB27_5slice4iter4IterNtNtNtB7_4trie6nibble6NibbleEENvYhINtNtB27_7convert4FromB4h_E4fromEEB7_
Line
Count
Source
1239
1.04M
    pub fn block_storage_closest_descendant_merkle_value(
1240
1.04M
        &self,
1241
1.04M
        block_hash: &[u8; 32],
1242
1.04M
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
1.04M
        key_nibbles: impl Iterator<Item = u8>,
1244
1.04M
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
1.04M
        // Process the iterators at the very beginning and before locking the database, in order
1246
1.04M
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
1.04M
        // the database as well.
1248
1.04M
        let key_vectored = parent_tries_paths_nibbles
1249
1.04M
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
1.04M
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
1.04M
            .collect::<Vec<_>>();
1252
1.04M
1253
1.04M
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
1.04M
        let mut statement = connection
1258
1.04M
            .prepare_cached(
1259
1.04M
                r#"
1260
1.04M
            WITH RECURSIVE
1261
1.04M
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
1.04M
                -- at most one item where `search_remain` is either empty or null. Empty
1263
1.04M
                -- indicates that we have found a match, while null means that the search has
1264
1.04M
                -- been interrupted due to a storage entry not being in the database. If
1265
1.04M
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
1.04M
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
1.04M
                -- or null, then the request key doesn't have any descendant.
1268
1.04M
                closest_descendant(node_hash, search_remain) AS (
1269
1.04M
                    SELECT
1270
1.04M
                            blocks.state_trie_root_hash,
1271
1.04M
                            CASE
1272
1.04M
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
1.04M
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
1.04M
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
1.04M
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
1.04M
                                ELSE
1277
1.04M
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
1.04M
                            END
1279
1.04M
                        FROM blocks
1280
1.04M
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
1.04M
                        WHERE blocks.hash = :block_hash
1282
1.04M
                            AND (
1283
1.04M
                                trie_node.partial_key IS NULL
1284
1.04M
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
1.04M
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
1.04M
                            )
1287
1.04M
1288
1.04M
                    UNION ALL
1289
1.04M
                    SELECT
1290
1.04M
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
1.04M
                            CASE
1292
1.04M
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
1.04M
                                    THEN X''      -- No child matching the key.
1294
1.04M
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
1.04M
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
1.04M
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
1.04M
                                    THEN NULL     -- Descendant node not in trie.
1298
1.04M
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
1.04M
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
1.04M
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
1.04M
                                ELSE
1302
1.04M
                                    X''           -- Unreachable.
1303
1.04M
                            END
1304
1.04M
                        FROM closest_descendant
1305
1.04M
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
1.04M
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
1.04M
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
1.04M
                        LEFT JOIN trie_node_storage
1309
1.04M
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
1.04M
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
1.04M
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
1.04M
                        WHERE
1313
1.04M
                            LENGTH(closest_descendant.search_remain) >= 1
1314
1.04M
                            AND (
1315
1.04M
                                trie_node.hash IS NULL
1316
1.04M
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
1.04M
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
1.04M
                            )
1319
1.04M
                )
1320
1.04M
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
1.04M
            FROM blocks
1322
1.04M
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
1.04M
            WHERE blocks.hash = :block_hash
1324
1.04M
            LIMIT 1"#,
1325
1.04M
            )
1326
1.04M
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
1.04M
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
1.04M
        let (has_block, incomplete_storage, merkle_value) = statement
1360
1.04M
            .query_row(
1361
1.04M
                rusqlite::named_params! {
1362
1.04M
                    ":block_hash": &block_hash[..],
1363
1.04M
                    ":key": key_vectored,
1364
1.04M
                },
1365
1.04M
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1.04M
                },
1371
1.04M
            )
1372
1.04M
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
1.04M
            })
?0
;
1375
1376
1.04M
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
1.04M
        }
1379
1.04M
1380
1.04M
        if incomplete_storage {
1381
0
            return Err(StorageAccessError::IncompleteStorage);
1382
1.04M
        }
1383
1.04M
1384
1.04M
        Ok(merkle_value)
1385
1.04M
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj0_EEB7_
Line
Count
Source
1239
2
    pub fn block_storage_closest_descendant_merkle_value(
1240
2
        &self,
1241
2
        block_hash: &[u8; 32],
1242
2
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
2
        key_nibbles: impl Iterator<Item = u8>,
1244
2
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
2
        // Process the iterators at the very beginning and before locking the database, in order
1246
2
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
2
        // the database as well.
1248
2
        let key_vectored = parent_tries_paths_nibbles
1249
2
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
2
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
2
            .collect::<Vec<_>>();
1252
2
1253
2
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
2
        let mut statement = connection
1258
2
            .prepare_cached(
1259
2
                r#"
1260
2
            WITH RECURSIVE
1261
2
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
2
                -- at most one item where `search_remain` is either empty or null. Empty
1263
2
                -- indicates that we have found a match, while null means that the search has
1264
2
                -- been interrupted due to a storage entry not being in the database. If
1265
2
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
2
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
2
                -- or null, then the request key doesn't have any descendant.
1268
2
                closest_descendant(node_hash, search_remain) AS (
1269
2
                    SELECT
1270
2
                            blocks.state_trie_root_hash,
1271
2
                            CASE
1272
2
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
2
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
2
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
2
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
2
                                ELSE
1277
2
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
2
                            END
1279
2
                        FROM blocks
1280
2
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
2
                        WHERE blocks.hash = :block_hash
1282
2
                            AND (
1283
2
                                trie_node.partial_key IS NULL
1284
2
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
2
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
2
                            )
1287
2
1288
2
                    UNION ALL
1289
2
                    SELECT
1290
2
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
2
                            CASE
1292
2
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
2
                                    THEN X''      -- No child matching the key.
1294
2
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
2
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
2
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
2
                                    THEN NULL     -- Descendant node not in trie.
1298
2
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
2
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
2
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
2
                                ELSE
1302
2
                                    X''           -- Unreachable.
1303
2
                            END
1304
2
                        FROM closest_descendant
1305
2
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
2
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
2
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
2
                        LEFT JOIN trie_node_storage
1309
2
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
2
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
2
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
2
                        WHERE
1313
2
                            LENGTH(closest_descendant.search_remain) >= 1
1314
2
                            AND (
1315
2
                                trie_node.hash IS NULL
1316
2
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
2
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
2
                            )
1319
2
                )
1320
2
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
2
            FROM blocks
1322
2
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
2
            WHERE blocks.hash = :block_hash
1324
2
            LIMIT 1"#,
1325
2
            )
1326
2
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
2
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
2
        let (has_block, incomplete_storage, merkle_value) = statement
1360
2
            .query_row(
1361
2
                rusqlite::named_params! {
1362
2
                    ":block_hash": &block_hash[..],
1363
2
                    ":key": key_vectored,
1364
2
                },
1365
2
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
2
                },
1371
2
            )
1372
2
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
2
            })
?0
;
1375
1376
2
        if !has_block {
1377
1
            return Err(StorageAccessError::UnknownBlock);
1378
1
        }
1379
1
1380
1
        if incomplete_storage {
1381
0
            return Err(StorageAccessError::IncompleteStorage);
1382
1
        }
1383
1
1384
1
        Ok(merkle_value)
1385
2
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj1_EEB7_
Line
Count
Source
1239
3
    pub fn block_storage_closest_descendant_merkle_value(
1240
3
        &self,
1241
3
        block_hash: &[u8; 32],
1242
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
3
        key_nibbles: impl Iterator<Item = u8>,
1244
3
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
3
        // Process the iterators at the very beginning and before locking the database, in order
1246
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
3
        // the database as well.
1248
3
        let key_vectored = parent_tries_paths_nibbles
1249
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
3
            .collect::<Vec<_>>();
1252
3
1253
3
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
3
        let mut statement = connection
1258
3
            .prepare_cached(
1259
3
                r#"
1260
3
            WITH RECURSIVE
1261
3
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
3
                -- at most one item where `search_remain` is either empty or null. Empty
1263
3
                -- indicates that we have found a match, while null means that the search has
1264
3
                -- been interrupted due to a storage entry not being in the database. If
1265
3
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
3
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
3
                -- or null, then the request key doesn't have any descendant.
1268
3
                closest_descendant(node_hash, search_remain) AS (
1269
3
                    SELECT
1270
3
                            blocks.state_trie_root_hash,
1271
3
                            CASE
1272
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
3
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
3
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
3
                                ELSE
1277
3
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
3
                            END
1279
3
                        FROM blocks
1280
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
3
                        WHERE blocks.hash = :block_hash
1282
3
                            AND (
1283
3
                                trie_node.partial_key IS NULL
1284
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
3
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
3
                            )
1287
3
1288
3
                    UNION ALL
1289
3
                    SELECT
1290
3
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
3
                            CASE
1292
3
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
3
                                    THEN X''      -- No child matching the key.
1294
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
3
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
3
                                    THEN NULL     -- Descendant node not in trie.
1298
3
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
3
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
3
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
3
                                ELSE
1302
3
                                    X''           -- Unreachable.
1303
3
                            END
1304
3
                        FROM closest_descendant
1305
3
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
3
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
3
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
3
                        LEFT JOIN trie_node_storage
1309
3
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
3
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
3
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
3
                        WHERE
1313
3
                            LENGTH(closest_descendant.search_remain) >= 1
1314
3
                            AND (
1315
3
                                trie_node.hash IS NULL
1316
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
3
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
3
                            )
1319
3
                )
1320
3
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
3
            FROM blocks
1322
3
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
3
            WHERE blocks.hash = :block_hash
1324
3
            LIMIT 1"#,
1325
3
            )
1326
3
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
3
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
3
        let (has_block, incomplete_storage, merkle_value) = statement
1360
3
            .query_row(
1361
3
                rusqlite::named_params! {
1362
3
                    ":block_hash": &block_hash[..],
1363
3
                    ":key": key_vectored,
1364
3
                },
1365
3
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
1371
3
            )
1372
3
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
3
            })
?0
;
1375
1376
3
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
3
        }
1379
3
1380
3
        if incomplete_storage {
1381
1
            return Err(StorageAccessError::IncompleteStorage);
1382
2
        }
1383
2
1384
2
        Ok(merkle_value)
1385
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj2_EEB7_
Line
Count
Source
1239
3
    pub fn block_storage_closest_descendant_merkle_value(
1240
3
        &self,
1241
3
        block_hash: &[u8; 32],
1242
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
3
        key_nibbles: impl Iterator<Item = u8>,
1244
3
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
3
        // Process the iterators at the very beginning and before locking the database, in order
1246
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
3
        // the database as well.
1248
3
        let key_vectored = parent_tries_paths_nibbles
1249
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
3
            .collect::<Vec<_>>();
1252
3
1253
3
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
3
        let mut statement = connection
1258
3
            .prepare_cached(
1259
3
                r#"
1260
3
            WITH RECURSIVE
1261
3
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
3
                -- at most one item where `search_remain` is either empty or null. Empty
1263
3
                -- indicates that we have found a match, while null means that the search has
1264
3
                -- been interrupted due to a storage entry not being in the database. If
1265
3
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
3
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
3
                -- or null, then the request key doesn't have any descendant.
1268
3
                closest_descendant(node_hash, search_remain) AS (
1269
3
                    SELECT
1270
3
                            blocks.state_trie_root_hash,
1271
3
                            CASE
1272
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
3
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
3
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
3
                                ELSE
1277
3
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
3
                            END
1279
3
                        FROM blocks
1280
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
3
                        WHERE blocks.hash = :block_hash
1282
3
                            AND (
1283
3
                                trie_node.partial_key IS NULL
1284
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
3
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
3
                            )
1287
3
1288
3
                    UNION ALL
1289
3
                    SELECT
1290
3
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
3
                            CASE
1292
3
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
3
                                    THEN X''      -- No child matching the key.
1294
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
3
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
3
                                    THEN NULL     -- Descendant node not in trie.
1298
3
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
3
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
3
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
3
                                ELSE
1302
3
                                    X''           -- Unreachable.
1303
3
                            END
1304
3
                        FROM closest_descendant
1305
3
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
3
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
3
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
3
                        LEFT JOIN trie_node_storage
1309
3
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
3
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
3
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
3
                        WHERE
1313
3
                            LENGTH(closest_descendant.search_remain) >= 1
1314
3
                            AND (
1315
3
                                trie_node.hash IS NULL
1316
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
3
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
3
                            )
1319
3
                )
1320
3
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
3
            FROM blocks
1322
3
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
3
            WHERE blocks.hash = :block_hash
1324
3
            LIMIT 1"#,
1325
3
            )
1326
3
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
3
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
3
        let (has_block, incomplete_storage, merkle_value) = statement
1360
3
            .query_row(
1361
3
                rusqlite::named_params! {
1362
3
                    ":block_hash": &block_hash[..],
1363
3
                    ":key": key_vectored,
1364
3
                },
1365
3
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
1371
3
            )
1372
3
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
3
            })
?0
;
1375
1376
3
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
3
        }
1379
3
1380
3
        if incomplete_storage {
1381
1
            return Err(StorageAccessError::IncompleteStorage);
1382
2
        }
1383
2
1384
2
        Ok(merkle_value)
1385
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj3_EEB7_
Line
Count
Source
1239
4
    pub fn block_storage_closest_descendant_merkle_value(
1240
4
        &self,
1241
4
        block_hash: &[u8; 32],
1242
4
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
4
        key_nibbles: impl Iterator<Item = u8>,
1244
4
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
4
        // Process the iterators at the very beginning and before locking the database, in order
1246
4
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
4
        // the database as well.
1248
4
        let key_vectored = parent_tries_paths_nibbles
1249
4
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
4
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
4
            .collect::<Vec<_>>();
1252
4
1253
4
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
4
        let mut statement = connection
1258
4
            .prepare_cached(
1259
4
                r#"
1260
4
            WITH RECURSIVE
1261
4
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
4
                -- at most one item where `search_remain` is either empty or null. Empty
1263
4
                -- indicates that we have found a match, while null means that the search has
1264
4
                -- been interrupted due to a storage entry not being in the database. If
1265
4
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
4
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
4
                -- or null, then the request key doesn't have any descendant.
1268
4
                closest_descendant(node_hash, search_remain) AS (
1269
4
                    SELECT
1270
4
                            blocks.state_trie_root_hash,
1271
4
                            CASE
1272
4
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
4
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
4
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
4
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
4
                                ELSE
1277
4
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
4
                            END
1279
4
                        FROM blocks
1280
4
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
4
                        WHERE blocks.hash = :block_hash
1282
4
                            AND (
1283
4
                                trie_node.partial_key IS NULL
1284
4
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
4
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
4
                            )
1287
4
1288
4
                    UNION ALL
1289
4
                    SELECT
1290
4
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
4
                            CASE
1292
4
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
4
                                    THEN X''      -- No child matching the key.
1294
4
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
4
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
4
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
4
                                    THEN NULL     -- Descendant node not in trie.
1298
4
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
4
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
4
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
4
                                ELSE
1302
4
                                    X''           -- Unreachable.
1303
4
                            END
1304
4
                        FROM closest_descendant
1305
4
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
4
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
4
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
4
                        LEFT JOIN trie_node_storage
1309
4
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
4
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
4
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
4
                        WHERE
1313
4
                            LENGTH(closest_descendant.search_remain) >= 1
1314
4
                            AND (
1315
4
                                trie_node.hash IS NULL
1316
4
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
4
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
4
                            )
1319
4
                )
1320
4
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
4
            FROM blocks
1322
4
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
4
            WHERE blocks.hash = :block_hash
1324
4
            LIMIT 1"#,
1325
4
            )
1326
4
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
4
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
4
        let (has_block, incomplete_storage, merkle_value) = statement
1360
4
            .query_row(
1361
4
                rusqlite::named_params! {
1362
4
                    ":block_hash": &block_hash[..],
1363
4
                    ":key": key_vectored,
1364
4
                },
1365
4
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
4
                },
1371
4
            )
1372
4
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
4
            })
?0
;
1375
1376
4
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
4
        }
1379
4
1380
4
        if incomplete_storage {
1381
0
            return Err(StorageAccessError::IncompleteStorage);
1382
4
        }
1383
4
1384
4
        Ok(merkle_value)
1385
4
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj4_EEB7_
Line
Count
Source
1239
3
    pub fn block_storage_closest_descendant_merkle_value(
1240
3
        &self,
1241
3
        block_hash: &[u8; 32],
1242
3
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
3
        key_nibbles: impl Iterator<Item = u8>,
1244
3
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
3
        // Process the iterators at the very beginning and before locking the database, in order
1246
3
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
3
        // the database as well.
1248
3
        let key_vectored = parent_tries_paths_nibbles
1249
3
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
3
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
3
            .collect::<Vec<_>>();
1252
3
1253
3
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
3
        let mut statement = connection
1258
3
            .prepare_cached(
1259
3
                r#"
1260
3
            WITH RECURSIVE
1261
3
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
3
                -- at most one item where `search_remain` is either empty or null. Empty
1263
3
                -- indicates that we have found a match, while null means that the search has
1264
3
                -- been interrupted due to a storage entry not being in the database. If
1265
3
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
3
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
3
                -- or null, then the request key doesn't have any descendant.
1268
3
                closest_descendant(node_hash, search_remain) AS (
1269
3
                    SELECT
1270
3
                            blocks.state_trie_root_hash,
1271
3
                            CASE
1272
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
3
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
3
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
3
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
3
                                ELSE
1277
3
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
3
                            END
1279
3
                        FROM blocks
1280
3
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
3
                        WHERE blocks.hash = :block_hash
1282
3
                            AND (
1283
3
                                trie_node.partial_key IS NULL
1284
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
3
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
3
                            )
1287
3
1288
3
                    UNION ALL
1289
3
                    SELECT
1290
3
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
3
                            CASE
1292
3
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
3
                                    THEN X''      -- No child matching the key.
1294
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
3
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
3
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
3
                                    THEN NULL     -- Descendant node not in trie.
1298
3
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
3
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
3
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
3
                                ELSE
1302
3
                                    X''           -- Unreachable.
1303
3
                            END
1304
3
                        FROM closest_descendant
1305
3
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
3
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
3
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
3
                        LEFT JOIN trie_node_storage
1309
3
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
3
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
3
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
3
                        WHERE
1313
3
                            LENGTH(closest_descendant.search_remain) >= 1
1314
3
                            AND (
1315
3
                                trie_node.hash IS NULL
1316
3
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
3
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
3
                            )
1319
3
                )
1320
3
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
3
            FROM blocks
1322
3
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
3
            WHERE blocks.hash = :block_hash
1324
3
            LIMIT 1"#,
1325
3
            )
1326
3
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
3
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
3
        let (has_block, incomplete_storage, merkle_value) = statement
1360
3
            .query_row(
1361
3
                rusqlite::named_params! {
1362
3
                    ":block_hash": &block_hash[..],
1363
3
                    ":key": key_vectored,
1364
3
                },
1365
3
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
3
                },
1371
3
            )
1372
3
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
3
            })
?0
;
1375
1376
3
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
3
        }
1379
3
1380
3
        if incomplete_storage {
1381
1
            return Err(StorageAccessError::IncompleteStorage);
1382
2
        }
1383
2
1384
2
        Ok(merkle_value)
1385
3
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj5_EEB7_
Line
Count
Source
1239
1
    pub fn block_storage_closest_descendant_merkle_value(
1240
1
        &self,
1241
1
        block_hash: &[u8; 32],
1242
1
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
1
        key_nibbles: impl Iterator<Item = u8>,
1244
1
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
1
        // Process the iterators at the very beginning and before locking the database, in order
1246
1
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
1
        // the database as well.
1248
1
        let key_vectored = parent_tries_paths_nibbles
1249
1
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
1
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
1
            .collect::<Vec<_>>();
1252
1
1253
1
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
1
        let mut statement = connection
1258
1
            .prepare_cached(
1259
1
                r#"
1260
1
            WITH RECURSIVE
1261
1
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
1
                -- at most one item where `search_remain` is either empty or null. Empty
1263
1
                -- indicates that we have found a match, while null means that the search has
1264
1
                -- been interrupted due to a storage entry not being in the database. If
1265
1
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
1
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
1
                -- or null, then the request key doesn't have any descendant.
1268
1
                closest_descendant(node_hash, search_remain) AS (
1269
1
                    SELECT
1270
1
                            blocks.state_trie_root_hash,
1271
1
                            CASE
1272
1
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
1
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
1
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
1
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
1
                                ELSE
1277
1
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
1
                            END
1279
1
                        FROM blocks
1280
1
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
1
                        WHERE blocks.hash = :block_hash
1282
1
                            AND (
1283
1
                                trie_node.partial_key IS NULL
1284
1
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
1
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
1
                            )
1287
1
1288
1
                    UNION ALL
1289
1
                    SELECT
1290
1
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
1
                            CASE
1292
1
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
1
                                    THEN X''      -- No child matching the key.
1294
1
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
1
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
1
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
1
                                    THEN NULL     -- Descendant node not in trie.
1298
1
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
1
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
1
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
1
                                ELSE
1302
1
                                    X''           -- Unreachable.
1303
1
                            END
1304
1
                        FROM closest_descendant
1305
1
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
1
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
1
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
1
                        LEFT JOIN trie_node_storage
1309
1
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
1
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
1
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
1
                        WHERE
1313
1
                            LENGTH(closest_descendant.search_remain) >= 1
1314
1
                            AND (
1315
1
                                trie_node.hash IS NULL
1316
1
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
1
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
1
                            )
1319
1
                )
1320
1
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
1
            FROM blocks
1322
1
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
1
            WHERE blocks.hash = :block_hash
1324
1
            LIMIT 1"#,
1325
1
            )
1326
1
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
1
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
1
        let (has_block, incomplete_storage, merkle_value) = statement
1360
1
            .query_row(
1361
1
                rusqlite::named_params! {
1362
1
                    ":block_hash": &block_hash[..],
1363
1
                    ":key": key_vectored,
1364
1
                },
1365
1
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1
                },
1371
1
            )
1372
1
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
1
            })
?0
;
1375
1376
1
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
1
        }
1379
1
1380
1
        if incomplete_storage {
1381
1
            return Err(StorageAccessError::IncompleteStorage);
1382
0
        }
1383
0
1384
0
        Ok(merkle_value)
1385
1
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB1Z_B1Y_EINtNtNtB27_5array4iter8IntoIterhKj8_EEB7_
Line
Count
Source
1239
1
    pub fn block_storage_closest_descendant_merkle_value(
1240
1
        &self,
1241
1
        block_hash: &[u8; 32],
1242
1
        parent_tries_paths_nibbles: impl Iterator<Item = impl Iterator<Item = u8>>,
1243
1
        key_nibbles: impl Iterator<Item = u8>,
1244
1
    ) -> Result<Option<Vec<u8>>, StorageAccessError> {
1245
1
        // Process the iterators at the very beginning and before locking the database, in order
1246
1
        // to avoid a deadlock in case the `next()` function of one of the iterators accesses
1247
1
        // the database as well.
1248
1
        let key_vectored = parent_tries_paths_nibbles
1249
1
            .flat_map(|t| t.inspect(|n| assert!(*n < 16)).chain(iter::once(0x10)))
1250
1
            .chain(key_nibbles.inspect(|n| assert!(*n < 16)))
1251
1
            .collect::<Vec<_>>();
1252
1
1253
1
        let connection = self.database.lock();
1254
1255
        // TODO: trie_root_ref system untested
1256
        // TODO: infinite loop if there's a loop in the trie; detect this
1257
1
        let mut statement = connection
1258
1
            .prepare_cached(
1259
1
                r#"
1260
1
            WITH RECURSIVE
1261
1
                -- At the end of the recursive statement, `closest_descendant` must always contain
1262
1
                -- at most one item where `search_remain` is either empty or null. Empty
1263
1
                -- indicates that we have found a match, while null means that the search has
1264
1
                -- been interrupted due to a storage entry not being in the database. If
1265
1
                -- `search_remain` is null, then `node_hash` is irrelevant.
1266
1
                -- If `closest_descendant` doesn't have any entry where `search_remain` is empty
1267
1
                -- or null, then the request key doesn't have any descendant.
1268
1
                closest_descendant(node_hash, search_remain) AS (
1269
1
                    SELECT
1270
1
                            blocks.state_trie_root_hash,
1271
1
                            CASE
1272
1
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) = 0
1273
1
                                    THEN X''   -- Trie root node isn't in database, but since key is empty we have a match anyway
1274
1
                                WHEN trie_node.partial_key IS NULL AND LENGTH(:key) != 0
1275
1
                                    THEN NULL  -- Trie root node isn't in database and we can't iterate further
1276
1
                                ELSE
1277
1
                                    COALESCE(SUBSTR(:key, 1 + LENGTH(trie_node.partial_key)), X'')
1278
1
                            END
1279
1
                        FROM blocks
1280
1
                        LEFT JOIN trie_node ON blocks.state_trie_root_hash = trie_node.hash
1281
1
                        WHERE blocks.hash = :block_hash
1282
1
                            AND (
1283
1
                                trie_node.partial_key IS NULL
1284
1
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(:key)), X'') = :key
1285
1
                                OR COALESCE(SUBSTR(:key, 1, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1286
1
                            )
1287
1
1288
1
                    UNION ALL
1289
1
                    SELECT
1290
1
                            COALESCE(trie_node_child.child_hash, trie_node_storage.trie_root_ref),
1291
1
                            CASE
1292
1
                                WHEN trie_node_child.child_hash IS NULL AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) != '10'
1293
1
                                    THEN X''      -- No child matching the key.
1294
1
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL AND LENGTH(closest_descendant.search_remain) = 1
1295
1
                                    THEN X''      -- Descendant node not in trie but we know that it's the result.
1296
1
                                WHEN trie_node_child.child_hash IS NOT NULL AND trie_node.hash IS NULL
1297
1
                                    THEN NULL     -- Descendant node not in trie.
1298
1
                                WHEN COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1299
1
                                        OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1300
1
                                    THEN SUBSTR(closest_descendant.search_remain, 2 + LENGTH(trie_node.partial_key))
1301
1
                                ELSE
1302
1
                                    X''           -- Unreachable.
1303
1
                            END
1304
1
                        FROM closest_descendant
1305
1
                        LEFT JOIN trie_node_child ON closest_descendant.node_hash = trie_node_child.hash
1306
1
                            AND SUBSTR(closest_descendant.search_remain, 1, 1) = trie_node_child.child_num
1307
1
                        LEFT JOIN trie_node ON trie_node.hash = trie_node_child.child_hash
1308
1
                        LEFT JOIN trie_node_storage
1309
1
                            ON closest_descendant.node_hash = trie_node_storage.node_hash
1310
1
                            AND HEX(SUBSTR(closest_descendant.search_remain, 1, 1)) = '10'
1311
1
                            AND trie_node_storage.trie_root_ref IS NOT NULL
1312
1
                        WHERE
1313
1
                            LENGTH(closest_descendant.search_remain) >= 1
1314
1
                            AND (
1315
1
                                trie_node.hash IS NULL
1316
1
                                OR COALESCE(SUBSTR(trie_node.partial_key, 1, LENGTH(closest_descendant.search_remain) - 1), X'') = COALESCE(SUBSTR(closest_descendant.search_remain, 2), X'')
1317
1
                                OR COALESCE(SUBSTR(closest_descendant.search_remain, 2, LENGTH(trie_node.partial_key)), X'') = trie_node.partial_key
1318
1
                            )
1319
1
                )
1320
1
            SELECT COUNT(blocks.hash) >= 1, closest_descendant.node_hash IS NOT NULL AND closest_descendant.search_remain IS NULL, closest_descendant.node_hash
1321
1
            FROM blocks
1322
1
            LEFT JOIN closest_descendant ON LENGTH(closest_descendant.search_remain) = 0 OR closest_descendant.search_remain IS NULL
1323
1
            WHERE blocks.hash = :block_hash
1324
1
            LIMIT 1"#,
1325
1
            )
1326
1
            .map_err(|err| {
1327
                StorageAccessError::Corrupted(CorruptedError::Internal(
1328
                    InternalError(err),
1329
                ))
1330
1
            })
?0
;
1331
1332
        // In order to debug the SQL query above (for example in case of a failing test),
1333
        // uncomment this block:
1334
        //
1335
        /*println!("{:?}", {
1336
            let mut statement = connection
1337
                    .prepare_cached(
1338
                        r#"
1339
                    WITH RECURSIVE
1340
                        copy-paste the definition of closest_descendant here
1341
1342
                    SELECT * FROM closest_descendant"#).unwrap();
1343
            statement
1344
                .query_map(
1345
                    rusqlite::named_params! {
1346
                        ":block_hash": &block_hash[..],
1347
                        ":key": key_vectored,
1348
                    },
1349
                    |row| {
1350
                        let node_hash = row.get::<_, Option<Vec<u8>>>(0)?.map(hex::encode);
1351
                        let search_remain = row.get::<_, Option<Vec<u8>>>(1)?;
1352
                        Ok((node_hash, search_remain))
1353
                    },
1354
                )
1355
                .unwrap()
1356
                .collect::<Vec<_>>()
1357
        });*/
1358
1359
1
        let (has_block, incomplete_storage, merkle_value) = statement
1360
1
            .query_row(
1361
1
                rusqlite::named_params! {
1362
1
                    ":block_hash": &block_hash[..],
1363
1
                    ":key": key_vectored,
1364
1
                },
1365
1
                |row| {
1366
                    let has_block = row.get::<_, i64>(0)? != 0;
1367
                    let incomplete_storage = row.get::<_, i64>(1)? != 0;
1368
                    let merkle_value = row.get::<_, Option<Vec<u8>>>(2)?;
1369
                    Ok((has_block, incomplete_storage, merkle_value))
1370
1
                },
1371
1
            )
1372
1
            .map_err(|err| {
1373
                StorageAccessError::Corrupted(CorruptedError::Internal(InternalError(err)))
1374
1
            })
?0
;
1375
1376
1
        if !has_block {
1377
0
            return Err(StorageAccessError::UnknownBlock);
1378
1
        }
1379
1
1380
1
        if incomplete_storage {
1381
0
            return Err(StorageAccessError::IncompleteStorage);
1382
1
        }
1383
1
1384
1
        Ok(merkle_value)
1385
1
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyhEIB20_B1Z_EINtNtNtB26_8adapters3map3MapINtNtB37_7flatten7FlatMapIB3v_INtNtNtB28_5slice4iter4IterNtNtNtB7_8executor20trie_root_calculator14InProgressNodeEINtNtB37_5chain5ChainINtNtB24_4once4OnceINtCs1qmLyiTSqYF_6either6EitherANtNtNtB7_4trie6nibble6Nibblej1_RINtNtCsdZExvAaxgia_5alloc3vec3VecB6u_EEEINtNtB28_6option8IntoIterB5Y_EENCNvMs3_B4r_NtB4r_5Inner21current_node_full_key0EINtNvNtB7_4util11as_ref_iter4IterB5Y_B6u_EIB8Z_B6u_B5Y_EENvYhINtNtB28_7convert4FromB6u_E4fromEEB7_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4r_14SyncBackground12author_block0s2_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvNtNtCsiUjFBJteJ7x_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0sa_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEEB4s_
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4r_14SyncBackground12author_block0s2_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB4r_14SyncBackground12author_block0s2_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase45block_storage_closest_descendant_merkle_valueINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhEINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtB2Y_6option8IntoIterINtB24_3VechEENCNCNCNvNtCsiUjFBJteJ7x_17smoldot_full_node17consensus_service12runtime_call0s3_00EINtNtB2U_6copied6CopiedINtNtNtB2Y_5slice4iter4IterhEEECsibGXYHQB8Ea_25json_rpc_general_requests
1386
1387
    /// Inserts a block in the database and sets it as the finalized block.
1388
    ///
1389
    /// The parent of the block doesn't need to be present in the database.
1390
    ///
1391
    /// If the block is already in the database, it is replaced by the one provided.
1392
1.04k
    pub fn reset<'a>(
1393
1.04k
        &self,
1394
1.04k
        finalized_block_header: &[u8],
1395
1.04k
        finalized_block_body: impl ExactSizeIterator<Item = &'a [u8]>,
1396
1.04k
        finalized_block_justification: Option<Vec<u8>>,
1397
1.04k
    ) -> Result<(), CorruptedError> {
1398
1.04k
        // Start a transaction to insert everything in one go.
1399
1.04k
        let mut database = self.database.lock();
1400
1.04k
        let transaction = database
1401
1.04k
            .transaction()
1402
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpE0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EE0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EE0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEE0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EE0CsibGXYHQB8Ea_25json_rpc_general_requests
1403
1404
        // Temporarily disable foreign key checks in order to make the initial insertion easier,
1405
        // as we don't have to make sure that trie nodes are sorted.
1406
        // Note that this is immediately disabled again when we `COMMIT`.
1407
1.04k
        transaction
1408
1.04k
            .execute("PRAGMA defer_foreign_keys = ON", ())
1409
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs_0CsibGXYHQB8Ea_25json_rpc_general_requests
1410
1411
1.04k
        let finalized_block_hash = header::hash_from_scale_encoded_header(finalized_block_header);
1412
1.04k
        // TODO: this module shouldn't decode blocks
1413
1.04k
        let decoded = header::decode(finalized_block_header, self.block_number_bytes).unwrap();
1414
1.04k
1415
1.04k
        transaction
1416
1.04k
            .prepare_cached(
1417
1.04k
                "INSERT OR REPLACE INTO blocks(hash, parent_hash, state_trie_root_hash, number, header, is_best_chain, justification) VALUES(?, ?, ?, ?, ?, TRUE, ?)",
1418
1.04k
            )
1419
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs0_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs0_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs0_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs0_0CsibGXYHQB8Ea_25json_rpc_general_requests
1420
            .execute((
1421
1.04k
                &finalized_block_hash[..],
1422
1.04k
                if decoded.number != 0 {
1423
0
                    Some(&decoded.parent_hash[..])
1424
1.04k
                } else { None },
1425
1.04k
                &decoded.state_root[..],
1426
1.04k
                i64::try_from(decoded.number).unwrap(),
1427
1.04k
                finalized_block_header,
1428
1.04k
                finalized_block_justification.as_deref(),
1429
1.04k
            ))
1430
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs1_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs1_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs1_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs1_0CsibGXYHQB8Ea_25json_rpc_general_requests
1431
1432
1.04k
        transaction
1433
1.04k
            .execute(
1434
1.04k
                "DELETE FROM blocks_body WHERE hash = ?",
1435
1.04k
                (&finalized_block_hash[..],),
1436
1.04k
            )
1437
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs2_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs2_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs2_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs2_0CsibGXYHQB8Ea_25json_rpc_general_requests
1438
1439
        {
1440
1.04k
            let mut statement = transaction
1441
1.04k
                .prepare_cached(
1442
1.04k
                    "INSERT OR IGNORE INTO blocks_body(hash, idx, extrinsic) VALUES(?, ?, ?)",
1443
1.04k
                )
1444
1.04k
                .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs3_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs3_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs3_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs3_0CsibGXYHQB8Ea_25json_rpc_general_requests
1445
1.04k
            for (
index, item0
) in finalized_block_body.enumerate() {
1446
0
                statement
1447
0
                    .execute((
1448
0
                        &finalized_block_hash[..],
1449
0
                        i64::try_from(index).unwrap(),
1450
0
                        item,
1451
0
                    ))
1452
0
                    .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs4_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs4_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs4_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs4_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs4_0CsibGXYHQB8Ea_25json_rpc_general_requests
1453
            }
1454
        }
1455
1456
1.04k
        meta_set_blob(&transaction, "best", &finalized_block_hash[..])
?0
;
1457
1.04k
        meta_set_number(&transaction, "finalized", decoded.number)
?0
;
1458
1459
1.04k
        transaction
1460
1.04k
            .commit()
1461
1.04k
            .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs5_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetpEs5_0B9_
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs5_0CsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs5_0CscDgN54JpMGG_6author
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEs5_0CsibGXYHQB8Ea_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1v_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3m_14SyncBackground14process_blocks0s_00EEs5_0CsibGXYHQB8Ea_25json_rpc_general_requests
1462
1463
1.04k
        Ok(())
1464
1.04k
    }
_RINvMNtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEEB7_
Line
Count
Source
1392
1.02k
    pub fn reset<'a>(
1393
1.02k
        &self,
1394
1.02k
        finalized_block_header: &[u8],
1395
1.02k
        finalized_block_body: impl ExactSizeIterator<Item = &'a [u8]>,
1396
1.02k
        finalized_block_justification: Option<Vec<u8>>,
1397
1.02k
    ) -> Result<(), CorruptedError> {
1398
1.02k
        // Start a transaction to insert everything in one go.
1399
1.02k
        let mut database = self.database.lock();
1400
1.02k
        let transaction = database
1401
1.02k
            .transaction()
1402
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1403
1404
        // Temporarily disable foreign key checks in order to make the initial insertion easier,
1405
        // as we don't have to make sure that trie nodes are sorted.
1406
        // Note that this is immediately disabled again when we `COMMIT`.
1407
1.02k
        transaction
1408
1.02k
            .execute("PRAGMA defer_foreign_keys = ON", ())
1409
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1410
1411
1.02k
        let finalized_block_hash = header::hash_from_scale_encoded_header(finalized_block_header);
1412
1.02k
        // TODO: this module shouldn't decode blocks
1413
1.02k
        let decoded = header::decode(finalized_block_header, self.block_number_bytes).unwrap();
1414
1.02k
1415
1.02k
        transaction
1416
1.02k
            .prepare_cached(
1417
1.02k
                "INSERT OR REPLACE INTO blocks(hash, parent_hash, state_trie_root_hash, number, header, is_best_chain, justification) VALUES(?, ?, ?, ?, ?, TRUE, ?)",
1418
1.02k
            )
1419
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1420
            .execute((
1421
1.02k
                &finalized_block_hash[..],
1422
1.02k
                if decoded.number != 0 {
1423
0
                    Some(&decoded.parent_hash[..])
1424
1.02k
                } else { None },
1425
1.02k
                &decoded.state_root[..],
1426
1.02k
                i64::try_from(decoded.number).unwrap(),
1427
1.02k
                finalized_block_header,
1428
1.02k
                finalized_block_justification.as_deref(),
1429
1.02k
            ))
1430
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1431
1432
1.02k
        transaction
1433
1.02k
            .execute(
1434
1.02k
                "DELETE FROM blocks_body WHERE hash = ?",
1435
1.02k
                (&finalized_block_hash[..],),
1436
1.02k
            )
1437
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1438
1439
        {
1440
1.02k
            let mut statement = transaction
1441
1.02k
                .prepare_cached(
1442
1.02k
                    "INSERT OR IGNORE INTO blocks_body(hash, idx, extrinsic) VALUES(?, ?, ?)",
1443
1.02k
                )
1444
1.02k
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1445
1.02k
            for (
index, item0
) in finalized_block_body.enumerate() {
1446
0
                statement
1447
0
                    .execute((
1448
0
                        &finalized_block_hash[..],
1449
0
                        i64::try_from(index).unwrap(),
1450
0
                        item,
1451
0
                    ))
1452
0
                    .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
1453
            }
1454
        }
1455
1456
1.02k
        meta_set_blob(&transaction, "best", &finalized_block_hash[..])
?0
;
1457
1.02k
        meta_set_number(&transaction, "finalized", decoded.number)
?0
;
1458
1459
1.02k
        transaction
1460
1.02k
            .commit()
1461
1.02k
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1462
1463
1.02k
        Ok(())
1464
1.02k
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetpEB7_
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEECsiLzmwikkc22_14json_rpc_basic
Line
Count
Source
1392
2
    pub fn reset<'a>(
1393
2
        &self,
1394
2
        finalized_block_header: &[u8],
1395
2
        finalized_block_body: impl ExactSizeIterator<Item = &'a [u8]>,
1396
2
        finalized_block_justification: Option<Vec<u8>>,
1397
2
    ) -> Result<(), CorruptedError> {
1398
2
        // Start a transaction to insert everything in one go.
1399
2
        let mut database = self.database.lock();
1400
2
        let transaction = database
1401
2
            .transaction()
1402
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1403
1404
        // Temporarily disable foreign key checks in order to make the initial insertion easier,
1405
        // as we don't have to make sure that trie nodes are sorted.
1406
        // Note that this is immediately disabled again when we `COMMIT`.
1407
2
        transaction
1408
2
            .execute("PRAGMA defer_foreign_keys = ON", ())
1409
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1410
1411
2
        let finalized_block_hash = header::hash_from_scale_encoded_header(finalized_block_header);
1412
2
        // TODO: this module shouldn't decode blocks
1413
2
        let decoded = header::decode(finalized_block_header, self.block_number_bytes).unwrap();
1414
2
1415
2
        transaction
1416
2
            .prepare_cached(
1417
2
                "INSERT OR REPLACE INTO blocks(hash, parent_hash, state_trie_root_hash, number, header, is_best_chain, justification) VALUES(?, ?, ?, ?, ?, TRUE, ?)",
1418
2
            )
1419
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1420
            .execute((
1421
2
                &finalized_block_hash[..],
1422
2
                if decoded.number != 0 {
1423
0
                    Some(&decoded.parent_hash[..])
1424
2
                } else { None },
1425
2
                &decoded.state_root[..],
1426
2
                i64::try_from(decoded.number).unwrap(),
1427
2
                finalized_block_header,
1428
2
                finalized_block_justification.as_deref(),
1429
2
            ))
1430
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1431
1432
2
        transaction
1433
2
            .execute(
1434
2
                "DELETE FROM blocks_body WHERE hash = ?",
1435
2
                (&finalized_block_hash[..],),
1436
2
            )
1437
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1438
1439
        {
1440
2
            let mut statement = transaction
1441
2
                .prepare_cached(
1442
2
                    "INSERT OR IGNORE INTO blocks_body(hash, idx, extrinsic) VALUES(?, ?, ?)",
1443
2
                )
1444
2
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1445
2
            for (
index, item0
) in finalized_block_body.enumerate() {
1446
0
                statement
1447
0
                    .execute((
1448
0
                        &finalized_block_hash[..],
1449
0
                        i64::try_from(index).unwrap(),
1450
0
                        item,
1451
0
                    ))
1452
0
                    .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
1453
            }
1454
        }
1455
1456
2
        meta_set_blob(&transaction, "best", &finalized_block_hash[..])
?0
;
1457
2
        meta_set_number(&transaction, "finalized", decoded.number)
?0
;
1458
1459
2
        transaction
1460
2
            .commit()
1461
2
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1462
1463
2
        Ok(())
1464
2
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1t_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3k_14SyncBackground14process_blocks0s_00EECsiLzmwikkc22_14json_rpc_basic
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEECscDgN54JpMGG_6author
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1t_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3k_14SyncBackground14process_blocks0s_00EECscDgN54JpMGG_6author
_RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyRShEECsibGXYHQB8Ea_25json_rpc_general_requests
Line
Count
Source
1392
19
    pub fn reset<'a>(
1393
19
        &self,
1394
19
        finalized_block_header: &[u8],
1395
19
        finalized_block_body: impl ExactSizeIterator<Item = &'a [u8]>,
1396
19
        finalized_block_justification: Option<Vec<u8>>,
1397
19
    ) -> Result<(), CorruptedError> {
1398
19
        // Start a transaction to insert everything in one go.
1399
19
        let mut database = self.database.lock();
1400
19
        let transaction = database
1401
19
            .transaction()
1402
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1403
1404
        // Temporarily disable foreign key checks in order to make the initial insertion easier,
1405
        // as we don't have to make sure that trie nodes are sorted.
1406
        // Note that this is immediately disabled again when we `COMMIT`.
1407
19
        transaction
1408
19
            .execute("PRAGMA defer_foreign_keys = ON", ())
1409
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1410
1411
19
        let finalized_block_hash = header::hash_from_scale_encoded_header(finalized_block_header);
1412
19
        // TODO: this module shouldn't decode blocks
1413
19
        let decoded = header::decode(finalized_block_header, self.block_number_bytes).unwrap();
1414
19
1415
19
        transaction
1416
19
            .prepare_cached(
1417
19
                "INSERT OR REPLACE INTO blocks(hash, parent_hash, state_trie_root_hash, number, header, is_best_chain, justification) VALUES(?, ?, ?, ?, ?, TRUE, ?)",
1418
19
            )
1419
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1420
            .execute((
1421
19
                &finalized_block_hash[..],
1422
19
                if decoded.number != 0 {
1423
0
                    Some(&decoded.parent_hash[..])
1424
19
                } else { None },
1425
19
                &decoded.state_root[..],
1426
19
                i64::try_from(decoded.number).unwrap(),
1427
19
                finalized_block_header,
1428
19
                finalized_block_justification.as_deref(),
1429
19
            ))
1430
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1431
1432
19
        transaction
1433
19
            .execute(
1434
19
                "DELETE FROM blocks_body WHERE hash = ?",
1435
19
                (&finalized_block_hash[..],),
1436
19
            )
1437
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1438
1439
        {
1440
19
            let mut statement = transaction
1441
19
                .prepare_cached(
1442
19
                    "INSERT OR IGNORE INTO blocks_body(hash, idx, extrinsic) VALUES(?, ?, ?)",
1443
19
                )
1444
19
                .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1445
19
            for (
index, item0
) in finalized_block_body.enumerate() {
1446
0
                statement
1447
0
                    .execute((
1448
0
                        &finalized_block_hash[..],
1449
0
                        i64::try_from(index).unwrap(),
1450
0
                        item,
1451
0
                    ))
1452
0
                    .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
1453
            }
1454
        }
1455
1456
19
        meta_set_blob(&transaction, "best", &finalized_block_hash[..])
?0
;
1457
19
        meta_set_number(&transaction, "finalized", decoded.number)
?0
;
1458
1459
19
        transaction
1460
19
            .commit()
1461
19
            .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1462
1463
19
        Ok(())
1464
19
    }
Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB3_18SqliteFullDatabase5resetINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtB1t_5slice4iter4IterINtNtCsdZExvAaxgia_5alloc3vec3VechEENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB3k_14SyncBackground14process_blocks0s_00EECsibGXYHQB8Ea_25json_rpc_general_requests
1465
}
1466
1467
impl fmt::Debug for SqliteFullDatabase {
1468
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1469
0
        f.debug_tuple("SqliteFullDatabase").finish()
1470
0
    }
Unexecuted instantiation: _RNvXs_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabaseNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB4_18SqliteFullDatabaseNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt
1471
}
1472
1473
impl Drop for SqliteFullDatabase {
1474
1.02k
    fn drop(&mut self) {
1475
1.02k
        if !std::thread::panicking() {
1476
1.02k
            // The SQLite documentation recommends running `PRAGMA optimize` when the database
1477
1.02k
            // closes.
1478
1.02k
            // TODO: it is also recommended to do this every 2 hours
1479
1.02k
            let _ = self.database.get_mut().execute("PRAGMA optimize", ());
1480
1.02k
        }
0
1481
1.02k
    }
_RNvXs0_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabaseNtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4drop
Line
Count
Source
1474
1.02k
    fn drop(&mut self) {
1475
1.02k
        if !std::thread::panicking() {
1476
1.02k
            // The SQLite documentation recommends running `PRAGMA optimize` when the database
1477
1.02k
            // closes.
1478
1.02k
            // TODO: it is also recommended to do this every 2 hours
1479
1.02k
            let _ = self.database.get_mut().execute("PRAGMA optimize", ());
1480
1.02k
        }
0
1481
1.02k
    }
Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18SqliteFullDatabaseNtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4drop
1482
}
1483
1484
/// See [`SqliteFullDatabase::finalized_and_above_missing_trie_nodes_unordered`].
1485
#[derive(Debug)]
1486
pub struct MissingTrieNode {
1487
    /// Blocks the trie node is known to belong to.
1488
    ///
1489
    /// Guaranteed to never be empty.
1490
    ///
1491
    /// Only contains blocks whose number is superior or equal to the latest finalized block
1492
    /// number.
1493
    pub blocks: Vec<MissingTrieNodeBlock>,
1494
    /// Hash of the missing trie node.
1495
    pub trie_node_hash: [u8; 32],
1496
}
1497
1498
/// See [`MissingTrieNode::blocks`].
1499
#[derive(Debug)]
1500
pub struct MissingTrieNodeBlock {
1501
    /// Hash of the block.
1502
    pub hash: [u8; 32],
1503
    /// Height of the block.
1504
    pub number: u64,
1505
    /// Path of the parent tries leading to the trie node.
1506
    pub parent_tries_paths_nibbles: Vec<Vec<u8>>,
1507
    /// Nibbles that compose the key of the trie node.
1508
    pub trie_node_key_nibbles: Vec<u8>,
1509
}
1510
1511
pub struct InsertTrieNode<'a> {
1512
    pub merkle_value: Cow<'a, [u8]>,
1513
    pub partial_key_nibbles: Cow<'a, [u8]>,
1514
    pub children_merkle_values: [Option<Cow<'a, [u8]>>; 16],
1515
    pub storage_value: InsertTrieNodeStorageValue<'a>,
1516
}
1517
1518
pub enum InsertTrieNodeStorageValue<'a> {
1519
    NoValue,
1520
    Value {
1521
        value: Cow<'a, [u8]>,
1522
        /// If `true`, the value is equal to the Merkle value of the root of another trie.
1523
        references_merkle_value: bool,
1524
    },
1525
}
1526
1527
/// Error while calling [`SqliteFullDatabase::insert`].
1528
0
#[derive(Debug, derive_more::Display, derive_more::From)]
Unexecuted instantiation: _RNvXs4_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_11InsertErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs4_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_11InsertErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
1529
pub enum InsertError {
1530
    /// Error accessing the database.
1531
    #[display(fmt = "{_0}")]
1532
    Corrupted(CorruptedError),
1533
    /// Block was already in the database.
1534
    Duplicate,
1535
    /// Error when decoding the header to import.
1536
    #[display(fmt = "Failed to decode header: {_0}")]
1537
    BadHeader(header::Error),
1538
    /// Parent of the block to insert isn't in the database.
1539
    MissingParent,
1540
    /// The new best block would be outside of the finalized chain.
1541
    BestNotInFinalizedChain,
1542
}
1543
1544
/// Error while calling [`SqliteFullDatabase::set_finalized`].
1545
0
#[derive(Debug, derive_more::Display, derive_more::From)]
Unexecuted instantiation: _RNvXs8_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_17SetFinalizedErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXs8_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_17SetFinalizedErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
1546
pub enum SetFinalizedError {
1547
    /// Error accessing the database.
1548
    Corrupted(CorruptedError),
1549
    /// New finalized block isn't in the database.
1550
    UnknownBlock,
1551
    /// New finalized block must be a child of the previous finalized block.
1552
    RevertForbidden,
1553
}
1554
1555
/// Error while accessing the storage of the finalized block.
1556
0
#[derive(Debug, derive_more::Display, derive_more::From)]
Unexecuted instantiation: _RNvXsb_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_18StorageAccessErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsb_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_18StorageAccessErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
1557
pub enum StorageAccessError {
1558
    /// Error accessing the database.
1559
    Corrupted(CorruptedError),
1560
    /// Some trie nodes of the storage of the requested block hash are missing.
1561
    IncompleteStorage,
1562
    /// Requested block couldn't be found in the database.
1563
    UnknownBlock,
1564
}
1565
1566
/// Error in the content of the database.
1567
// TODO: document and see if any entry is unused
1568
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXse_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_14CorruptedErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXse_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_14CorruptedErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
1569
pub enum CorruptedError {
1570
    /// Block numbers are expected to be 64 bits.
1571
    // TODO: remove this and use stronger schema
1572
    InvalidNumber,
1573
    /// Finalized block number stored in the database doesn't match any block.
1574
    InvalidFinalizedNum,
1575
    /// A block hash is expected to be 32 bytes. This isn't the case.
1576
    InvalidBlockHashLen,
1577
    /// A trie hash is expected to be 32 bytes. This isn't the case.
1578
    InvalidTrieHashLen,
1579
    /// The parent of a block in the database couldn't be found in that same database.
1580
    BrokenChain,
1581
    /// Missing a key in the `meta` table.
1582
    MissingMetaKey,
1583
    /// Some parts of the database refer to a block by its hash, but the block's constituents
1584
    /// couldn't be found.
1585
    MissingBlockHeader,
1586
    /// The header of a block in the database has failed to decode.
1587
    #[display(fmt = "Corrupted block header: {_0}")]
1588
    BlockHeaderCorrupted(header::Error),
1589
    /// The version information about a storage entry has failed to decode.
1590
    InvalidTrieEntryVersion,
1591
    #[display(fmt = "Internal error: {_0}")]
1592
    Internal(InternalError),
1593
}
1594
1595
/// Low-level database error, such as an error while accessing the file system.
1596
0
#[derive(Debug, derive_more::Display)]
Unexecuted instantiation: _RNvXsg_NtNtCsN16ciHI6Qf_7smoldot8database11full_sqliteNtB5_13InternalErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsg_NtNtCseuYC0Zibziv_7smoldot8database11full_sqliteNtB5_13InternalErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
1597
pub struct InternalError(rusqlite::Error);
1598
1599
26
fn meta_get_blob(
1600
26
    database: &rusqlite::Connection,
1601
26
    key: &str,
1602
26
) -> Result<Option<Vec<u8>>, CorruptedError> {
1603
26
    let value = database
1604
26
        .prepare_cached(r#"SELECT value_blob FROM meta WHERE key = ?"#)
1605
26
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_get_blob0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_get_blob0B7_
1606
26
        .query_row((key,), |row| row.get::<_, Vec<u8>>(0))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_get_blobs_0B7_
_RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_get_blobs_0B7_
Line
Count
Source
1606
26
        .query_row((key,), |row| row.get::<_, Vec<u8>>(0))
1607
26
        .optional()
1608
26
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_get_blobs0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_get_blobs0_0B7_
1609
26
    Ok(value)
1610
26
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_get_blob
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_get_blob
Line
Count
Source
1599
26
fn meta_get_blob(
1600
26
    database: &rusqlite::Connection,
1601
26
    key: &str,
1602
26
) -> Result<Option<Vec<u8>>, CorruptedError> {
1603
26
    let value = database
1604
26
        .prepare_cached(r#"SELECT value_blob FROM meta WHERE key = ?"#)
1605
26
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1606
26
        .query_row((key,), |row| row.get::<_, Vec<u8>>(0))
1607
26
        .optional()
1608
26
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1609
26
    Ok(value)
1610
26
}
1611
1612
21
fn meta_get_number(
1613
21
    database: &rusqlite::Connection,
1614
21
    key: &str,
1615
21
) -> Result<Option<u64>, CorruptedError> {
1616
21
    let value = database
1617
21
        .prepare_cached(r#"SELECT value_number FROM meta WHERE key = ?"#)
1618
21
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_get_number0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_get_number0B7_
1619
21
        .query_row((key,), |row| row.get::<_, i64>(0))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_get_numbers_0B7_
_RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_get_numbers_0B7_
Line
Count
Source
1619
21
        .query_row((key,), |row| row.get::<_, i64>(0))
1620
21
        .optional()
1621
21
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_get_numbers0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_get_numbers0_0B7_
1622
21
    Ok(value.map(|value| u64::from_ne_bytes(value.to_ne_bytes())))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_get_numbers1_0B7_
_RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_get_numbers1_0B7_
Line
Count
Source
1622
21
    Ok(value.map(|value| u64::from_ne_bytes(value.to_ne_bytes())))
1623
21
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_get_number
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_get_number
Line
Count
Source
1612
21
fn meta_get_number(
1613
21
    database: &rusqlite::Connection,
1614
21
    key: &str,
1615
21
) -> Result<Option<u64>, CorruptedError> {
1616
21
    let value = database
1617
21
        .prepare_cached(r#"SELECT value_number FROM meta WHERE key = ?"#)
1618
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1619
21
        .query_row((key,), |row| row.get::<_, i64>(0))
1620
21
        .optional()
1621
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1622
21
    Ok(value.map(|value| u64::from_ne_bytes(value.to_ne_bytes())))
1623
21
}
1624
1625
1.04k
fn meta_set_blob(
1626
1.04k
    database: &rusqlite::Connection,
1627
1.04k
    key: &str,
1628
1.04k
    value: &[u8],
1629
1.04k
) -> Result<(), CorruptedError> {
1630
1.04k
    database
1631
1.04k
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_blob) VALUES (?, ?)"#)
1632
1.04k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_set_blob0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_set_blob0B7_
1633
1.04k
        .execute((key, value))
1634
1.04k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_set_blobs_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_set_blobs_0B7_
1635
1.04k
    Ok(())
1636
1.04k
}
_RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13meta_set_blob
Line
Count
Source
1625
1.02k
fn meta_set_blob(
1626
1.02k
    database: &rusqlite::Connection,
1627
1.02k
    key: &str,
1628
1.02k
    value: &[u8],
1629
1.02k
) -> Result<(), CorruptedError> {
1630
1.02k
    database
1631
1.02k
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_blob) VALUES (?, ?)"#)
1632
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1633
1.02k
        .execute((key, value))
1634
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1635
1.02k
    Ok(())
1636
1.02k
}
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13meta_set_blob
Line
Count
Source
1625
21
fn meta_set_blob(
1626
21
    database: &rusqlite::Connection,
1627
21
    key: &str,
1628
21
    value: &[u8],
1629
21
) -> Result<(), CorruptedError> {
1630
21
    database
1631
21
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_blob) VALUES (?, ?)"#)
1632
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1633
21
        .execute((key, value))
1634
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1635
21
    Ok(())
1636
21
}
1637
1638
1.04k
fn meta_set_number(
1639
1.04k
    database: &rusqlite::Connection,
1640
1.04k
    key: &str,
1641
1.04k
    value: u64,
1642
1.04k
) -> Result<(), CorruptedError> {
1643
1.04k
    database
1644
1.04k
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_number) VALUES (?, ?)"#)
1645
1.04k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_set_number0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_set_number0B7_
1646
1.04k
        .execute((key, i64::from_ne_bytes(value.to_ne_bytes())))
1647
1.04k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_set_numbers_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_set_numbers_0B7_
1648
1.04k
    Ok(())
1649
1.04k
}
_RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite15meta_set_number
Line
Count
Source
1638
1.02k
fn meta_set_number(
1639
1.02k
    database: &rusqlite::Connection,
1640
1.02k
    key: &str,
1641
1.02k
    value: u64,
1642
1.02k
) -> Result<(), CorruptedError> {
1643
1.02k
    database
1644
1.02k
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_number) VALUES (?, ?)"#)
1645
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1646
1.02k
        .execute((key, i64::from_ne_bytes(value.to_ne_bytes())))
1647
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1648
1.02k
    Ok(())
1649
1.02k
}
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite15meta_set_number
Line
Count
Source
1638
21
fn meta_set_number(
1639
21
    database: &rusqlite::Connection,
1640
21
    key: &str,
1641
21
    value: u64,
1642
21
) -> Result<(), CorruptedError> {
1643
21
    database
1644
21
        .prepare_cached(r#"INSERT OR REPLACE INTO meta(key, value_number) VALUES (?, ?)"#)
1645
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1646
21
        .execute((key, i64::from_ne_bytes(value.to_ne_bytes())))
1647
21
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1648
21
    Ok(())
1649
21
}
1650
1651
0
fn has_block(database: &rusqlite::Connection, hash: &[u8]) -> Result<bool, CorruptedError> {
1652
0
    database
1653
0
        .prepare_cached(r#"SELECT COUNT(*) FROM blocks WHERE hash = ?"#)
1654
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite9has_block0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite9has_block0B7_
1655
0
        .query_row((hash,), |row| Ok(row.get_unwrap::<_, i64>(0) != 0))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite9has_blocks_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite9has_blocks_0B7_
1656
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite9has_blocks0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite9has_blocks0_0B7_
1657
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite9has_block
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite9has_block
1658
1659
// TODO: the fact that the meta table stores blobs makes it impossible to use joins ; fix that
1660
21
fn finalized_num(database: &rusqlite::Connection) -> Result<u64, CorruptedError> {
1661
21
    meta_get_number(database, "finalized")
?0
.ok_or(CorruptedError::MissingMetaKey)
1662
21
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite13finalized_num
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite13finalized_num
Line
Count
Source
1660
21
fn finalized_num(database: &rusqlite::Connection) -> Result<u64, CorruptedError> {
1661
21
    meta_get_number(database, "finalized")
?0
.ok_or(CorruptedError::MissingMetaKey)
1662
21
}
1663
1664
1.12k
fn finalized_hash(database: &rusqlite::Connection) -> Result<[u8; 32], CorruptedError> {
1665
1.12k
    let value = database
1666
1.12k
        .prepare_cached(r#"SELECT hash FROM blocks WHERE number = (SELECT value_number FROM meta WHERE key = "finalized")"#)
1667
1.12k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14finalized_hash0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14finalized_hash0B7_
1668
1.12k
        .query_row((), |row| row.get::<_, Vec<u8>>(0))
_RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14finalized_hashs_0B7_
Line
Count
Source
1668
1.02k
        .query_row((), |row| row.get::<_, Vec<u8>>(0))
_RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14finalized_hashs_0B7_
Line
Count
Source
1668
105
        .query_row((), |row| row.get::<_, Vec<u8>>(0))
1669
1.12k
        .optional()
1670
1.12k
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14finalized_hashs0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14finalized_hashs0_0B7_
1671
1.12k
        .ok_or(CorruptedError::InvalidFinalizedNum)
?0
;
1672
1673
1.12k
    if value.len() == 32 {
1674
1.12k
        let mut out = [0; 32];
1675
1.12k
        out.copy_from_slice(&value);
1676
1.12k
        Ok(out)
1677
    } else {
1678
0
        Err(CorruptedError::InvalidBlockHashLen)
1679
    }
1680
1.12k
}
_RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14finalized_hash
Line
Count
Source
1664
1.02k
fn finalized_hash(database: &rusqlite::Connection) -> Result<[u8; 32], CorruptedError> {
1665
1.02k
    let value = database
1666
1.02k
        .prepare_cached(r#"SELECT hash FROM blocks WHERE number = (SELECT value_number FROM meta WHERE key = "finalized")"#)
1667
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1668
1.02k
        .query_row((), |row| row.get::<_, Vec<u8>>(0))
1669
1.02k
        .optional()
1670
1.02k
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1671
1.02k
        .ok_or(CorruptedError::InvalidFinalizedNum)
?0
;
1672
1673
1.02k
    if value.len() == 32 {
1674
1.02k
        let mut out = [0; 32];
1675
1.02k
        out.copy_from_slice(&value);
1676
1.02k
        Ok(out)
1677
    } else {
1678
0
        Err(CorruptedError::InvalidBlockHashLen)
1679
    }
1680
1.02k
}
_RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14finalized_hash
Line
Count
Source
1664
105
fn finalized_hash(database: &rusqlite::Connection) -> Result<[u8; 32], CorruptedError> {
1665
105
    let value = database
1666
105
        .prepare_cached(r#"SELECT hash FROM blocks WHERE number = (SELECT value_number FROM meta WHERE key = "finalized")"#)
1667
105
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1668
105
        .query_row((), |row| row.get::<_, Vec<u8>>(0))
1669
105
        .optional()
1670
105
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1671
105
        .ok_or(CorruptedError::InvalidFinalizedNum)
?0
;
1672
1673
105
    if value.len() == 32 {
1674
105
        let mut out = [0; 32];
1675
105
        out.copy_from_slice(&value);
1676
105
        Ok(out)
1677
    } else {
1678
0
        Err(CorruptedError::InvalidBlockHashLen)
1679
    }
1680
105
}
1681
1682
45
fn block_hashes_by_number(
1683
45
    database: &rusqlite::Connection,
1684
45
    number: u64,
1685
45
) -> Result<Vec<[u8; 32]>, CorruptedError> {
1686
45
    let number = match i64::try_from(number) {
1687
45
        Ok(n) => n,
1688
0
        Err(_) => return Ok(Vec::new()),
1689
    };
1690
1691
45
    database
1692
45
        .prepare_cached(r#"SELECT hash FROM blocks WHERE number = ?"#)
1693
45
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_number0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_number0B7_
1694
45
        .query_map((number,), |row| row.get::<_, Vec<u8>>(0))
_RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_numbers_0B7_
Line
Count
Source
1694
45
        .query_map((number,), |row| row.get::<_, Vec<u8>>(0))
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_numbers_0B7_
1695
45
        .map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_numbers0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_numbers0_0B7_
1696
45
        .map(|value| {
1697
45
            let value = value.map_err(|err| 
CorruptedError::Internal(InternalError(err))0
)
?0
;
Unexecuted instantiation: _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_numbers1_00B9_
Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_numbers1_00B9_
1698
45
            <[u8; 32]>::try_from(&value[..]).map_err(|_| 
CorruptedError::InvalidBlockHashLen0
)
Unexecuted instantiation: _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_numbers1_0s_0B9_
Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_numbers1_0s_0B9_
1699
45
        })
_RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_numbers1_0B7_
Line
Count
Source
1696
45
        .map(|value| {
1697
45
            let value = value.map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
;
1698
45
            <[u8; 32]>::try_from(&value[..]).map_err(|_| CorruptedError::InvalidBlockHashLen)
1699
45
        })
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_numbers1_0B7_
1700
45
        .collect::<Result<Vec<_>, _>>()
1701
45
}
_RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite22block_hashes_by_number
Line
Count
Source
1682
45
fn block_hashes_by_number(
1683
45
    database: &rusqlite::Connection,
1684
45
    number: u64,
1685
45
) -> Result<Vec<[u8; 32]>, CorruptedError> {
1686
45
    let number = match i64::try_from(number) {
1687
45
        Ok(n) => n,
1688
0
        Err(_) => return Ok(Vec::new()),
1689
    };
1690
1691
45
    database
1692
45
        .prepare_cached(r#"SELECT hash FROM blocks WHERE number = ?"#)
1693
45
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1694
45
        .query_map((number,), |row| row.get::<_, Vec<u8>>(0))
1695
45
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
?0
1696
45
        .map(|value| {
1697
            let value = value.map_err(|err| CorruptedError::Internal(InternalError(err)))?;
1698
            <[u8; 32]>::try_from(&value[..]).map_err(|_| CorruptedError::InvalidBlockHashLen)
1699
45
        })
1700
45
        .collect::<Result<Vec<_>, _>>()
1701
45
}
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite22block_hashes_by_number
1702
1703
0
fn block_header(
1704
0
    database: &rusqlite::Connection,
1705
0
    hash: &[u8; 32],
1706
0
) -> Result<Option<Vec<u8>>, CorruptedError> {
1707
0
    database
1708
0
        .prepare_cached(r#"SELECT header FROM blocks WHERE hash = ?"#)
1709
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite12block_header0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite12block_header0B7_
1710
0
        .query_row((&hash[..],), |row| row.get::<_, Vec<u8>>(0))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite12block_headers_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite12block_headers_0B7_
1711
0
        .optional()
1712
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite12block_headers0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite12block_headers0_0B7_
1713
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite12block_header
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite12block_header
1714
1715
0
fn set_best_chain(
1716
0
    database: &rusqlite::Connection,
1717
0
    new_best_block_hash: &[u8],
1718
0
) -> Result<(), CorruptedError> {
1719
    // TODO: can this not be embedded in the SQL statement below?
1720
0
    let current_best = meta_get_blob(database, "best")?.ok_or(CorruptedError::MissingMetaKey)?;
1721
1722
    // TODO: untested except in the most basic situation
1723
    // In the SQL below, the temporary table `changes` is built by walking down (highest to lowest
1724
    // block number) the new best chain and old best chain. While walking down, the iteration
1725
    // keeps track of the block hashes and their number. If the new best chain has a higher number
1726
    // than the old best chain, then only the new best chain is iterated, and vice versa. If the
1727
    // new and old best chain have the same number, they are both iterated, and it is possible to
1728
    // compare the block hashes in order to know when to stop iterating. In the context of this
1729
    // algorithm, a `NULL` block hash represents "one past the new/old best block", which allows
1730
    // to not include the new/old best block in the temporary table until it needs to be included.
1731
0
    database
1732
0
        .prepare_cached(
1733
0
            r#"
1734
0
        WITH RECURSIVE
1735
0
            changes(block_to_include, block_to_retract, block_to_include_number, block_to_retract_number) AS (
1736
0
                SELECT NULL, NULL, blocks_inc.number + 1, blocks_ret.number + 1
1737
0
                FROM blocks AS blocks_inc, blocks as blocks_ret
1738
0
                WHERE blocks_inc.hash = :new_best AND blocks_ret.hash = :current_best
1739
0
            UNION ALL
1740
0
                SELECT
1741
0
                    CASE WHEN changes.block_to_include_number >= changes.block_to_retract_number THEN
1742
0
                        COALESCE(blocks_inc.parent_hash, :new_best)
1743
0
                    ELSE
1744
0
                        changes.block_to_include
1745
0
                    END,
1746
0
                    CASE WHEN changes.block_to_retract_number >= changes.block_to_include_number THEN
1747
0
                        COALESCE(blocks_ret.parent_hash, :current_best)
1748
0
                    ELSE
1749
0
                        changes.block_to_retract
1750
0
                    END,
1751
0
                    CASE WHEN changes.block_to_include_number >= block_to_retract_number THEN changes.block_to_include_number - 1
1752
0
                    ELSE changes.block_to_include_number END,
1753
0
                    CASE WHEN changes.block_to_retract_number >= changes.block_to_include_number THEN changes.block_to_retract_number - 1
1754
0
                    ELSE changes.block_to_retract_number END
1755
0
                FROM changes
1756
0
                LEFT JOIN blocks AS blocks_inc ON blocks_inc.hash = changes.block_to_include
1757
0
                LEFT JOIN blocks AS blocks_ret ON blocks_ret.hash = changes.block_to_retract
1758
0
                WHERE changes.block_to_include_number != changes.block_to_retract_number
1759
0
                    OR COALESCE(blocks_inc.parent_hash, :new_best) != COALESCE(blocks_ret.parent_hash, :current_best)
1760
0
            )
1761
0
        UPDATE blocks SET is_best_chain = (blocks.hash = changes.block_to_include)
1762
0
        FROM changes
1763
0
        WHERE blocks.hash = changes.block_to_include OR blocks.hash = changes.block_to_retract;
1764
0
            "#,
1765
0
        )
1766
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14set_best_chain0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14set_best_chain0B7_
1767
0
        .execute(rusqlite::named_params! {
1768
0
            ":current_best": current_best,
1769
0
            ":new_best": new_best_block_hash
1770
0
        })
1771
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14set_best_chains_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14set_best_chains_0B7_
1772
1773
0
    meta_set_blob(database, "best", new_best_block_hash)?;
1774
0
    Ok(())
1775
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite14set_best_chain
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite14set_best_chain
1776
1777
0
fn purge_block(database: &rusqlite::Connection, hash: &[u8]) -> Result<(), CorruptedError> {
1778
0
    purge_block_storage(database, hash)?;
1779
0
    database
1780
0
        .prepare_cached("DELETE FROM blocks_body WHERE hash = ?")
1781
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite11purge_block0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite11purge_block0B7_
1782
0
        .execute((hash,))
1783
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite11purge_blocks_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite11purge_blocks_0B7_
1784
0
    database
1785
0
        .prepare_cached("DELETE FROM blocks WHERE hash = ?")
1786
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite11purge_blocks0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite11purge_blocks0_0B7_
1787
0
        .execute((hash,))
1788
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite11purge_blocks1_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite11purge_blocks1_0B7_
1789
0
    Ok(())
1790
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite11purge_block
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite11purge_block
1791
1792
0
fn purge_block_storage(database: &rusqlite::Connection, hash: &[u8]) -> Result<(), CorruptedError> {
1793
    // TODO: untested
1794
1795
0
    let state_trie_root_hash = database
1796
0
        .prepare_cached(r#"SELECT state_trie_root_hash FROM blocks WHERE hash = ?"#)
1797
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storage0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storage0B7_
1798
0
        .query_row((hash,), |row| row.get::<_, Vec<u8>>(0))
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages_0B7_
1799
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages0_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages0_0B7_
1800
1801
0
    database
1802
0
        .prepare_cached(
1803
0
            r#"
1804
0
            UPDATE blocks SET state_trie_root_hash = NULL
1805
0
            WHERE hash = :block_hash
1806
0
        "#,
1807
0
        )
1808
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages1_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages1_0B7_
1809
0
        .execute(rusqlite::named_params! {
1810
0
            ":block_hash": hash,
1811
0
        })
1812
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages2_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages2_0B7_
1813
1814
    // TODO: doesn't delete everything in the situation where a single node with a merkle value is referenced multiple times from the same trie
1815
    // TODO: currently doesn't follow `trie_root_ref`
1816
0
    database
1817
0
        .prepare_cached(r#"
1818
0
            WITH RECURSIVE
1819
0
                to_delete(node_hash) AS (
1820
0
                    SELECT trie_node.hash
1821
0
                        FROM trie_node
1822
0
                        LEFT JOIN blocks ON blocks.hash != :block_hash AND blocks.state_trie_root_hash = trie_node.hash
1823
0
                        LEFT JOIN trie_node_storage ON trie_node_storage.trie_root_ref = trie_node.hash
1824
0
                        WHERE trie_node.hash = :state_trie_root_hash AND blocks.hash IS NULL AND trie_node_storage.node_hash IS NULL
1825
0
                    UNION ALL
1826
0
                    SELECT trie_node_child.child_hash
1827
0
                        FROM to_delete
1828
0
                        JOIN trie_node_child ON trie_node_child.hash = to_delete.node_hash
1829
0
                        LEFT JOIN blocks ON blocks.state_trie_root_hash = trie_node_child.child_hash
1830
0
                        LEFT JOIN trie_node_storage ON trie_node_storage.trie_root_ref = to_delete.node_hash
1831
0
                        WHERE blocks.hash IS NULL AND trie_node_storage.node_hash IS NULL
1832
0
                )
1833
0
            DELETE FROM trie_node
1834
0
            WHERE hash IN (SELECT node_hash FROM to_delete)
1835
0
        "#)
1836
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages3_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages3_0B7_
1837
0
        .execute(rusqlite::named_params! {
1838
0
            ":state_trie_root_hash": &state_trie_root_hash,
1839
0
            ":block_hash": hash,
1840
0
        })
1841
0
        .map_err(|err| CorruptedError::Internal(InternalError(err)))?;
Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storages4_0B7_
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storages4_0B7_
1842
0
    Ok(())
1843
0
}
Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot8database11full_sqlite19purge_block_storage
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot8database11full_sqlite19purge_block_storage