Coverage Report

Created: 2025-07-01 09:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/lib/src/executor/runtime_call.rs
Line
Count
Source
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
//! Wasm virtual machine, with automatic storage overlay.
19
//!
20
//! The code in this module builds upon the functionalities of the [`host`] module and
21
//! implements some of the host function calls. In other words, it is an easier-to-use version of
22
//! the [`host`] module.
23
//!
24
//! Most of the documentation of the [`host`] module also applies here.
25
//!
26
//! In addition to the functionalities provided by the [`host`] module, the `runtime_call` module:
27
//!
28
//! - Keeps track of the changes to the storage and off-chain storage made by the execution, and
29
//!   provides them at the end. Any storage access takes into account the intermediary list of
30
//!   changes.
31
//! - Automatically handles some externalities, such as calculating the Merkle root or storage
32
//!   transactions.
33
//!
34
//! These additional features considerably reduces the number of externals concepts to plug to
35
//! the virtual machine.
36
37
// TODO: more docs
38
39
use crate::{
40
    executor::{self, host, storage_diff, trie_root_calculator, vm},
41
    trie, util,
42
};
43
44
use alloc::{
45
    borrow::ToOwned as _,
46
    boxed::Box,
47
    collections::BTreeMap,
48
    format,
49
    string::{String, ToString as _},
50
    vec::Vec,
51
};
52
use core::{fmt, iter, ops};
53
54
pub use host::{
55
    Error as ErrorDetail, LogEmitInfo, LogEmitInfoHex, LogEmitInfoStr, StorageProofSizeBehavior,
56
};
57
pub use trie::{Nibble, TrieEntryVersion};
58
59
mod tests;
60
61
/// Configuration for [`run`].
62
pub struct Config<'a, TParams> {
63
    /// Virtual machine to be run.
64
    pub virtual_machine: host::HostVmPrototype,
65
66
    /// Name of the function to be called.
67
    pub function_to_call: &'a str,
68
69
    /// Parameter of the call, as an iterator of bytes. The concatenation of bytes forms the
70
    /// actual input.
71
    pub parameter: TParams,
72
73
    /// Initial state of [`Success::storage_changes`]. The changes made during this
74
    /// execution will be pushed over the value in this field.
75
    // TODO: consider accepting a different type
76
    // TODO: accept also child trie modifications
77
    pub storage_main_trie_changes: storage_diff::TrieDiff,
78
79
    /// Behavior if the `ext_storage_proof_size_storage_proof_size_version_1` host function is
80
    /// called.
81
    ///
82
    /// See the documentation of [`StorageProofSizeBehavior`].
83
    pub storage_proof_size_behavior: StorageProofSizeBehavior,
84
85
    /// Maximum log level of the runtime.
86
    ///
87
    /// > **Note**: This value is opaque from the point of the view of the client, and the runtime
88
    /// >           is free to interpret it the way it wants. However, usually values are: `0` for
89
    /// >           "off", `1` for "error", `2` for "warn", `3` for "info", `4` for "debug",
90
    /// >           and `5` for "trace".
91
    pub max_log_level: u32,
92
93
    /// If `true`, then [`StorageChanges::trie_changes_iter_ordered`] will return `Some`.
94
    /// Passing `None` requires fewer calculation and fewer storage accesses.
95
    pub calculate_trie_changes: bool,
96
}
97
98
/// Start running the WebAssembly virtual machine.
99
138
pub fn run(
100
138
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
138
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
138
    let state_trie_version = config
103
138
        .virtual_machine
104
138
        .runtime_version()
105
138
        .decode()
106
138
        .state_version
107
138
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
138
        vm: config
111
138
            .virtual_machine
112
138
            .run_vectored(
113
138
                config.function_to_call,
114
138
                config.storage_proof_size_behavior,
115
138
                config.parameter,
116
0
            )?
117
138
            .into(),
118
138
        pending_storage_changes: PendingStorageChanges {
119
138
            trie_diffs: {
120
138
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
138
                hm.insert(None, config.storage_main_trie_changes);
122
138
                hm
123
138
            },
124
138
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
138
                4,
126
138
                Default::default(),
127
138
            ),
128
138
            tries_changes: BTreeMap::new(),
129
138
            offchain_storage_changes: BTreeMap::new(),
130
138
        },
131
138
        state_trie_version,
132
138
        transactions_stack: Vec::new(),
133
138
        offchain_storage_changes: BTreeMap::new(),
134
138
        root_calculation: None,
135
138
        max_log_level: config.max_log_level,
136
138
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
138
    .run())
139
138
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherIBU_RShINtNtCsh2B47LN1tya_8arrayvec8arrayvec8ArrayVechKj9_EEIBU_B1v_IBU_INtNtCsaFPxhswmqCN_5alloc3vec3VechEB1s_EEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainINtNtB3j_3map3MapIB3f_IB3f_IB3f_INtNtNtB3l_7sources4once4OnceB1o_EB4C_EB4C_EB4C_ENcNtBT_4Left0EIB47_IB3f_IB4D_B2m_EINtNtB3j_7flatten7FlatMapNtNtB6_6header8LogsIterIB47_INtNtNtB3n_5array4iter8IntoIterB2u_Kj2_ENcNtB2m_5Right0ENCNvMs2_B6o_NtB6o_9DigestRef14scale_encoding0EENcNtBT_5Right0EEEB6_
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherINtNtCsh2B47LN1tya_8arrayvec8arrayvec8ArrayVechKj9_EIBU_Ahj8_IBU_B1o_B2i_EEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainINtNtB2H_3map3MapINtNtNtB2J_7sources4once4OnceB1o_ENcNtBT_4Left0EIB3v_INtNtB2H_7flatten7FlatMapINtNtNtB2L_5array4iter8IntoIterTB2i_B2i_EKj1_EIB2D_IB3v_IB3M_B2i_ENcNtB2e_4Left0EIB3v_IB2D_IB3v_B3L_NcNtB2n_4Left0EIB3v_B5V_NcNtB2n_5Right0EENcNtB2e_5Right0EENCINvMs_NtNtB6_6author7runtimeNtB7H_18InherentExtrinsics25inject_raw_inherents_listB2i_B51_E0ENcNtBT_5Right0EEEB6_
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherRAhj1_IBU_RShRINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainIB2e_INtNtB2i_3map3MapINtNtNtB2k_7sources4once4OnceB1o_ENcNtBT_4Left0EIB3b_IB3b_IB3s_B1B_ENcNtB1u_5Right0ENcNtBT_5Right0EEIB3b_IB3b_IB3s_B1y_ENcNtB1u_4Left0EB4N_EEEB6_
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherRINtNtCsaFPxhswmqCN_5alloc3vec3VechEIBU_B1o_INtNtCsh2B47LN1tya_8arrayvec8arrayvec8ArrayVechKj9_EEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainIB2Z_INtNtNtB35_7sources4once4OnceBT_EB3V_EINtNtB33_3map3MapINtNtNtB37_5slice4iter4IterNtNtB2_5tests9HexStringENCNvB5h_s_14execute_blockss0_0EEEB6_
Line
Count
Source
99
4
pub fn run(
100
4
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
4
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
4
    let state_trie_version = config
103
4
        .virtual_machine
104
4
        .runtime_version()
105
4
        .decode()
106
4
        .state_version
107
4
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
4
        vm: config
111
4
            .virtual_machine
112
4
            .run_vectored(
113
4
                config.function_to_call,
114
4
                config.storage_proof_size_behavior,
115
4
                config.parameter,
116
0
            )?
117
4
            .into(),
118
4
        pending_storage_changes: PendingStorageChanges {
119
4
            trie_diffs: {
120
4
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
4
                hm.insert(None, config.storage_main_trie_changes);
122
4
                hm
123
4
            },
124
4
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
4
                4,
126
4
                Default::default(),
127
4
            ),
128
4
            tries_changes: BTreeMap::new(),
129
4
            offchain_storage_changes: BTreeMap::new(),
130
4
        },
131
4
        state_trie_version,
132
4
        transactions_stack: Vec::new(),
133
4
        offchain_storage_changes: BTreeMap::new(),
134
4
        root_calculation: None,
135
4
        max_log_level: config.max_log_level,
136
4
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
4
    .run())
139
4
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources5empty5EmptyBT_EEB6_
Line
Count
Source
99
2
pub fn run(
100
2
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
2
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
2
    let state_trie_version = config
103
2
        .virtual_machine
104
2
        .runtime_version()
105
2
        .decode()
106
2
        .state_version
107
2
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
2
        vm: config
111
2
            .virtual_machine
112
2
            .run_vectored(
113
2
                config.function_to_call,
114
2
                config.storage_proof_size_behavior,
115
2
                config.parameter,
116
0
            )?
117
2
            .into(),
118
2
        pending_storage_changes: PendingStorageChanges {
119
2
            trie_diffs: {
120
2
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
2
                hm.insert(None, config.storage_main_trie_changes);
122
2
                hm
123
2
            },
124
2
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
2
                4,
126
2
                Default::default(),
127
2
            ),
128
2
            tries_changes: BTreeMap::new(),
129
2
            offchain_storage_changes: BTreeMap::new(),
130
2
        },
131
2
        state_trie_version,
132
2
        transactions_stack: Vec::new(),
133
2
        offchain_storage_changes: BTreeMap::new(),
134
2
        root_calculation: None,
135
2
        max_log_level: config.max_log_level,
136
2
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
2
    .run())
139
2
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runRINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EEB6_
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
_RINvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call3runRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources5empty5EmptyBT_EEB6_
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EECscoAnRPySggw_6author
_RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources5empty5EmptyBT_EECsfFWJyR6nd6r_17smoldot_full_node
Line
Count
Source
99
1
pub fn run(
100
1
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
1
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
1
    let state_trie_version = config
103
1
        .virtual_machine
104
1
        .runtime_version()
105
1
        .decode()
106
1
        .state_version
107
1
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
1
        vm: config
111
1
            .virtual_machine
112
1
            .run_vectored(
113
1
                config.function_to_call,
114
1
                config.storage_proof_size_behavior,
115
1
                config.parameter,
116
0
            )?
117
1
            .into(),
118
1
        pending_storage_changes: PendingStorageChanges {
119
1
            trie_diffs: {
120
1
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
1
                hm.insert(None, config.storage_main_trie_changes);
122
1
                hm
123
1
            },
124
1
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
1
                4,
126
1
                Default::default(),
127
1
            ),
128
1
            tries_changes: BTreeMap::new(),
129
1
            offchain_storage_changes: BTreeMap::new(),
130
1
        },
131
1
        state_trie_version,
132
1
        transactions_stack: Vec::new(),
133
1
        offchain_storage_changes: BTreeMap::new(),
134
1
        root_calculation: None,
135
1
        max_log_level: config.max_log_level,
136
1
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
1
    .run())
139
1
}
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherIBU_RShINtNtCsh2B47LN1tya_8arrayvec8arrayvec8ArrayVechKj9_EEIBU_B1v_IBU_INtNtCsaFPxhswmqCN_5alloc3vec3VechEB1s_EEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainINtNtB3j_3map3MapIB3f_IB3f_IB3f_INtNtNtB3l_7sources4once4OnceB1o_EB4C_EB4C_EB4C_ENcNtBT_4Left0EIB47_IB3f_IB4D_B2m_EINtNtB3j_7flatten7FlatMapNtNtB6_6header8LogsIterIB47_INtNtNtB3n_5array4iter8IntoIterB2u_Kj2_ENcNtB2m_5Right0ENCNvMs2_B6o_NtB6o_9DigestRef14scale_encoding0EENcNtBT_5Right0EEEB6_
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runINtCsfDbbEgL1j7J_6either6EitherINtNtCsh2B47LN1tya_8arrayvec8arrayvec8ArrayVechKj9_EIBU_Ahj8_IBU_B1o_B2i_EEEINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters5chain5ChainINtNtB2H_3map3MapINtNtNtB2J_7sources4once4OnceB1o_ENcNtBT_4Left0EIB3v_INtNtB2H_7flatten7FlatMapINtNtNtB2L_5array4iter8IntoIterTB2i_B2i_EKj1_EIB2D_IB3v_IB3M_B2i_ENcNtB2e_4Left0EIB3v_IB2D_IB3v_B3L_NcNtB2n_4Left0EIB3v_B5V_NcNtB2n_5Right0EENcNtB2e_5Right0EENCINvMs_NtNtB6_6author7runtimeNtB7H_18InherentExtrinsics25inject_raw_inherents_listB2i_B51_E0ENcNtBT_5Right0EEEB6_
_RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources5empty5EmptyBT_EEB6_
Line
Count
Source
99
126
pub fn run(
100
126
    config: Config<impl Iterator<Item = impl AsRef<[u8]>> + Clone>,
101
126
) -> Result<RuntimeCall, (host::StartErr, host::HostVmPrototype)> {
102
126
    let state_trie_version = config
103
126
        .virtual_machine
104
126
        .runtime_version()
105
126
        .decode()
106
126
        .state_version
107
126
        .unwrap_or(TrieEntryVersion::V0);
108
109
    Ok(Inner {
110
126
        vm: config
111
126
            .virtual_machine
112
126
            .run_vectored(
113
126
                config.function_to_call,
114
126
                config.storage_proof_size_behavior,
115
126
                config.parameter,
116
0
            )?
117
126
            .into(),
118
126
        pending_storage_changes: PendingStorageChanges {
119
126
            trie_diffs: {
120
126
                let mut hm = hashbrown::HashMap::with_capacity_and_hasher(4, Default::default());
121
126
                hm.insert(None, config.storage_main_trie_changes);
122
126
                hm
123
126
            },
124
126
            stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
125
126
                4,
126
126
                Default::default(),
127
126
            ),
128
126
            tries_changes: BTreeMap::new(),
129
126
            offchain_storage_changes: BTreeMap::new(),
130
126
        },
131
126
        state_trie_version,
132
126
        transactions_stack: Vec::new(),
133
126
        offchain_storage_changes: BTreeMap::new(),
134
126
        root_calculation: None,
135
126
        max_log_level: config.max_log_level,
136
126
        calculate_trie_changes: config.calculate_trie_changes,
137
    }
138
126
    .run())
139
126
}
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EEB6_
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources5empty5EmptyBT_EEB6_
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EECs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EECsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RINvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call3runRRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceBT_EECs4VrkfB1pvQ3_25json_rpc_general_requests
140
141
/// Execution is successful.
142
#[derive(Debug)]
143
pub struct Success {
144
    /// Contains the output value of the runtime, and the virtual machine that was passed at
145
    /// initialization.
146
    pub virtual_machine: SuccessVirtualMachine,
147
    /// List of changes to the storage that the block performs.
148
    pub storage_changes: StorageChanges,
149
    /// State trie version indicated by the runtime. All the storage changes indicated by
150
    /// [`Success::storage_changes`] should store this version alongside with them.
151
    pub state_trie_version: TrieEntryVersion,
152
}
153
154
/// See [`Success::storage_changes`].
155
pub struct StorageChanges {
156
    /// The [`PendingStorageChanges`] that was built by the state machine. The changes are no
157
    /// longer pending.
158
    inner: PendingStorageChanges,
159
160
    /// See [`Config::calculate_trie_changes`].
161
    calculate_trie_changes: bool,
162
}
163
164
impl StorageChanges {
165
    /// Returns an empty [`StorageChanges`], as if the execution didn't modify anything.
166
0
    pub fn empty() -> StorageChanges {
167
0
        StorageChanges {
168
0
            inner: PendingStorageChanges {
169
0
                trie_diffs: hashbrown::HashMap::with_capacity_and_hasher(0, Default::default()),
170
0
                stale_child_tries_root_hashes: hashbrown::HashSet::with_capacity_and_hasher(
171
0
                    4,
172
0
                    Default::default(),
173
0
                ),
174
0
                tries_changes: BTreeMap::new(),
175
0
                offchain_storage_changes: BTreeMap::new(),
176
0
            },
177
0
            calculate_trie_changes: true,
178
0
        }
179
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges5empty
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges5empty
180
181
    /// Returns the change, if any, at the given key of the main trie.
182
    ///
183
    /// Returns `None` if the runtime hasn't modified this entry in the main trie, and `Some(None)`
184
    /// if the runtime has removed the storage item of this entry.
185
0
    pub fn main_trie_diff_get(&self, key: &[u8]) -> Option<Option<&[u8]>> {
186
0
        self.inner
187
0
            .trie_diffs
188
0
            .get(&None)
189
0
            .and_then(|diff| diff.diff_get(key).map(|(v, _)| v))
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges18main_trie_diff_get0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges18main_trie_diff_get0B8_
190
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges18main_trie_diff_get
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges18main_trie_diff_get
191
192
    /// Returns an iterator to all the entries of the main trie that are modified by this runtime
193
    /// call.
194
    ///
195
    /// Each value is either `Some` if the runtime overwrites this value, or `None` if it erases
196
    /// the underlying value.
197
    ///
198
    /// > **Note**: This function is equivalent to
199
    /// >           [`StorageChanges::storage_changes_iter_unordered`], except that it only returns
200
    /// >           changes made to the main trie.
201
0
    pub fn main_trie_storage_changes_iter_unordered(
202
0
        &self,
203
0
    ) -> impl Iterator<Item = (&[u8], Option<&[u8]>)> + Clone {
204
0
        self.inner
205
0
            .trie_diffs
206
0
            .get(&None)
207
0
            .into_iter()
208
0
            .flat_map(|list| list.diff_iter_unordered().map(|(k, v, ())| (k, v)))
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges40main_trie_storage_changes_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges40main_trie_storage_changes_iter_unordered0CsfFWJyR6nd6r_17smoldot_full_node
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges40main_trie_storage_changes_iter_unordered0B8_
Unexecuted instantiation: _RNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChanges40main_trie_storage_changes_iter_unordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges40main_trie_storage_changes_iter_unordered00CsfFWJyR6nd6r_17smoldot_full_node
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges40main_trie_storage_changes_iter_unordered00Ba_
209
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges40main_trie_storage_changes_iter_unordered
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges40main_trie_storage_changes_iter_unordered
210
211
    /// Returns the list of all child tries whose content has been modified in some way.
212
0
    pub fn tries_with_storage_changes_unordered(&self) -> impl Iterator<Item = &[u8]> {
213
0
        self.inner.trie_diffs.keys().filter_map(|k| k.as_deref())
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges36tries_with_storage_changes_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges36tries_with_storage_changes_unordered0B8_
214
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges36tries_with_storage_changes_unordered
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges36tries_with_storage_changes_unordered
215
216
    /// Returns an iterator to all the entries of the given child trie that are modified by this
217
    /// runtime call.
218
    ///
219
    /// Each value is either `Some` if the runtime overwrites this value, or `None` if it erases
220
    /// the underlying value.
221
    ///
222
    /// > **Note**: This function is equivalent to
223
    /// >           [`StorageChanges::storage_changes_iter_unordered`], except that it only returns
224
    /// >           changes made to the given child trie.
225
0
    pub fn child_trie_storage_changes_iter_unordered(
226
0
        &self,
227
0
        child_trie: &[u8],
228
0
    ) -> impl Iterator<Item = (&[u8], Option<&[u8]>)> + Clone {
229
0
        self.inner
230
0
            .trie_diffs
231
0
            .get(&Some(child_trie.to_vec())) // TODO: annoying unnecessary overhead
232
0
            .into_iter()
233
0
            .flat_map(|list| list.diff_iter_unordered().map(|(k, v, ())| (k, v)))
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges41child_trie_storage_changes_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges41child_trie_storage_changes_iter_unordered0B8_
Unexecuted instantiation: _RNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChanges41child_trie_storage_changes_iter_unordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges41child_trie_storage_changes_iter_unordered00Ba_
234
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges41child_trie_storage_changes_iter_unordered
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges41child_trie_storage_changes_iter_unordered
235
236
    /// Returns an iterator to all the entries that are modified by this runtime call.
237
    ///
238
    /// Each value is either `Some` if the runtime overwrites this value, or `None` if it erases
239
    /// the underlying value.
240
0
    pub fn storage_changes_iter_unordered(
241
0
        &self,
242
0
    ) -> impl Iterator<Item = (Option<&[u8]>, &[u8], Option<&[u8]>)> + Clone {
243
0
        self.inner.trie_diffs.iter().flat_map(|(trie, list)| {
244
0
            list.diff_iter_unordered()
245
0
                .map(move |(k, v, ())| (trie.as_deref(), k, v))
Unexecuted instantiation: _RNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChanges30storage_changes_iter_unordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges30storage_changes_iter_unordered00Ba_
246
0
        })
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges30storage_changes_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges30storage_changes_iter_unordered0B8_
247
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges30storage_changes_iter_unordered
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges30storage_changes_iter_unordered
248
249
    /// Returns an iterator over the list of all changes performed to the tries (main trie and
250
    /// child tries included).
251
    ///
252
    /// Returns `Some` if and only if [`Config::calculate_trie_changes`] was `true` or if the
253
    /// [`StorageChanges`] was created using [`StorageChanges::empty`].
254
0
    pub fn trie_changes_iter_ordered(
255
0
        &self,
256
0
    ) -> Option<impl Iterator<Item = (Option<&[u8]>, &[Nibble], TrieChange)>> {
257
0
        if !self.calculate_trie_changes {
258
0
            return None;
259
0
        }
260
261
        Some(
262
0
            self.inner
263
0
                .tries_changes
264
0
                .iter()
265
0
                .map(|((child_trie, key), change)| {
266
0
                    let change = match change {
267
0
                        PendingStorageChangesTrieNode::Removed => TrieChange::Remove,
268
                        PendingStorageChangesTrieNode::InsertUpdate {
269
0
                            new_merkle_value,
270
0
                            partial_key,
271
0
                            children_merkle_values,
272
                        } => {
273
0
                            debug_assert!(key.ends_with(partial_key));
274
275
0
                            let new_storage_value = if key.len() % 2 == 0 {
276
0
                                let key_bytes =
277
0
                                    trie::nibbles_to_bytes_truncate(key.iter().copied())
278
0
                                        .collect::<Vec<_>>();
279
0
                                match self
280
0
                                    .inner
281
0
                                    .trie_diffs
282
0
                                    .get(child_trie)
283
0
                                    .and_then(|diff| diff.diff_get(&key_bytes))
Unexecuted instantiation: _RNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered00CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered00CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered00Cs4VrkfB1pvQ3_25json_rpc_general_requests
284
                                {
285
0
                                    None => TrieChangeStorageValue::Unmodified,
286
0
                                    Some((new_value, ())) => {
287
0
                                        TrieChangeStorageValue::Modified { new_value }
288
                                    }
289
                                }
290
                            } else {
291
0
                                TrieChangeStorageValue::Unmodified
292
                            };
293
294
0
                            let children_merkle_values = <Box<[_; 16]>>::try_from(
295
0
                                children_merkle_values
296
0
                                    .iter()
297
0
                                    .map(|child| child.as_ref().map(|mv| &mv[..]))
Unexecuted instantiation: _RNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered0s_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered0s_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered0s_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered0s_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChanges25trie_changes_iter_ordered0s_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCNCNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_14StorageChanges25trie_changes_iter_ordered0s_00Bc_
Unexecuted instantiation: _RNCNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChanges25trie_changes_iter_ordered0s_00CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChanges25trie_changes_iter_ordered0s_00Bc_
Unexecuted instantiation: _RNCNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChanges25trie_changes_iter_ordered0s_00CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNCNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChanges25trie_changes_iter_ordered0s_00Cs4VrkfB1pvQ3_25json_rpc_general_requests
298
0
                                    .collect::<Box<[_]>>(),
299
                            )
300
0
                            .unwrap();
301
302
0
                            TrieChange::InsertUpdate {
303
0
                                new_merkle_value,
304
0
                                partial_key,
305
0
                                children_merkle_values,
306
0
                                new_storage_value,
307
0
                            }
308
                        }
309
                    };
310
311
0
                    (child_trie.as_deref(), &key[..], change)
312
0
                }),
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChanges25trie_changes_iter_ordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges25trie_changes_iter_ordered0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges25trie_changes_iter_ordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges25trie_changes_iter_ordered0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChanges25trie_changes_iter_ordered0Cs4VrkfB1pvQ3_25json_rpc_general_requests
313
        )
314
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges25trie_changes_iter_ordered
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges25trie_changes_iter_ordered
315
316
    /// Returns a diff of the main trie.
317
    // TODO: weird API, necessary to turn this object back to a value for Config::storage_changes
318
3
    pub fn into_main_trie_diff(mut self) -> storage_diff::TrieDiff {
319
3
        self.inner
320
3
            .trie_diffs
321
3
            .remove(&None)
322
3
            .unwrap_or(storage_diff::TrieDiff::empty())
323
3
    }
_RNvMNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB2_14StorageChanges19into_main_trie_diff
Line
Count
Source
318
3
    pub fn into_main_trie_diff(mut self) -> storage_diff::TrieDiff {
319
3
        self.inner
320
3
            .trie_diffs
321
3
            .remove(&None)
322
3
            .unwrap_or(storage_diff::TrieDiff::empty())
323
3
    }
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB2_14StorageChanges19into_main_trie_diff
324
}
325
326
impl fmt::Debug for StorageChanges {
327
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
328
0
        if let Some(trie_changes) = self.trie_changes_iter_ordered() {
329
0
            f.debug_map()
330
0
                .entries(trie_changes.map(|(child_trie, key, change)| {
331
0
                    let mut key_str = key
332
0
                        .iter()
333
0
                        .copied()
334
0
                        .map(|n| format!("{:x}", n))
Unexecuted instantiation: _RNCNCNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt00Bc_
Unexecuted instantiation: _RNCNCNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt00Bc_
335
0
                        .collect::<String>();
336
0
                    if key_str.is_empty() {
337
0
                        key_str = "∅".to_owned();
338
0
                    }
339
340
0
                    let key = match child_trie {
341
0
                        Some(ct) => format!(
342
0
                            "<{}>:{}",
343
0
                            if ct.is_empty() {
344
0
                                "∅".to_string()
345
                            } else {
346
0
                                hex::encode(ct)
347
                            },
348
                            key_str
349
                        ),
350
0
                        None => format!("<main>:{}", key_str),
351
                    };
352
353
0
                    (key, change)
354
0
                }))
Unexecuted instantiation: _RNCNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt0Ba_
Unexecuted instantiation: _RNCNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt0Ba_
355
0
                .finish()
356
        } else {
357
0
            f.debug_map()
358
0
                .entries(self.inner.trie_diffs.iter().flat_map(|(child_trie, diff)| {
359
0
                    diff.diff_iter_unordered().map(move |(key, value, _)| {
360
0
                        let mut key_str = key
361
0
                            .iter()
362
0
                            .copied()
363
0
                            .map(|n| format!("{:x}", n))
Unexecuted instantiation: _RNCNCNCNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtBa_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_000Be_
Unexecuted instantiation: _RNCNCNCNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_000Be_
364
0
                            .collect::<String>();
365
0
                        if key_str.is_empty() {
366
0
                            key_str = "∅".to_owned();
367
0
                        }
368
369
0
                        let key = match child_trie {
370
0
                            Some(ct) => format!(
371
0
                                "<{}>:{}",
372
0
                                if ct.is_empty() {
373
0
                                    "∅".to_string()
374
                                } else {
375
0
                                    hex::encode(ct)
376
                                },
377
                                key_str
378
                            ),
379
0
                            None => format!("<main>:{}", key_str),
380
                        };
381
382
0
                        let change = if let Some(value) = value {
383
0
                            hex::encode(value)
384
                        } else {
385
0
                            "<deleted>".into()
386
                        };
387
388
0
                        (key, change)
389
0
                    })
Unexecuted instantiation: _RNCNCNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_00Bc_
Unexecuted instantiation: _RNCNCNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_00Bc_
390
0
                }))
Unexecuted instantiation: _RNCNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_0Ba_
Unexecuted instantiation: _RNCNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_0Ba_
391
0
                .finish()
392
        }
393
0
    }
Unexecuted instantiation: _RNvXs_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB4_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB4_14StorageChangesNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
394
}
395
396
#[derive(Clone)]
397
pub enum TrieChange<'a> {
398
    /// Trie node is either newly-created, or already existed and has a new Merkle value.
399
    InsertUpdate {
400
        /// New Merkle value associated to this trie node. Always inferior or equal to 32 bytes.
401
        new_merkle_value: &'a [u8],
402
        partial_key: &'a [Nibble],
403
        children_merkle_values: Box<[Option<&'a [u8]>; 16]>,
404
        /// Change to the storage value of that trie node.
405
        new_storage_value: TrieChangeStorageValue<'a>,
406
    },
407
    /// Trie node is removed.
408
    Remove,
409
}
410
411
impl<'a> fmt::Debug for TrieChange<'a> {
412
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413
0
        match self {
414
0
            TrieChange::Remove => f.debug_tuple("Remove").finish(),
415
            TrieChange::InsertUpdate {
416
0
                new_merkle_value,
417
0
                partial_key,
418
0
                children_merkle_values,
419
0
                new_storage_value,
420
0
            } => f
421
0
                .debug_struct("InsertUpdate")
422
0
                .field("new_merkle_value", &hex::encode(new_merkle_value))
423
0
                .field(
424
0
                    "partial_key",
425
0
                    &partial_key
426
0
                        .iter()
427
0
                        .map(|n| format!("{:x}", n))
Unexecuted instantiation: _RNCNvXs0_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt0Bb_
Unexecuted instantiation: _RNCNvXs0_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt0Bb_
428
0
                        .collect::<String>(),
429
                )
430
0
                .field(
431
0
                    "children_merkle_values",
432
0
                    &children_merkle_values
433
0
                        .iter()
434
0
                        .map(|child| match child {
435
0
                            Some(child) => hex::encode(child),
436
0
                            None => "∅".to_string(),
437
0
                        })
Unexecuted instantiation: _RNCNvXs0_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_0Bb_
Unexecuted instantiation: _RNCNvXs0_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmts_0Bb_
438
0
                        .collect::<Vec<_>>()
439
0
                        .join(","),
440
                )
441
0
                .field("new_storage_value", new_storage_value)
442
0
                .finish(),
443
        }
444
0
    }
Unexecuted instantiation: _RNvXs0_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs0_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_10TrieChangeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
445
}
446
447
#[derive(Clone)]
448
pub enum TrieChangeStorageValue<'a> {
449
    Unmodified,
450
    Modified { new_value: Option<&'a [u8]> },
451
}
452
453
impl<'a> fmt::Debug for TrieChangeStorageValue<'a> {
454
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
455
0
        match self {
456
0
            TrieChangeStorageValue::Unmodified => f.debug_tuple("Unmodified").finish(),
457
            TrieChangeStorageValue::Modified { new_value: None } => {
458
0
                f.debug_tuple("Modified").field(&"<deleted>").finish()
459
            }
460
            TrieChangeStorageValue::Modified {
461
0
                new_value: Some(new_value),
462
0
            } => f
463
0
                .debug_tuple("Modified")
464
0
                .field(&hex::encode(new_value))
465
0
                .finish(),
466
        }
467
0
    }
Unexecuted instantiation: _RNvXs1_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_22TrieChangeStorageValueNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs1_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_22TrieChangeStorageValueNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
468
}
469
470
/// Function execution has succeeded. Contains the return value of the call.
471
pub struct SuccessVirtualMachine(host::Finished);
472
473
impl SuccessVirtualMachine {
474
    /// Returns the value the called function has returned.
475
133
    pub fn value(&self) -> impl AsRef<[u8]> {
476
133
        self.0.value()
477
133
    }
_RNvMs2_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachine5value
Line
Count
Source
475
6
    pub fn value(&self) -> impl AsRef<[u8]> {
476
6
        self.0.value()
477
6
    }
_RNvMs2_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachine5value
Line
Count
Source
475
127
    pub fn value(&self) -> impl AsRef<[u8]> {
476
127
        self.0.value()
477
127
    }
478
479
    /// Turns the virtual machine back into a prototype.
480
132
    pub fn into_prototype(self) -> host::HostVmPrototype {
481
132
        self.0.into_prototype()
482
132
    }
_RNvMs2_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachine14into_prototype
Line
Count
Source
480
6
    pub fn into_prototype(self) -> host::HostVmPrototype {
481
6
        self.0.into_prototype()
482
6
    }
_RNvMs2_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachine14into_prototype
Line
Count
Source
480
126
    pub fn into_prototype(self) -> host::HostVmPrototype {
481
126
        self.0.into_prototype()
482
126
    }
483
}
484
485
impl fmt::Debug for SuccessVirtualMachine {
486
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
487
0
        f.debug_tuple("SuccessVirtualMachine").finish()
488
0
    }
Unexecuted instantiation: _RNvXs3_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachineNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs3_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SuccessVirtualMachineNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
489
}
490
491
/// Error that can happen during the execution.
492
#[derive(Debug, derive_more::Display, derive_more::Error)]
493
#[display("{detail}")]
494
pub struct Error {
495
    /// Exact error that happened.
496
    #[error(source)]
497
    pub detail: ErrorDetail,
498
    /// Prototype of the virtual machine that was passed through [`Config::virtual_machine`].
499
    pub prototype: host::HostVmPrototype,
500
}
501
502
/// Current state of the execution.
503
#[must_use]
504
pub enum RuntimeCall {
505
    /// Execution is over.
506
    Finished(Result<Success, Error>),
507
    /// Loading a storage value is required in order to continue.
508
    StorageGet(StorageGet),
509
    /// Obtaining the Merkle value of the closest descendant of a trie node is required in order
510
    /// to continue.
511
    ClosestDescendantMerkleValue(ClosestDescendantMerkleValue),
512
    /// Fetching the key that follows a given one is required in order to continue.
513
    NextKey(NextKey),
514
    /// Verifying whether a signature is correct is required in order to continue.
515
    SignatureVerification(SignatureVerification),
516
    /// Runtime would like to emit some log.
517
    LogEmit(LogEmit),
518
    /// Setting an offchain storage value is required in order to continue.
519
    ///
520
    /// Contrary to [`OffchainContext::StorageSet`], this variant is allowed to happen
521
    /// outside of offchain workers.
522
    OffchainStorageSet(OffchainStorageSet),
523
    /// Functions that can only be called within the context of an offchain worker.
524
    Offchain(OffchainContext),
525
}
526
527
impl RuntimeCall {
528
    /// Cancels execution of the virtual machine and returns back the prototype.
529
0
    pub fn into_prototype(self) -> host::HostVmPrototype {
530
0
        match self {
531
0
            RuntimeCall::Finished(Ok(inner)) => inner.virtual_machine.into_prototype(),
532
0
            RuntimeCall::Finished(Err(inner)) => inner.prototype,
533
0
            RuntimeCall::StorageGet(inner) => inner.inner.vm.into_prototype(),
534
0
            RuntimeCall::ClosestDescendantMerkleValue(inner) => inner.inner.vm.into_prototype(),
535
0
            RuntimeCall::NextKey(inner) => inner.inner.vm.into_prototype(),
536
0
            RuntimeCall::SignatureVerification(inner) => inner.inner.vm.into_prototype(),
537
0
            RuntimeCall::LogEmit(inner) => inner.inner.vm.into_prototype(),
538
0
            RuntimeCall::OffchainStorageSet(inner) => inner.inner.vm.into_prototype(),
539
0
            RuntimeCall::Offchain(inner) => inner.into_prototype(),
540
        }
541
0
    }
Unexecuted instantiation: _RNvMs4_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_11RuntimeCall14into_prototype
Unexecuted instantiation: _RNvMs4_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_11RuntimeCall14into_prototype
542
}
543
544
pub enum OffchainContext {
545
    /// Loading an offchain storage value is required in order to continue.
546
    StorageGet(OffchainStorageGet),
547
    /// Setting an offchain storage value is required in order to continue.
548
    ///
549
    /// Contrary to [`RuntimeCall::OffchainStorageSet`], this variant can only happen in offchain
550
    /// workers.
551
    StorageSet(OffchainStorageCompareSet),
552
    /// Timestamp for offchain worker.
553
    Timestamp(OffchainTimestamp),
554
    /// Random seed for offchain worker.
555
    RandomSeed(OffchainRandomSeed),
556
    /// Submit transaction from offchain worker.
557
    SubmitTransaction(OffchainSubmitTransaction),
558
}
559
560
impl OffchainContext {
561
0
    pub fn into_prototype(self) -> host::HostVmPrototype {
562
0
        match self {
563
0
            OffchainContext::StorageGet(inner) => inner.inner.vm.into_prototype(),
564
0
            OffchainContext::StorageSet(inner) => inner.inner.vm.into_prototype(),
565
0
            OffchainContext::Timestamp(inner) => inner.inner.vm.into_prototype(),
566
0
            OffchainContext::RandomSeed(inner) => inner.inner.vm.into_prototype(),
567
0
            OffchainContext::SubmitTransaction(inner) => inner.inner.vm.into_prototype(),
568
        }
569
0
    }
Unexecuted instantiation: _RNvMs5_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_15OffchainContext14into_prototype
Unexecuted instantiation: _RNvMs5_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_15OffchainContext14into_prototype
570
}
571
572
/// Loading a storage value is required in order to continue.
573
#[must_use]
574
pub struct StorageGet {
575
    inner: Inner,
576
}
577
578
impl StorageGet {
579
    /// Returns the key whose value must be passed to [`StorageGet::inject_value`].
580
9.27k
    pub fn key(&self) -> impl AsRef<[u8]> {
581
        enum Three<A, B, C> {
582
            A(A),
583
            B(B),
584
            C(C),
585
        }
586
587
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
588
9.27k
            fn as_ref(&self) -> &[u8] {
589
9.27k
                match self {
590
2.22k
                    Three::A(a) => a.as_ref(),
591
8
                    Three::B(b) => b.as_ref(),
592
7.05k
                    Three::C(c) => c.as_ref(),
593
                }
594
9.27k
            }
_RNvXNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refBc_
Line
Count
Source
588
9.19k
            fn as_ref(&self) -> &[u8] {
589
9.19k
                match self {
590
2.13k
                    Three::A(a) => a.as_ref(),
591
8
                    Three::B(b) => b.as_ref(),
592
7.05k
                    Three::C(c) => c.as_ref(),
593
                }
594
9.19k
            }
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refCscoAnRPySggw_6author
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refCsfFWJyR6nd6r_17smoldot_full_node
_RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refBc_
Line
Count
Source
588
84
            fn as_ref(&self) -> &[u8] {
589
84
                match self {
590
84
                    Three::A(a) => a.as_ref(),
591
0
                    Three::B(b) => b.as_ref(),
592
0
                    Three::C(c) => c.as_ref(),
593
                }
594
84
            }
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refCsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet3keyINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB29_11Interpreter11read_memory12AccessOffsetB1X_EEB1s_INtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB1Y_E6as_refCs4VrkfB1pvQ3_25json_rpc_general_requests
595
        }
596
597
9.27k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
598
2.22k
            (host::HostVm::ExternalStorageGet(req), None) => Three::A(req.key()),
599
8
            (host::HostVm::ExternalStorageAppend(req), None) => Three::B(req.key()),
600
7.05k
            (_, Some((_, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
601
                // TODO: optimize?
602
49.3k
                let 
key_nibbles7.05k
=
value_request7.05k
.
key7.05k
().
fold7.05k
(
Vec::new7.05k
(), |mut a, b| {
603
49.3k
                    a.extend_from_slice(b.as_ref());
604
49.3k
                    a
605
49.3k
                });
_RNCNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_10StorageGet3key0Bb_
Line
Count
Source
602
49.3k
                let key_nibbles = value_request.key().fold(Vec::new(), |mut a, b| {
603
49.3k
                    a.extend_from_slice(b.as_ref());
604
49.3k
                    a
605
49.3k
                });
Unexecuted instantiation: _RNCNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_10StorageGet3key0Bb_
606
7.05k
                debug_assert_eq!(key_nibbles.len() % 2, 0);
607
7.05k
                Three::C(
608
7.05k
                    trie::nibbles_to_bytes_suffix_extend(key_nibbles.into_iter())
609
7.05k
                        .collect::<Vec<_>>(),
610
7.05k
                )
611
            }
612
613
            // We only create a `StorageGet` if the state is one of the above.
614
0
            _ => unreachable!(),
615
        }
616
9.27k
    }
_RNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_10StorageGet3key
Line
Count
Source
580
9.19k
    pub fn key(&self) -> impl AsRef<[u8]> {
581
        enum Three<A, B, C> {
582
            A(A),
583
            B(B),
584
            C(C),
585
        }
586
587
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
588
            fn as_ref(&self) -> &[u8] {
589
                match self {
590
                    Three::A(a) => a.as_ref(),
591
                    Three::B(b) => b.as_ref(),
592
                    Three::C(c) => c.as_ref(),
593
                }
594
            }
595
        }
596
597
9.19k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
598
2.13k
            (host::HostVm::ExternalStorageGet(req), None) => Three::A(req.key()),
599
8
            (host::HostVm::ExternalStorageAppend(req), None) => Three::B(req.key()),
600
7.05k
            (_, Some((_, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
601
                // TODO: optimize?
602
7.05k
                let key_nibbles = value_request.key().fold(Vec::new(), |mut a, b| {
603
                    a.extend_from_slice(b.as_ref());
604
                    a
605
                });
606
7.05k
                debug_assert_eq!(key_nibbles.len() % 2, 0);
607
7.05k
                Three::C(
608
7.05k
                    trie::nibbles_to_bytes_suffix_extend(key_nibbles.into_iter())
609
7.05k
                        .collect::<Vec<_>>(),
610
7.05k
                )
611
            }
612
613
            // We only create a `StorageGet` if the state is one of the above.
614
0
            _ => unreachable!(),
615
        }
616
9.19k
    }
_RNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_10StorageGet3key
Line
Count
Source
580
84
    pub fn key(&self) -> impl AsRef<[u8]> {
581
        enum Three<A, B, C> {
582
            A(A),
583
            B(B),
584
            C(C),
585
        }
586
587
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
588
            fn as_ref(&self) -> &[u8] {
589
                match self {
590
                    Three::A(a) => a.as_ref(),
591
                    Three::B(b) => b.as_ref(),
592
                    Three::C(c) => c.as_ref(),
593
                }
594
            }
595
        }
596
597
84
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
598
84
            (host::HostVm::ExternalStorageGet(req), None) => Three::A(req.key()),
599
0
            (host::HostVm::ExternalStorageAppend(req), None) => Three::B(req.key()),
600
0
            (_, Some((_, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
601
                // TODO: optimize?
602
0
                let key_nibbles = value_request.key().fold(Vec::new(), |mut a, b| {
603
                    a.extend_from_slice(b.as_ref());
604
                    a
605
                });
606
0
                debug_assert_eq!(key_nibbles.len() % 2, 0);
607
0
                Three::C(
608
0
                    trie::nibbles_to_bytes_suffix_extend(key_nibbles.into_iter())
609
0
                        .collect::<Vec<_>>(),
610
0
                )
611
            }
612
613
            // We only create a `StorageGet` if the state is one of the above.
614
0
            _ => unreachable!(),
615
        }
616
84
    }
617
618
    /// If `Some`, read from the given child trie. If `None`, read from the main trie.
619
449
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
620
        enum Three<A, B, C> {
621
            A(A),
622
            B(B),
623
            C(C),
624
        }
625
626
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
627
11
            fn as_ref(&self) -> &[u8] {
628
11
                match self {
629
6
                    Three::A(a) => a.as_ref(),
630
0
                    Three::B(b) => b.as_ref(),
631
5
                    Three::C(c) => c.as_ref(),
632
                }
633
11
            }
_RNvXNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refBc_
Line
Count
Source
627
11
            fn as_ref(&self) -> &[u8] {
628
11
                match self {
629
6
                    Three::A(a) => a.as_ref(),
630
0
                    Three::B(b) => b.as_ref(),
631
5
                    Three::C(c) => c.as_ref(),
632
                }
633
11
            }
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refCscoAnRPySggw_6author
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refCsfFWJyR6nd6r_17smoldot_full_node
Unexecuted instantiation: _RNvXININvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBb_10StorageGet10child_trie0pppEINtB5_5ThreepppEINtNtCs1p5UDGgVI4d_4core7convert5AsRefShE6as_refBf_
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refCsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNvXNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2h_11Interpreter11read_memory12AccessOffsetB25_EEB25_RINtNtCsaFPxhswmqCN_5alloc3vec3VechEEINtNtCs1p5UDGgVI4d_4core7convert5AsRefB26_E6as_refCs4VrkfB1pvQ3_25json_rpc_general_requests
634
        }
635
636
449
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
637
124
            (host::HostVm::ExternalStorageGet(req), None) => req.child_trie().map(Three::A),
638
7
            (host::HostVm::ExternalStorageAppend(req), None) => req.child_trie().map(Three::B),
639
318
            (_, Some((child_trie, trie_root_calculator::InProgress::StorageValue(_)))) => {
640
318
                child_trie.as_ref().map(Three::C)
641
            }
642
            // We only create a `StorageGet` if the state is one of the above.
643
0
            _ => unreachable!(),
644
        }
645
449
    }
_RNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_10StorageGet10child_trie
Line
Count
Source
619
449
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
620
        enum Three<A, B, C> {
621
            A(A),
622
            B(B),
623
            C(C),
624
        }
625
626
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
627
            fn as_ref(&self) -> &[u8] {
628
                match self {
629
                    Three::A(a) => a.as_ref(),
630
                    Three::B(b) => b.as_ref(),
631
                    Three::C(c) => c.as_ref(),
632
                }
633
            }
634
        }
635
636
449
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
637
124
            (host::HostVm::ExternalStorageGet(req), None) => req.child_trie().map(Three::A),
638
7
            (host::HostVm::ExternalStorageAppend(req), None) => req.child_trie().map(Three::B),
639
318
            (_, Some((child_trie, trie_root_calculator::InProgress::StorageValue(_)))) => {
640
318
                child_trie.as_ref().map(Three::C)
641
            }
642
            // We only create a `StorageGet` if the state is one of the above.
643
0
            _ => unreachable!(),
644
        }
645
449
    }
Unexecuted instantiation: _RNvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_10StorageGet10child_trie
646
647
    /// Injects the corresponding storage value.
648
697
    pub fn inject_value(
649
697
        mut self,
650
697
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
651
697
    ) -> RuntimeCall {
652
        // TODO: update the implementation to not require the folding here
653
697
        let value = value.map(|(value, version)| 
{486
654
486
            let value = value.fold(Vec::new(), |mut a, b| {
655
486
                a.extend_from_slice(b.as_ref());
656
486
                a
657
486
            });
_RNCNCINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00Be_
Line
Count
Source
654
402
            let value = value.fold(Vec::new(), |mut a, b| {
655
402
                a.extend_from_slice(b.as_ref());
656
402
                a
657
402
            });
Unexecuted instantiation: _RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00CsfFWJyR6nd6r_17smoldot_full_node
_RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00Be_
Line
Count
Source
654
42
            let value = value.fold(Vec::new(), |mut a, b| {
655
42
                a.extend_from_slice(b.as_ref());
656
42
                a
657
42
            });
_RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00Be_
Line
Count
Source
654
42
            let value = value.fold(Vec::new(), |mut a, b| {
655
42
                a.extend_from_slice(b.as_ref());
656
42
                a
657
42
            });
Unexecuted instantiation: _RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBa_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1s_EE00Cs4VrkfB1pvQ3_25json_rpc_general_requests
658
486
            (value, version)
659
486
        });
_RNCINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0Bc_
Line
Count
Source
653
402
        let value = value.map(|(value, version)| {
654
402
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
402
            (value, version)
659
402
        });
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0CsfFWJyR6nd6r_17smoldot_full_node
_RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0Bc_
Line
Count
Source
653
42
        let value = value.map(|(value, version)| {
654
42
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
42
            (value, version)
659
42
        });
_RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0Bc_
Line
Count
Source
653
42
        let value = value.map(|(value, version)| {
654
42
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
42
            (value, version)
659
42
        });
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EE0Cs4VrkfB1pvQ3_25json_rpc_general_requests
660
661
697
        match (self.inner.vm, self.inner.root_calculation.take()) {
662
251
            (host::HostVm::ExternalStorageGet(req), None) => {
663
                // TODO: should actually report the offset and max_size in the API
664
251
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &
v[..]177
));
_RNCINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0Bc_
Line
Count
Source
664
93
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0CsfFWJyR6nd6r_17smoldot_full_node
_RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0Bc_
Line
Count
Source
664
42
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
_RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0Bc_
Line
Count
Source
664
42
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
665
            }
666
8
            (host::HostVm::ExternalStorageAppend(req), None) => {
667
                // TODO: could be less overhead?
668
8
                let trie = self
669
8
                    .inner
670
8
                    .pending_storage_changes
671
8
                    .trie_diffs
672
8
                    .entry(req.child_trie().map(|ct| 
ct.as_ref()0
.
to_vec0
()))
Unexecuted instantiation: _RNCINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueppEs0_0Bc_
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueppEs0_0Bc_
673
8
                    .or_insert(storage_diff::TrieDiff::empty());
674
675
                // TODO: could be less overhead?
676
8
                let mut value = value.map(|(v, _)| v).unwrap_or_default();
677
8
                append_to_storage_value(&mut value, req.value().as_ref());
678
8
                trie.diff_insert(req.key().as_ref().to_vec(), value, ());
679
680
8
                self.inner.vm = req.resume();
681
            }
682
438
            (vm, Some((trie, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
683
438
                self.inner.vm = vm;
684
438
                self.inner.root_calculation = Some((
685
438
                    trie,
686
438
                    value_request.inject_value(value.as_ref().map(|(v, vers)| (
&v[..]308
,
*vers308
))),
_RNCINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0Bc_
Line
Count
Source
686
308
                    value_request.inject_value(value.as_ref().map(|(v, vers)| (&v[..], *vers))),
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0CsfFWJyR6nd6r_17smoldot_full_node
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0Bc_
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0Bc_
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1q_EEs2_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
687
                ));
688
            }
689
690
            // We only create a `StorageGet` if the state is one of the above.
691
0
            _ => unreachable!(),
692
        };
693
694
697
        self.inner.run()
695
697
    }
_RINvMs6_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EEBa_
Line
Count
Source
648
613
    pub fn inject_value(
649
613
        mut self,
650
613
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
651
613
    ) -> RuntimeCall {
652
        // TODO: update the implementation to not require the folding here
653
613
        let value = value.map(|(value, version)| {
654
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
            (value, version)
659
        });
660
661
613
        match (self.inner.vm, self.inner.root_calculation.take()) {
662
167
            (host::HostVm::ExternalStorageGet(req), None) => {
663
                // TODO: should actually report the offset and max_size in the API
664
167
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
665
            }
666
8
            (host::HostVm::ExternalStorageAppend(req), None) => {
667
                // TODO: could be less overhead?
668
8
                let trie = self
669
8
                    .inner
670
8
                    .pending_storage_changes
671
8
                    .trie_diffs
672
8
                    .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
673
8
                    .or_insert(storage_diff::TrieDiff::empty());
674
675
                // TODO: could be less overhead?
676
8
                let mut value = value.map(|(v, _)| v).unwrap_or_default();
677
8
                append_to_storage_value(&mut value, req.value().as_ref());
678
8
                trie.diff_insert(req.key().as_ref().to_vec(), value, ());
679
680
8
                self.inner.vm = req.resume();
681
            }
682
438
            (vm, Some((trie, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
683
438
                self.inner.vm = vm;
684
438
                self.inner.root_calculation = Some((
685
438
                    trie,
686
438
                    value_request.inject_value(value.as_ref().map(|(v, vers)| (&v[..], *vers))),
687
                ));
688
            }
689
690
            // We only create a `StorageGet` if the state is one of the above.
691
0
            _ => unreachable!(),
692
        };
693
694
613
        self.inner.run()
695
613
    }
Unexecuted instantiation: _RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EECscoAnRPySggw_6author
Unexecuted instantiation: _RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EECsfFWJyR6nd6r_17smoldot_full_node
_RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EEBa_
Line
Count
Source
648
42
    pub fn inject_value(
649
42
        mut self,
650
42
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
651
42
    ) -> RuntimeCall {
652
        // TODO: update the implementation to not require the folding here
653
42
        let value = value.map(|(value, version)| {
654
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
            (value, version)
659
        });
660
661
42
        match (self.inner.vm, self.inner.root_calculation.take()) {
662
42
            (host::HostVm::ExternalStorageGet(req), None) => {
663
                // TODO: should actually report the offset and max_size in the API
664
42
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
665
            }
666
0
            (host::HostVm::ExternalStorageAppend(req), None) => {
667
                // TODO: could be less overhead?
668
0
                let trie = self
669
0
                    .inner
670
0
                    .pending_storage_changes
671
0
                    .trie_diffs
672
0
                    .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
673
0
                    .or_insert(storage_diff::TrieDiff::empty());
674
675
                // TODO: could be less overhead?
676
0
                let mut value = value.map(|(v, _)| v).unwrap_or_default();
677
0
                append_to_storage_value(&mut value, req.value().as_ref());
678
0
                trie.diff_insert(req.key().as_ref().to_vec(), value, ());
679
680
0
                self.inner.vm = req.resume();
681
            }
682
0
            (vm, Some((trie, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
683
0
                self.inner.vm = vm;
684
0
                self.inner.root_calculation = Some((
685
0
                    trie,
686
0
                    value_request.inject_value(value.as_ref().map(|(v, vers)| (&v[..], *vers))),
687
                ));
688
            }
689
690
            // We only create a `StorageGet` if the state is one of the above.
691
0
            _ => unreachable!(),
692
        };
693
694
42
        self.inner.run()
695
42
    }
_RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EEBa_
Line
Count
Source
648
42
    pub fn inject_value(
649
42
        mut self,
650
42
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>,
651
42
    ) -> RuntimeCall {
652
        // TODO: update the implementation to not require the folding here
653
42
        let value = value.map(|(value, version)| {
654
            let value = value.fold(Vec::new(), |mut a, b| {
655
                a.extend_from_slice(b.as_ref());
656
                a
657
            });
658
            (value, version)
659
        });
660
661
42
        match (self.inner.vm, self.inner.root_calculation.take()) {
662
42
            (host::HostVm::ExternalStorageGet(req), None) => {
663
                // TODO: should actually report the offset and max_size in the API
664
42
                self.inner.vm = req.resume_full_value(value.as_ref().map(|(v, _)| &v[..]));
665
            }
666
0
            (host::HostVm::ExternalStorageAppend(req), None) => {
667
                // TODO: could be less overhead?
668
0
                let trie = self
669
0
                    .inner
670
0
                    .pending_storage_changes
671
0
                    .trie_diffs
672
0
                    .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
673
0
                    .or_insert(storage_diff::TrieDiff::empty());
674
675
                // TODO: could be less overhead?
676
0
                let mut value = value.map(|(v, _)| v).unwrap_or_default();
677
0
                append_to_storage_value(&mut value, req.value().as_ref());
678
0
                trie.diff_insert(req.key().as_ref().to_vec(), value, ());
679
680
0
                self.inner.vm = req.resume();
681
            }
682
0
            (vm, Some((trie, trie_root_calculator::InProgress::StorageValue(value_request)))) => {
683
0
                self.inner.vm = vm;
684
0
                self.inner.root_calculation = Some((
685
0
                    trie,
686
0
                    value_request.inject_value(value.as_ref().map(|(v, vers)| (&v[..], *vers))),
687
                ));
688
            }
689
690
            // We only create a `StorageGet` if the state is one of the above.
691
0
            _ => unreachable!(),
692
        };
693
694
42
        self.inner.run()
695
42
    }
Unexecuted instantiation: _RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EECs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EECsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RINvMs6_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_10StorageGet12inject_valueRShINtNtNtNtCs1p5UDGgVI4d_4core4iter7sources4once4OnceB1o_EECs4VrkfB1pvQ3_25json_rpc_general_requests
696
}
697
698
/// Fetching the key that follows a given one is required in order to continue.
699
#[must_use]
700
pub struct NextKey {
701
    inner: Inner,
702
703
    /// If `Some`, ask for the key inside of this field rather than the one of `inner`.
704
    key_overwrite: Option<Vec<u8>>,
705
706
    /// Number of keys removed. Used only to implement clearing a prefix, otherwise stays at 0.
707
    keys_removed_so_far: u32,
708
}
709
710
impl NextKey {
711
    /// Returns the key whose next key must be passed back.
712
16.4k
    pub fn key(&self) -> impl Iterator<Item = Nibble> {
713
16.4k
        if let Some(
key_overwrite15
) = &self.key_overwrite {
714
15
            return either::Left(trie::bytes_to_nibbles(key_overwrite.iter().copied()));
715
16.4k
        }
716
717
        either::Right(
718
16.4k
            match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
719
1
                (host::HostVm::ExternalStorageNextKey(req), _) => {
720
1
                    either::Left(trie::bytes_to_nibbles(util::as_ref_iter(req.key())))
721
                }
722
723
16.4k
                (_, Some((_, trie_root_calculator::InProgress::ClosestDescendant(req)))) => {
724
16.4k
                    either::Right(req.key().flat_map(util::as_ref_iter))
725
                }
726
727
                // Note that in the case `ExternalStorageClearPrefix`, `key_overwrite` is
728
                // always `Some`.
729
0
                _ => unreachable!(),
730
            },
731
        )
732
16.4k
    }
_RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7NextKey3key
Line
Count
Source
712
16.4k
    pub fn key(&self) -> impl Iterator<Item = Nibble> {
713
16.4k
        if let Some(
key_overwrite15
) = &self.key_overwrite {
714
15
            return either::Left(trie::bytes_to_nibbles(key_overwrite.iter().copied()));
715
16.4k
        }
716
717
        either::Right(
718
16.4k
            match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
719
1
                (host::HostVm::ExternalStorageNextKey(req), _) => {
720
1
                    either::Left(trie::bytes_to_nibbles(util::as_ref_iter(req.key())))
721
                }
722
723
16.4k
                (_, Some((_, trie_root_calculator::InProgress::ClosestDescendant(req)))) => {
724
16.4k
                    either::Right(req.key().flat_map(util::as_ref_iter))
725
                }
726
727
                // Note that in the case `ExternalStorageClearPrefix`, `key_overwrite` is
728
                // always `Some`.
729
0
                _ => unreachable!(),
730
            },
731
        )
732
16.4k
    }
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7NextKey3key
733
734
    /// If `Some`, read from the given child trie. If `None`, read from the main trie.
735
12.9k
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
736
        enum Three<A, B, C> {
737
            A(A),
738
            B(B),
739
            C(C),
740
        }
741
742
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
743
144
            fn as_ref(&self) -> &[u8] {
744
144
                match self {
745
0
                    Three::A(a) => a.as_ref(),
746
140
                    Three::B(b) => b.as_ref(),
747
4
                    Three::C(c) => c.as_ref(),
748
                }
749
144
            }
_RNvXNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refBc_
Line
Count
Source
743
144
            fn as_ref(&self) -> &[u8] {
744
144
                match self {
745
0
                    Three::A(a) => a.as_ref(),
746
140
                    Three::B(b) => b.as_ref(),
747
4
                    Three::C(c) => c.as_ref(),
748
                }
749
144
            }
Unexecuted instantiation: _RNvXNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refCscoAnRPySggw_6author
Unexecuted instantiation: _RNvXNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refCsfFWJyR6nd6r_17smoldot_full_node
Unexecuted instantiation: _RNvXININvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtBb_7NextKey10child_trie0pppEINtB5_5ThreepppEINtNtCs1p5UDGgVI4d_4core7convert5AsRefShE6as_refBf_
Unexecuted instantiation: _RNvXNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvXNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refCsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNvXNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10child_trieINtB2_5ThreeINtCsfDbbEgL1j7J_6either6EitherRShINtNvMs5_NtNtBa_2vm11interpreterNtB2d_11Interpreter11read_memory12AccessOffsetB21_EERINtNtCsaFPxhswmqCN_5alloc3vec3VechEB1w_EINtNtCs1p5UDGgVI4d_4core7convert5AsRefB22_E6as_refCs4VrkfB1pvQ3_25json_rpc_general_requests
750
        }
751
752
12.9k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
753
2
            (host::HostVm::ExternalStorageNextKey(req), _) => req.child_trie().map(Three::A),
754
12.9k
            (_, Some((child_trie, _))) => child_trie.as_ref().map(Three::B),
755
28
            (host::HostVm::ExternalStorageClearPrefix(req), _) => req.child_trie().map(Three::C),
756
0
            _ => unreachable!(),
757
        }
758
12.9k
    }
_RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7NextKey10child_trie
Line
Count
Source
735
12.9k
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
736
        enum Three<A, B, C> {
737
            A(A),
738
            B(B),
739
            C(C),
740
        }
741
742
        impl<A: AsRef<[u8]>, B: AsRef<[u8]>, C: AsRef<[u8]>> AsRef<[u8]> for Three<A, B, C> {
743
            fn as_ref(&self) -> &[u8] {
744
                match self {
745
                    Three::A(a) => a.as_ref(),
746
                    Three::B(b) => b.as_ref(),
747
                    Three::C(c) => c.as_ref(),
748
                }
749
            }
750
        }
751
752
12.9k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
753
2
            (host::HostVm::ExternalStorageNextKey(req), _) => req.child_trie().map(Three::A),
754
12.9k
            (_, Some((child_trie, _))) => child_trie.as_ref().map(Three::B),
755
28
            (host::HostVm::ExternalStorageClearPrefix(req), _) => req.child_trie().map(Three::C),
756
0
            _ => unreachable!(),
757
        }
758
12.9k
    }
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7NextKey10child_trie
759
760
    /// If `true`, then the provided value must the one superior or equal to the requested key.
761
    /// If `false`, then the provided value must be strictly superior to the requested key.
762
8.25k
    pub fn or_equal(&self) -> bool {
763
8.25k
        (
matches!8.23k
(self.inner.vm, host::HostVm::ExternalStorageClearPrefix(_))
764
15
            && self.keys_removed_so_far == 0)
765
8.24k
            || self.inner.root_calculation.is_some()
766
8.25k
    }
_RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7NextKey8or_equal
Line
Count
Source
762
8.25k
    pub fn or_equal(&self) -> bool {
763
8.25k
        (
matches!8.23k
(self.inner.vm, host::HostVm::ExternalStorageClearPrefix(_))
764
15
            && self.keys_removed_so_far == 0)
765
8.24k
            || self.inner.root_calculation.is_some()
766
8.25k
    }
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7NextKey8or_equal
767
768
    /// If `true`, then the search must include both branch nodes and storage nodes. If `false`,
769
    /// the search only covers storage nodes.
770
8.25k
    pub fn branch_nodes(&self) -> bool {
771
8.25k
        self.inner.root_calculation.is_some()
772
8.25k
    }
_RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7NextKey12branch_nodes
Line
Count
Source
770
8.25k
    pub fn branch_nodes(&self) -> bool {
771
8.25k
        self.inner.root_calculation.is_some()
772
8.25k
    }
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7NextKey12branch_nodes
773
774
    /// Returns the prefix the next key must start with. If the next key doesn't start with the
775
    /// given prefix, then `None` should be provided.
776
8.25k
    pub fn prefix(&self) -> impl Iterator<Item = Nibble> {
777
8.25k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
778
15
            (host::HostVm::ExternalStorageClearPrefix(req), _) => {
779
15
                either::Left(trie::bytes_to_nibbles(util::as_ref_iter(req.prefix())))
780
            }
781
8.23k
            (_, Some(_)) => either::Right(either::Left(self.key())),
782
1
            _ => either::Right(either::Right(iter::empty())),
783
        }
784
8.25k
    }
_RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7NextKey6prefix
Line
Count
Source
776
8.25k
    pub fn prefix(&self) -> impl Iterator<Item = Nibble> {
777
8.25k
        match (&self.inner.vm, self.inner.root_calculation.as_ref()) {
778
15
            (host::HostVm::ExternalStorageClearPrefix(req), _) => {
779
15
                either::Left(trie::bytes_to_nibbles(util::as_ref_iter(req.prefix())))
780
            }
781
8.23k
            (_, Some(_)) => either::Right(either::Left(self.key())),
782
1
            _ => either::Right(either::Right(iter::empty())),
783
        }
784
8.25k
    }
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7NextKey6prefix
785
786
    /// Injects the key.
787
    ///
788
    /// # Panic
789
    ///
790
    /// Panics if the key passed as parameter isn't strictly superior to the requested key.
791
    /// Panics if the key passed as parameter doesn't start with the requested prefix.
792
    ///
793
8.25k
    pub fn inject_key(mut self, key: Option<impl Iterator<Item = Nibble>>) -> RuntimeCall {
794
8.25k
        match (self.inner.vm, self.inner.root_calculation.take()) {
795
1
            (host::HostVm::ExternalStorageNextKey(req), None) => {
796
1
                let key =
797
1
                    key.map(|key| trie::nibbles_to_bytes_suffix_extend(key).collect::<Vec<_>>());
Unexecuted instantiation: _RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE0Bc_
_RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyNtNtNtBc_4trie13branch_search21BranchTrieNodeKeyIterE0Bc_
Line
Count
Source
797
1
                    key.map(|key| trie::nibbles_to_bytes_suffix_extend(key).collect::<Vec<_>>());
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEE0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EE0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EE0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtNtCsfFWJyR6nd6r_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0se_00EE0B3a_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNvMNtNtBc_8database11full_sqliteNtB35_18SqliteFullDatabase20to_chain_informations_00EE0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEE0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterRShEE0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEE0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EE0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EE0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEE0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EE0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EE0Cs4VrkfB1pvQ3_25json_rpc_general_requests
798
799
1
                let trie = self
800
1
                    .inner
801
1
                    .pending_storage_changes
802
1
                    .trie_diffs
803
1
                    .get(&req.child_trie().map(|ct| 
ct.as_ref()0
.
to_owned0
())); // TODO: overhead
Unexecuted instantiation: _RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEs_0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyNtNtNtBc_4trie13branch_search21BranchTrieNodeKeyIterEs_0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtNtCsfFWJyR6nd6r_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0se_00EEs_0B3a_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNvMNtNtBc_8database11full_sqliteNtB35_18SqliteFullDatabase20to_chain_informations_00EEs_0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterRShEEs_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
804
805
1
                let empty = storage_diff::TrieDiff::empty(); // TODO: weird
806
1
                let search = {
807
1
                    let req_key = req.key();
808
1
                    let requested_key = if let Some(
key_overwrite0
) = &self.key_overwrite {
809
0
                        &key_overwrite[..]
810
                    } else {
811
1
                        req_key.as_ref()
812
                    };
813
                    // TODO: this code is a bit weird
814
1
                    trie.unwrap_or(&empty)
815
1
                        .storage_next_key(requested_key, key.as_deref(), false)
816
                };
817
818
1
                match search {
819
1
                    storage_diff::StorageNextKey::Found(k) => {
820
1
                        self.inner.vm = req.resume(k);
821
1
                    }
822
0
                    storage_diff::StorageNextKey::NextOf(next) => {
823
0
                        let key_overwrite = Some(next.to_owned());
824
0
                        self.inner.vm = host::HostVm::ExternalStorageNextKey(req);
825
0
                        return RuntimeCall::NextKey(NextKey {
826
0
                            inner: self.inner,
827
0
                            key_overwrite,
828
0
                            keys_removed_so_far: 0,
829
0
                        });
830
                    }
831
                }
832
            }
833
834
15
            (host::HostVm::ExternalStorageClearPrefix(req), None) => {
835
                // TODO: there's some trickiness regarding the behavior w.r.t keys only in the overlay; figure out
836
837
15
                if let Some(
key9
) = key {
838
9
                    let key = trie::nibbles_to_bytes_suffix_extend(key).collect::<Vec<_>>();
839
9
                    assert!(key.starts_with(req.prefix().as_ref()));
840
841
                    // TODO: /!\ must clear keys from overlay as well
842
843
9
                    if req
844
9
                        .max_keys_to_remove()
845
9
                        .map_or(false, |max| self.keys_removed_so_far >= max)
Unexecuted instantiation: _RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEs0_0Bc_
_RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyNtNtNtBc_4trie13branch_search21BranchTrieNodeKeyIterEs0_0Bc_
Line
Count
Source
845
9
                        .map_or(false, |max| self.keys_removed_so_far >= max)
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs0_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs0_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs0_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtNtCsfFWJyR6nd6r_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0se_00EEs0_0B3a_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNvMNtNtBc_8database11full_sqliteNtB35_18SqliteFullDatabase20to_chain_informations_00EEs0_0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs0_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterRShEEs0_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs0_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs0_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs0_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs0_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs0_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs0_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
846
0
                    {
847
0
                        self.inner.vm = req.resume(self.keys_removed_so_far, true);
848
0
                    } else {
849
                        // TODO: overhead
850
9
                        let trie = self
851
9
                            .inner
852
9
                            .pending_storage_changes
853
9
                            .trie_diffs
854
9
                            .entry(req.child_trie().map(|ct| 
ct.as_ref()1
.
to_vec1
()))
Unexecuted instantiation: _RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEs1_0Bc_
_RNCINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyNtNtNtBc_4trie13branch_search21BranchTrieNodeKeyIterEs1_0Bc_
Line
Count
Source
854
1
                            .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs1_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs1_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs1_0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtNtCsfFWJyR6nd6r_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0se_00EEs1_0B3a_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNvMNtNtBc_8database11full_sqliteNtB35_18SqliteFullDatabase20to_chain_informations_00EEs1_0Bc_
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterRShEEs1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs1_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs1_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs1_0CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtBc_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEEs1_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB39_14SyncBackground12author_block0s6_00EEs1_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EEs1_0Cs4VrkfB1pvQ3_25json_rpc_general_requests
855
9
                            .or_insert(storage_diff::TrieDiff::empty());
856
857
9
                        trie.diff_insert_erase(key.clone(), ());
858
9
                        self.keys_removed_so_far += 1;
859
9
                        self.key_overwrite = Some(key); // TODO: might be expensive if lots of keys
860
9
                        self.inner.vm = req.into();
861
862
9
                        return RuntimeCall::NextKey(self);
863
                    }
864
6
                } else {
865
6
                    self.inner.vm = req.resume(self.keys_removed_so_far, false);
866
6
                }
867
            }
868
869
8.23k
            (vm, Some((trie, trie_root_calculator::InProgress::ClosestDescendant(req)))) => {
870
8.23k
                self.inner.vm = vm;
871
8.23k
                self.inner.root_calculation = Some((trie, req.inject(key)));
872
8.23k
            }
873
874
            // We only create a `NextKey` if the state is one of the above.
875
0
            _ => unreachable!(),
876
        };
877
878
8.24k
        self.inner.run()
879
8.25k
    }
Unexecuted instantiation: _RINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEBa_
_RINvMs7_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyNtNtNtBa_4trie13branch_search21BranchTrieNodeKeyIterEBa_
Line
Count
Source
793
8.25k
    pub fn inject_key(mut self, key: Option<impl Iterator<Item = Nibble>>) -> RuntimeCall {
794
8.25k
        match (self.inner.vm, self.inner.root_calculation.take()) {
795
1
            (host::HostVm::ExternalStorageNextKey(req), None) => {
796
1
                let key =
797
1
                    key.map(|key| trie::nibbles_to_bytes_suffix_extend(key).collect::<Vec<_>>());
798
799
1
                let trie = self
800
1
                    .inner
801
1
                    .pending_storage_changes
802
1
                    .trie_diffs
803
1
                    .get(&req.child_trie().map(|ct| ct.as_ref().to_owned())); // TODO: overhead
804
805
1
                let empty = storage_diff::TrieDiff::empty(); // TODO: weird
806
1
                let search = {
807
1
                    let req_key = req.key();
808
1
                    let requested_key = if let Some(
key_overwrite0
) = &self.key_overwrite {
809
0
                        &key_overwrite[..]
810
                    } else {
811
1
                        req_key.as_ref()
812
                    };
813
                    // TODO: this code is a bit weird
814
1
                    trie.unwrap_or(&empty)
815
1
                        .storage_next_key(requested_key, key.as_deref(), false)
816
                };
817
818
1
                match search {
819
1
                    storage_diff::StorageNextKey::Found(k) => {
820
1
                        self.inner.vm = req.resume(k);
821
1
                    }
822
0
                    storage_diff::StorageNextKey::NextOf(next) => {
823
0
                        let key_overwrite = Some(next.to_owned());
824
0
                        self.inner.vm = host::HostVm::ExternalStorageNextKey(req);
825
0
                        return RuntimeCall::NextKey(NextKey {
826
0
                            inner: self.inner,
827
0
                            key_overwrite,
828
0
                            keys_removed_so_far: 0,
829
0
                        });
830
                    }
831
                }
832
            }
833
834
15
            (host::HostVm::ExternalStorageClearPrefix(req), None) => {
835
                // TODO: there's some trickiness regarding the behavior w.r.t keys only in the overlay; figure out
836
837
15
                if let Some(
key9
) = key {
838
9
                    let key = trie::nibbles_to_bytes_suffix_extend(key).collect::<Vec<_>>();
839
9
                    assert!(key.starts_with(req.prefix().as_ref()));
840
841
                    // TODO: /!\ must clear keys from overlay as well
842
843
9
                    if req
844
9
                        .max_keys_to_remove()
845
9
                        .map_or(false, |max| self.keys_removed_so_far >= max)
846
0
                    {
847
0
                        self.inner.vm = req.resume(self.keys_removed_so_far, true);
848
0
                    } else {
849
                        // TODO: overhead
850
9
                        let trie = self
851
9
                            .inner
852
9
                            .pending_storage_changes
853
9
                            .trie_diffs
854
9
                            .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
855
9
                            .or_insert(storage_diff::TrieDiff::empty());
856
857
9
                        trie.diff_insert_erase(key.clone(), ());
858
9
                        self.keys_removed_so_far += 1;
859
9
                        self.key_overwrite = Some(key); // TODO: might be expensive if lots of keys
860
9
                        self.inner.vm = req.into();
861
862
9
                        return RuntimeCall::NextKey(self);
863
                    }
864
6
                } else {
865
6
                    self.inner.vm = req.resume(self.keys_removed_so_far, false);
866
6
                }
867
            }
868
869
8.23k
            (vm, Some((trie, trie_root_calculator::InProgress::ClosestDescendant(req)))) => {
870
8.23k
                self.inner.vm = vm;
871
8.23k
                self.inner.root_calculation = Some((trie, req.inject(key)));
872
8.23k
            }
873
874
            // We only create a `NextKey` if the state is one of the above.
875
0
            _ => unreachable!(),
876
        };
877
878
8.24k
        self.inner.run()
879
8.25k
    }
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEECscoAnRPySggw_6author
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB37_14SyncBackground12author_block0s6_00EECscoAnRPySggw_6author
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EECscoAnRPySggw_6author
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtNtCsfFWJyR6nd6r_17smoldot_full_node16json_rpc_service16requests_handler22spawn_requests_handler0se_00EEB38_
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNvMNtNtBa_8database11full_sqliteNtB33_18SqliteFullDatabase20to_chain_informations_00EEBa_
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEECs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterRShEECs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEECsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB37_14SyncBackground12author_block0s6_00EECsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EECsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtBa_4trie12proof_decode12EntryKeyIterINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhEEECs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsfFWJyR6nd6r_17smoldot_full_node17consensus_serviceNtB37_14SyncBackground12author_block0s6_00EECs4VrkfB1pvQ3_25json_rpc_general_requests
Unexecuted instantiation: _RINvMs7_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_7NextKey10inject_keyINtNtNtNtCs1p5UDGgVI4d_4core4iter8adapters3map3MapINtNtNtCsaFPxhswmqCN_5alloc3vec9into_iter8IntoIterhENCNCNCNvNtCsfFWJyR6nd6r_17smoldot_full_node17consensus_service12runtime_call0s7_00EECs4VrkfB1pvQ3_25json_rpc_general_requests
880
}
881
882
/// Obtaining the Merkle value of the closest descendant of a trie node is required in order to
883
/// continue.
884
#[must_use]
885
pub struct ClosestDescendantMerkleValue {
886
    inner: Inner,
887
}
888
889
impl ClosestDescendantMerkleValue {
890
    /// Returns the key whose closest descendant Merkle value must be passed to
891
    /// [`ClosestDescendantMerkleValue::inject_merkle_value`].
892
0
    pub fn key(&self) -> impl Iterator<Item = Nibble> {
893
0
        let (_, trie_root_calculator::InProgress::ClosestDescendantMerkleValue(request)) =
894
0
            self.inner.root_calculation.as_ref().unwrap()
895
        else {
896
0
            unreachable!()
897
        };
898
0
        request.key().flat_map(util::as_ref_iter)
899
0
    }
Unexecuted instantiation: _RNvMs8_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue3key
Unexecuted instantiation: _RNvMs8_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue3key
900
901
    /// If `Some`, read from the given child trie. If `None`, read from the main trie.
902
0
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
903
0
        let (trie, trie_root_calculator::InProgress::ClosestDescendantMerkleValue(_)) =
904
0
            self.inner.root_calculation.as_ref().unwrap()
905
        else {
906
0
            unreachable!()
907
        };
908
0
        trie.as_ref()
909
0
    }
Unexecuted instantiation: _RNvMs8_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue10child_trie
Unexecuted instantiation: _RNvMs8_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue10child_trie
910
911
    /// Indicate that the value is unknown and resume the calculation.
912
    ///
913
    /// This function be used if you are unaware of the Merkle value. The algorithm will perform
914
    /// the calculation of this Merkle value manually, which takes more time.
915
6.77k
    pub fn resume_unknown(mut self) -> RuntimeCall {
916
6.77k
        let (trie, trie_root_calculator::InProgress::ClosestDescendantMerkleValue(request)) =
917
6.77k
            self.inner.root_calculation.take().unwrap()
918
        else {
919
0
            unreachable!()
920
        };
921
922
6.77k
        self.inner.root_calculation = Some((trie, request.resume_unknown()));
923
6.77k
        self.inner.run()
924
6.77k
    }
_RNvMs8_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue14resume_unknown
Line
Count
Source
915
6.77k
    pub fn resume_unknown(mut self) -> RuntimeCall {
916
6.77k
        let (trie, trie_root_calculator::InProgress::ClosestDescendantMerkleValue(request)) =
917
6.77k
            self.inner.root_calculation.take().unwrap()
918
        else {
919
0
            unreachable!()
920
        };
921
922
6.77k
        self.inner.root_calculation = Some((trie, request.resume_unknown()));
923
6.77k
        self.inner.run()
924
6.77k
    }
Unexecuted instantiation: _RNvMs8_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue14resume_unknown
925
926
    /// Injects the corresponding Merkle value.
927
    ///
928
    /// `None` can be passed if there is no descendant or, in the case of a child trie read, in
929
    /// order to indicate that the child trie does not exist.
930
0
    pub fn inject_merkle_value(mut self, merkle_value: Option<&[u8]>) -> RuntimeCall {
931
0
        let (trie, trie_root_calculator::InProgress::ClosestDescendantMerkleValue(request)) =
932
0
            self.inner.root_calculation.take().unwrap()
933
        else {
934
0
            unreachable!()
935
        };
936
937
0
        self.inner.root_calculation = Some((
938
0
            trie,
939
0
            match merkle_value {
940
0
                Some(merkle_value) => request.inject_merkle_value(merkle_value),
941
                None => {
942
                    // We don't properly handle the situation where there's no descendant or no child
943
                    // trie.
944
0
                    request.resume_unknown()
945
                }
946
            },
947
        ));
948
0
        self.inner.run()
949
0
    }
Unexecuted instantiation: _RNvMs8_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue19inject_merkle_value
Unexecuted instantiation: _RNvMs8_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_28ClosestDescendantMerkleValue19inject_merkle_value
950
}
951
952
/// Verifying whether a signature is correct is required in order to continue.
953
#[must_use]
954
pub struct SignatureVerification {
955
    inner: Inner,
956
}
957
958
impl SignatureVerification {
959
    /// Returns the message that the signature is expected to sign.
960
0
    pub fn message(&self) -> impl AsRef<[u8]> {
961
0
        match self.inner.vm {
962
0
            host::HostVm::SignatureVerification(ref sig) => sig.message(),
963
0
            _ => unreachable!(),
964
        }
965
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification7message
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification7message
966
967
    /// Returns the signature.
968
    ///
969
    /// > **Note**: Be aware that this signature is untrusted input and might not be part of the
970
    /// >           set of valid signatures.
971
0
    pub fn signature(&self) -> impl AsRef<[u8]> {
972
0
        match self.inner.vm {
973
0
            host::HostVm::SignatureVerification(ref sig) => sig.signature(),
974
0
            _ => unreachable!(),
975
        }
976
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification9signature
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification9signature
977
978
    /// Returns the public key the signature is against.
979
    ///
980
    /// > **Note**: Be aware that this public key is untrusted input and might not be part of the
981
    /// >           set of valid public keys.
982
0
    pub fn public_key(&self) -> impl AsRef<[u8]> {
983
0
        match self.inner.vm {
984
0
            host::HostVm::SignatureVerification(ref sig) => sig.public_key(),
985
0
            _ => unreachable!(),
986
        }
987
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification10public_key
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification10public_key
988
989
    /// Verify the signature. Returns `true` if it is valid.
990
0
    pub fn is_valid(&self) -> bool {
991
0
        match self.inner.vm {
992
0
            host::HostVm::SignatureVerification(ref sig) => sig.is_valid(),
993
0
            _ => unreachable!(),
994
        }
995
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification8is_valid
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification8is_valid
996
997
    /// Verify the signature and resume execution.
998
6
    pub fn verify_and_resume(mut self) -> RuntimeCall {
999
6
        match self.inner.vm {
1000
6
            host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.verify_and_resume(),
1001
0
            _ => unreachable!(),
1002
        }
1003
1004
6
        self.inner.run()
1005
6
    }
_RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification17verify_and_resume
Line
Count
Source
998
6
    pub fn verify_and_resume(mut self) -> RuntimeCall {
999
6
        match self.inner.vm {
1000
6
            host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.verify_and_resume(),
1001
0
            _ => unreachable!(),
1002
        }
1003
1004
6
        self.inner.run()
1005
6
    }
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification17verify_and_resume
1006
1007
    /// Resume the execution assuming that the signature is valid.
1008
    ///
1009
    /// > **Note**: You are strongly encouraged to call
1010
    /// >           [`SignatureVerification::verify_and_resume`]. This function is meant to be
1011
    /// >           used only in debugging situations.
1012
0
    pub fn resume_success(mut self) -> RuntimeCall {
1013
0
        match self.inner.vm {
1014
0
            host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_success(),
1015
0
            _ => unreachable!(),
1016
        }
1017
1018
0
        self.inner.run()
1019
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification14resume_success
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification14resume_success
1020
1021
    /// Resume the execution assuming that the signature is invalid.
1022
    ///
1023
    /// > **Note**: You are strongly encouraged to call
1024
    /// >           [`SignatureVerification::verify_and_resume`]. This function is meant to be
1025
    /// >           used only in debugging situations.
1026
0
    pub fn resume_failed(mut self) -> RuntimeCall {
1027
0
        match self.inner.vm {
1028
0
            host::HostVm::SignatureVerification(sig) => self.inner.vm = sig.resume_failed(),
1029
0
            _ => unreachable!(),
1030
        }
1031
1032
0
        self.inner.run()
1033
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_21SignatureVerification13resume_failed
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_21SignatureVerification13resume_failed
1034
}
1035
1036
/// Loading an offchain storage value is required in order to continue.
1037
#[must_use]
1038
pub struct OffchainStorageGet {
1039
    inner: Inner,
1040
}
1041
1042
impl OffchainStorageGet {
1043
    /// Returns the key whose value must be passed to [`OffchainStorageGet::inject_value`].
1044
0
    pub fn key(&self) -> impl AsRef<[u8]> {
1045
0
        match &self.inner.vm {
1046
0
            host::HostVm::ExternalOffchainStorageGet(req) => req.key(),
1047
            // We only create a `OffchainStorageGet` if the state is one of the above.
1048
0
            _ => unreachable!(),
1049
        }
1050
0
    }
Unexecuted instantiation: _RNvMsa_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_18OffchainStorageGet3key
Unexecuted instantiation: _RNvMsa_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_18OffchainStorageGet3key
1051
1052
    /// Injects the corresponding storage value.
1053
0
    pub fn inject_value(mut self, value: Option<impl AsRef<[u8]>>) -> RuntimeCall {
1054
0
        match self.inner.vm {
1055
0
            host::HostVm::ExternalOffchainStorageGet(req) => {
1056
0
                self.inner.vm = req.resume(value.as_ref().map(|v| v.as_ref()));
Unexecuted instantiation: _RNCINvMsa_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB8_18OffchainStorageGet12inject_valuepE0Bc_
Unexecuted instantiation: _RNCINvMsa_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB8_18OffchainStorageGet12inject_valuepE0Bc_
1057
            }
1058
            // We only create a `OffchainStorageGet` if the state is one of the above.
1059
0
            _ => unreachable!(),
1060
        };
1061
1062
0
        self.inner.run()
1063
0
    }
Unexecuted instantiation: _RINvMsa_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB6_18OffchainStorageGet12inject_valuepEBa_
Unexecuted instantiation: _RINvMsa_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB6_18OffchainStorageGet12inject_valuepEBa_
1064
}
1065
1066
/// Setting the value of an offchain storage value is required.
1067
#[must_use]
1068
pub struct OffchainStorageSet {
1069
    inner: Inner,
1070
}
1071
1072
impl OffchainStorageSet {
1073
    /// Returns the key whose value must be set.
1074
0
    pub fn key(&self) -> impl AsRef<[u8]> {
1075
0
        match &self.inner.vm {
1076
            host::HostVm::Finished(_) => {
1077
0
                self.inner
1078
0
                    .offchain_storage_changes
1079
0
                    .first_key_value()
1080
0
                    .unwrap()
1081
0
                    .0
1082
            }
1083
            // We only create a `OffchainStorageSet` if the state is one of the above.
1084
0
            _ => unreachable!(),
1085
        }
1086
0
    }
Unexecuted instantiation: _RNvMsb_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet3key
Unexecuted instantiation: _RNvMsb_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet3key
1087
1088
    /// Returns the value to set.
1089
    ///
1090
    /// If `None` is returned, the key should be removed from the storage entirely.
1091
0
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
1092
0
        match &self.inner.vm {
1093
0
            host::HostVm::Finished(_) => self
1094
0
                .inner
1095
0
                .offchain_storage_changes
1096
0
                .first_key_value()
1097
0
                .unwrap()
1098
0
                .1
1099
0
                .as_ref(),
1100
            // We only create a `OffchainStorageSet` if the state is one of the above.
1101
0
            _ => unreachable!(),
1102
        }
1103
0
    }
Unexecuted instantiation: _RNvMsb_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet5value
Unexecuted instantiation: _RNvMsb_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet5value
1104
1105
    /// Resumes execution after having set the value.
1106
0
    pub fn resume(mut self) -> RuntimeCall {
1107
0
        match self.inner.vm {
1108
0
            host::HostVm::Finished(_) => {
1109
0
                self.inner.offchain_storage_changes.pop_first();
1110
0
            }
1111
            // We only create a `OffchainStorageSet` if the state is one of the above.
1112
0
            _ => unreachable!(),
1113
        };
1114
1115
0
        self.inner.run()
1116
0
    }
Unexecuted instantiation: _RNvMsb_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet6resume
Unexecuted instantiation: _RNvMsb_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_18OffchainStorageSet6resume
1117
}
1118
1119
/// Setting the value of an offchain storage value is required.
1120
#[must_use]
1121
pub struct OffchainStorageCompareSet {
1122
    inner: Inner,
1123
}
1124
1125
impl OffchainStorageCompareSet {
1126
    /// Returns the key whose value must be set.
1127
0
    pub fn key(&self) -> impl AsRef<[u8]> {
1128
0
        match &self.inner.vm {
1129
0
            host::HostVm::ExternalOffchainStorageSet(req) => either::Left(req.key()),
1130
0
            host::HostVm::Finished(_) => either::Right(
1131
0
                self.inner
1132
0
                    .offchain_storage_changes
1133
0
                    .first_key_value()
1134
0
                    .unwrap()
1135
0
                    .0,
1136
0
            ),
1137
            // We only create a `OffchainStorageSet` if the state is one of the above.
1138
0
            _ => unreachable!(),
1139
        }
1140
0
    }
Unexecuted instantiation: _RNvMsc_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet3key
Unexecuted instantiation: _RNvMsc_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet3key
1141
1142
    /// Returns the value to set.
1143
    ///
1144
    /// If `None` is returned, the key should be removed from the storage entirely.
1145
0
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
1146
0
        match &self.inner.vm {
1147
0
            host::HostVm::ExternalOffchainStorageSet(req) => req.value().map(either::Left),
1148
0
            host::HostVm::Finished(_) => self
1149
0
                .inner
1150
0
                .offchain_storage_changes
1151
0
                .first_key_value()
1152
0
                .unwrap()
1153
0
                .1
1154
0
                .as_ref()
1155
0
                .map(either::Right),
1156
1157
            // We only create a `OffchainStorageSet` if the state is one of the above.
1158
0
            _ => unreachable!(),
1159
        }
1160
0
    }
Unexecuted instantiation: _RNvMsc_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet5value
Unexecuted instantiation: _RNvMsc_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet5value
1161
1162
    /// Returns the value the current value should be compared against. The operation is a no-op if they don't compare equal.
1163
0
    pub fn old_value(&self) -> Option<impl AsRef<[u8]>> {
1164
0
        match &self.inner.vm {
1165
0
            host::HostVm::ExternalOffchainStorageSet(req) => req.old_value(),
1166
0
            host::HostVm::Finished(_) => None,
1167
            // We only create a `OffchainStorageSet` if the state is one of the above.
1168
0
            _ => unreachable!(),
1169
        }
1170
0
    }
Unexecuted instantiation: _RNvMsc_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet9old_value
Unexecuted instantiation: _RNvMsc_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet9old_value
1171
1172
    /// Resumes execution after having set the value. Must indicate whether a value was written.
1173
0
    pub fn resume(mut self, replaced: bool) -> RuntimeCall {
1174
0
        match self.inner.vm {
1175
0
            host::HostVm::ExternalOffchainStorageSet(req) => {
1176
0
                self.inner.vm = req.resume(replaced);
1177
0
            }
1178
0
            host::HostVm::Finished(_) => {
1179
0
                self.inner.offchain_storage_changes.pop_first();
1180
0
            }
1181
            // We only create a `OffchainStorageSet` if the state is one of the above.
1182
0
            _ => unreachable!(),
1183
        };
1184
1185
0
        self.inner.run()
1186
0
    }
Unexecuted instantiation: _RNvMsc_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet6resume
Unexecuted instantiation: _RNvMsc_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainStorageCompareSet6resume
1187
}
1188
1189
/// Providing the current UNIX timestamp is required in order to continue.
1190
#[must_use]
1191
pub struct OffchainTimestamp {
1192
    inner: Inner,
1193
}
1194
1195
impl OffchainTimestamp {
1196
    /// Resume execution by providing the current UNIX timestamp.
1197
0
    pub fn inject_timestamp(mut self, value: u64) -> RuntimeCall {
1198
0
        match self.inner.vm {
1199
0
            host::HostVm::OffchainTimestamp(req) => {
1200
0
                self.inner.vm = req.resume(value);
1201
0
            }
1202
            // We only create a `OffchainTimestamp` if the state is one of the above.
1203
0
            _ => unreachable!(),
1204
        };
1205
1206
0
        self.inner.run()
1207
0
    }
Unexecuted instantiation: _RNvMsd_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_17OffchainTimestamp16inject_timestamp
Unexecuted instantiation: _RNvMsd_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_17OffchainTimestamp16inject_timestamp
1208
}
1209
1210
/// Providing a random number is required in order to continue.
1211
#[must_use]
1212
pub struct OffchainRandomSeed {
1213
    inner: Inner,
1214
}
1215
1216
impl OffchainRandomSeed {
1217
    /// Resume execution by providing a random number.
1218
0
    pub fn inject_random_seed(mut self, value: [u8; 32]) -> RuntimeCall {
1219
0
        match self.inner.vm {
1220
0
            host::HostVm::OffchainRandomSeed(req) => {
1221
0
                self.inner.vm = req.resume(value);
1222
0
            }
1223
            // We only create a `OffchainRandomSeed` if the state is one of the above.
1224
0
            _ => unreachable!(),
1225
        };
1226
1227
0
        self.inner.run()
1228
0
    }
Unexecuted instantiation: _RNvMse_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_18OffchainRandomSeed18inject_random_seed
Unexecuted instantiation: _RNvMse_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_18OffchainRandomSeed18inject_random_seed
1229
}
1230
1231
/// The runtime requests submitting a transaction.
1232
#[must_use]
1233
pub struct OffchainSubmitTransaction {
1234
    inner: Inner,
1235
}
1236
1237
impl OffchainSubmitTransaction {
1238
    /// Returns the SCALE-encoded transaction that must be submitted.
1239
0
    pub fn transaction(&self) -> impl AsRef<[u8]> {
1240
0
        match &self.inner.vm {
1241
0
            host::HostVm::OffchainSubmitTransaction(req) => req.transaction(),
1242
            // We only create a `OffchainSubmitTransaction` if the state is one of the above.
1243
0
            _ => unreachable!(),
1244
        }
1245
0
    }
Unexecuted instantiation: _RNvMsf_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainSubmitTransaction11transaction
Unexecuted instantiation: _RNvMsf_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainSubmitTransaction11transaction
1246
1247
    /// Resume execution. Must indicate whether the transaction has been successfully submitted.
1248
0
    pub fn resume(mut self, success: bool) -> RuntimeCall {
1249
0
        match self.inner.vm {
1250
0
            host::HostVm::OffchainSubmitTransaction(req) => {
1251
0
                self.inner.vm = req.resume(success);
1252
0
            }
1253
            // We only create a `OffchainSubmitTransaction` if the state is one of the above.
1254
0
            _ => unreachable!(),
1255
        };
1256
1257
0
        self.inner.run()
1258
0
    }
Unexecuted instantiation: _RNvMsf_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_25OffchainSubmitTransaction6resume
Unexecuted instantiation: _RNvMsf_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_25OffchainSubmitTransaction6resume
1259
}
1260
1261
/// Report about a log entry being emitted.
1262
///
1263
/// Use [`LogEmit::info`] to obtain what must be printed.
1264
#[must_use]
1265
pub struct LogEmit {
1266
    inner: Inner,
1267
}
1268
1269
impl LogEmit {
1270
    /// Returns the data that the runtime would like to print.
1271
0
    pub fn info(&self) -> LogEmitInfo {
1272
0
        match &self.inner.vm {
1273
0
            host::HostVm::LogEmit(req) => req.info(),
1274
            // We only create a `LogEmit` if the inner state is `LogEmit`.
1275
0
            _ => unreachable!(),
1276
        }
1277
0
    }
Unexecuted instantiation: _RNvMsg_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7LogEmit4info
Unexecuted instantiation: _RNvMsg_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7LogEmit4info
1278
1279
    /// Resume execution.
1280
0
    pub fn resume(mut self) -> RuntimeCall {
1281
0
        match self.inner.vm {
1282
0
            host::HostVm::LogEmit(req) => {
1283
0
                self.inner.vm = req.resume();
1284
0
            }
1285
            // We only create a `LogEmit` if the inner state is `LogEmit`.
1286
0
            _ => unreachable!(),
1287
        };
1288
1289
0
        self.inner.run()
1290
0
    }
Unexecuted instantiation: _RNvMsg_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_7LogEmit6resume
Unexecuted instantiation: _RNvMsg_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_7LogEmit6resume
1291
}
1292
1293
/// Implementation detail of the execution. Shared by all the variants of [`RuntimeCall`]
1294
/// other than [`RuntimeCall::Finished`].
1295
struct Inner {
1296
    /// Virtual machine running the call.
1297
    vm: host::HostVm,
1298
1299
    /// Pending changes to the storage that this execution performs.
1300
    pending_storage_changes: PendingStorageChanges,
1301
1302
    /// Contains a copy of [`Inner::pending_storage_changes`] at the time when the transaction
1303
    /// started. When the storage transaction ends, either the entry is silently discarded (to
1304
    /// commit), or is written over [`Inner::pending_storage_changes`] (to rollback).
1305
    ///
1306
    /// Contains a `Vec` in case transactions are stacked.
1307
    transactions_stack: Vec<PendingStorageChanges>,
1308
1309
    /// State trie version indicated by the runtime. All the storage changes that are performed
1310
    /// use this version.
1311
    state_trie_version: TrieEntryVersion,
1312
1313
    /// Pending changes to the off-chain storage that this execution performs.
1314
    offchain_storage_changes: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
1315
1316
    /// Trie root calculation in progress. Contains the trie whose root is being calculated
1317
    /// (`Some` for a child trie or `None` for the main trie) and the calculation state machine.
1318
    root_calculation: Option<(Option<Vec<u8>>, trie_root_calculator::InProgress)>,
1319
1320
    /// Value provided by [`Config::max_log_level`].
1321
    max_log_level: u32,
1322
1323
    /// See [`Config::calculate_trie_changes`].
1324
    calculate_trie_changes: bool,
1325
}
1326
1327
/// See [`Inner::pending_storage_changes`].
1328
#[derive(Clone)]
1329
struct PendingStorageChanges {
1330
    /// For each trie, the values that have been written to it.
1331
    trie_diffs: hashbrown::HashMap<Option<Vec<u8>>, storage_diff::TrieDiff, fnv::FnvBuildHasher>,
1332
1333
    /// List of tries (`None` for the main trie and `Some` for child tries) whose root hash must
1334
    /// be recalculated (and for child tries stored into the main trie).
1335
    /// This is necessary in order to populate [`PendingStorageChanges::tries_changes`].
1336
    stale_child_tries_root_hashes: hashbrown::HashSet<Option<Vec<u8>>, fnv::FnvBuildHasher>,
1337
1338
    /// Changes to the trie nodes of all the tries.
1339
    tries_changes: BTreeMap<(Option<Vec<u8>>, Vec<Nibble>), PendingStorageChangesTrieNode>,
1340
1341
    /// Changes to the off-chain storage committed by on-chain transactions.
1342
    offchain_storage_changes: BTreeMap<Vec<u8>, Option<Vec<u8>>>,
1343
}
1344
1345
/// See [`PendingStorageChanges::tries_changes`].
1346
#[derive(Clone)]
1347
enum PendingStorageChangesTrieNode {
1348
    Removed,
1349
    InsertUpdate {
1350
        new_merkle_value: Vec<u8>,
1351
        partial_key: Vec<Nibble>,
1352
        children_merkle_values: Box<[Option<Vec<u8>>; 16]>,
1353
    },
1354
}
1355
1356
/// Writing and reading keys the main trie under this prefix obeys special rules.
1357
const CHILD_STORAGE_SPECIAL_PREFIX: &[u8] = b":child_storage:";
1358
/// Writing and reading keys the main trie under this prefix obeys special rules.
1359
const DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX: &[u8] = b":child_storage:default:";
1360
1361
impl Inner {
1362
    /// Continues the execution.
1363
15.8k
    fn run(mut self) -> RuntimeCall {
1364
        loop {
1365
18.9k
            match self.root_calculation.take() {
1366
2.90k
                None => {}
1367
8.23k
                Some((trie, trie_root_calculator::InProgress::ClosestDescendant(calc_req))) => {
1368
8.23k
                    self.root_calculation = Some((
1369
8.23k
                        trie,
1370
8.23k
                        trie_root_calculator::InProgress::ClosestDescendant(calc_req),
1371
8.23k
                    ));
1372
8.23k
                    return RuntimeCall::NextKey(NextKey {
1373
8.23k
                        inner: self,
1374
8.23k
                        key_overwrite: None,
1375
8.23k
                        keys_removed_so_far: 0,
1376
8.23k
                    });
1377
                }
1378
514
                Some((trie, trie_root_calculator::InProgress::StorageValue(calc_req))) => {
1379
514
                    if calc_req
1380
514
                        .key()
1381
3.56k
                        .
fold514
(0, |count, slice| count + slice.as_ref().len())
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3run0Bb_
Line
Count
Source
1381
3.56k
                        .fold(0, |count, slice| count + slice.as_ref().len())
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3run0Bb_
1382
                        % 2
1383
                        == 0
1384
                    {
1385
438
                        self.root_calculation = Some((
1386
438
                            trie,
1387
438
                            trie_root_calculator::InProgress::StorageValue(calc_req),
1388
438
                        ));
1389
438
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1390
                    } else {
1391
                        // If the number of nibbles in the key is uneven, we are sure that
1392
                        // there exists no storage value.
1393
76
                        self.root_calculation = Some((trie, calc_req.inject_value(None)));
1394
76
                        continue;
1395
                    }
1396
                }
1397
                Some((
1398
6.77k
                    trie,
1399
6.77k
                    trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1400
                )) => {
1401
6.77k
                    self.root_calculation = Some((
1402
6.77k
                        trie,
1403
6.77k
                        trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1404
6.77k
                    ));
1405
6.77k
                    return RuntimeCall::ClosestDescendantMerkleValue(
1406
6.77k
                        ClosestDescendantMerkleValue { inner: self },
1407
6.77k
                    );
1408
                }
1409
500
                Some((trie, trie_root_calculator::InProgress::TrieNodeInsertUpdateEvent(ev))) => {
1410
500
                    self.pending_storage_changes.tries_changes.insert(
1411
500
                        (trie.clone(), ev.key_as_vec()),
1412
                        PendingStorageChangesTrieNode::InsertUpdate {
1413
500
                            new_merkle_value: ev.merkle_value().to_owned(),
1414
500
                            partial_key: ev.partial_key().to_owned(),
1415
500
                            children_merkle_values: TryFrom::try_from(
1416
500
                                ev.children_merkle_values()
1417
8.00k
                                    .
map500
(|mv| mv.map(|mv|
mv489
.
to_owned489
()))
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs_0Bb_
Line
Count
Source
1417
8.00k
                                    .map(|mv| mv.map(|mv| mv.to_owned()))
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs_0Bb_
_RNCNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB9_5Inner3runs_00Bd_
Line
Count
Source
1417
489
                                    .map(|mv| mv.map(|mv| mv.to_owned()))
Unexecuted instantiation: _RNCNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB9_5Inner3runs_00Bd_
1418
500
                                    .collect::<Vec<_>>()
1419
500
                                    .into_boxed_slice(),
1420
                            )
1421
500
                            .unwrap(),
1422
                        },
1423
                    );
1424
1425
500
                    self.root_calculation = Some((trie, ev.resume()));
1426
500
                    continue;
1427
                }
1428
13
                Some((trie, trie_root_calculator::InProgress::TrieNodeRemoveEvent(ev))) => {
1429
13
                    self.pending_storage_changes.tries_changes.insert(
1430
13
                        (trie.clone(), ev.key_as_vec()),
1431
13
                        PendingStorageChangesTrieNode::Removed,
1432
                    );
1433
1434
13
                    self.root_calculation = Some((trie, ev.resume()));
1435
13
                    continue;
1436
                }
1437
10
                Some((trie, trie_root_calculator::InProgress::Finished { trie_root_hash })) => {
1438
10
                    self.pending_storage_changes
1439
10
                        .stale_child_tries_root_hashes
1440
10
                        .remove(&trie);
1441
1442
                    // If we've finished calculating a child trie, update its entry in the
1443
                    // main trie.
1444
10
                    if let Some(
child_trie5
) = &trie {
1445
5
                        let mut main_trie_key = Vec::with_capacity(
1446
5
                            DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX.len() + child_trie.len(),
1447
                        );
1448
5
                        main_trie_key.extend_from_slice(DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX);
1449
5
                        main_trie_key.extend_from_slice(child_trie);
1450
1451
5
                        if trie_root_hash != trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE {
1452
4
                            self.pending_storage_changes
1453
4
                                .trie_diffs
1454
4
                                .entry(None)
1455
4
                                .or_default()
1456
4
                                .diff_insert(main_trie_key, trie_root_hash.to_vec(), ());
1457
4
                        } else {
1458
1
                            self.pending_storage_changes
1459
1
                                .trie_diffs
1460
1
                                .entry(None)
1461
1
                                .or_default()
1462
1
                                .diff_insert_erase(main_trie_key, ());
1463
1
                        }
1464
1465
5
                        self.pending_storage_changes
1466
5
                            .stale_child_tries_root_hashes
1467
5
                            .insert(None);
1468
5
                    }
1469
1470
                    // Resume the VM execution only if the calculated trie is the one that was
1471
                    // requested by the runtime.
1472
10
                    if let host::HostVm::ExternalStorageRoot(req) = self.vm {
1473
                        // Code below is a bit convoluted due to borrow checker issues.
1474
10
                        let trie_match = match (req.child_trie(), trie) {
1475
5
                            (None, None) => true,
1476
0
                            (Some(a), Some(b)) if a.as_ref() == b => true,
1477
5
                            _ => false,
1478
                        };
1479
10
                        if trie_match {
1480
5
                            self.vm = req.resume(&trie_root_hash);
1481
5
                        } else {
1482
5
                            self.vm = host::HostVm::ExternalStorageRoot(req);
1483
5
                        }
1484
0
                    }
1485
1486
10
                    continue;
1487
                }
1488
            }
1489
1490
            // If the runtime requests the trie root hash of the main trie, we must first
1491
            // recalculate the trie root hash of every single child trie that has been modified
1492
            // since the previous trie root hash calculation.
1493
            // This is also done if execution is finished, in order for the diff provided as
1494
            // output to be accurate.
1495
            {
1496
2.90k
                let trie_to_flush: Option<Option<either::Either<_, &[u8]>>> = match &self.vm {
1497
                    host::HostVm::Finished(_) => {
1498
138
                        if let Some(
child_trie0
) = self
1499
138
                            .pending_storage_changes
1500
138
                            .stale_child_tries_root_hashes
1501
138
                            .iter()
1502
138
                            .find_map(|ct| 
ct3
.
as_ref3
())
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs0_0Bb_
Line
Count
Source
1502
3
                            .find_map(|ct| ct.as_ref())
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs0_0Bb_
1503
                        {
1504
0
                            Some(Some(either::Right(child_trie)))
1505
138
                        } else if self
1506
138
                            .pending_storage_changes
1507
138
                            .stale_child_tries_root_hashes
1508
138
                            .contains(&None)
1509
3
                            && self.calculate_trie_changes
1510
                        {
1511
0
                            Some(None)
1512
                        } else {
1513
138
                            None
1514
                        }
1515
                    }
1516
10
                    host::HostVm::ExternalStorageRoot(req) => {
1517
10
                        if let Some(
child_trie0
) = req.child_trie() {
1518
0
                            Some(Some(either::Left(child_trie)))
1519
                        } else {
1520
                            // Find any child trie in `pending_storage_changes`. If `None` is
1521
                            // found, calculate the main trie.
1522
                            // It is important to calculate the child tries before the main tries.
1523
                            Some(
1524
10
                                self.pending_storage_changes
1525
10
                                    .stale_child_tries_root_hashes
1526
10
                                    .iter()
1527
12
                                    .
find_map10
(|ct| ct.as_ref())
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs1_0Bb_
Line
Count
Source
1527
12
                                    .find_map(|ct| ct.as_ref())
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs1_0Bb_
1528
10
                                    .map(|t| either::Right(
&t[..]5
)),
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs2_0Bb_
Line
Count
Source
1528
5
                                    .map(|t| either::Right(&t[..])),
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs2_0Bb_
1529
                            )
1530
                        }
1531
                    }
1532
2.75k
                    _ => None,
1533
                };
1534
1535
2.90k
                if let Some(
trie_to_flush10
) = trie_to_flush {
1536
                    // Remove from `tries_changes` all the changes concerning this trie.
1537
                    // TODO: O(n) and generally not optimized
1538
                    {
1539
10
                        let to_remove = self
1540
10
                            .pending_storage_changes
1541
10
                            .tries_changes
1542
10
                            .range((
1543
                                ops::Bound::Included((
1544
10
                                    trie_to_flush
1545
10
                                        .as_ref()
1546
10
                                        .map(|t| 
AsRef::<[u8]>::as_ref(t)5
.
to_owned5
()),
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs3_0Bb_
Line
Count
Source
1546
5
                                        .map(|t| AsRef::<[u8]>::as_ref(t).to_owned()),
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs3_0Bb_
1547
10
                                    Vec::new(),
1548
                                )),
1549
10
                                ops::Bound::Unbounded,
1550
                            ))
1551
10
                            .take_while(|((ct, _), _)| 
{4
1552
4
                                ct.as_ref().map(|ct| &ct[..])
_RNCNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB9_5Inner3runs4_00Bd_
Line
Count
Source
1552
4
                                ct.as_ref().map(|ct| &ct[..])
Unexecuted instantiation: _RNCNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB9_5Inner3runs4_00Bd_
1553
4
                                    == trie_to_flush.as_ref().map(AsRef::<[u8]>::as_ref)
1554
4
                            })
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs4_0Bb_
Line
Count
Source
1551
4
                            .take_while(|((ct, _), _)| {
1552
4
                                ct.as_ref().map(|ct| &ct[..])
1553
4
                                    == trie_to_flush.as_ref().map(AsRef::<[u8]>::as_ref)
1554
4
                            })
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs4_0Bb_
1555
10
                            .map(|(k, _)| 
k0
.
clone0
())
Unexecuted instantiation: _RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs5_0Bb_
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs5_0Bb_
1556
10
                            .collect::<Vec<_>>();
1557
10
                        for 
to_remove0
in to_remove {
1558
0
                            self.pending_storage_changes
1559
0
                                .tries_changes
1560
0
                                .remove(&to_remove);
1561
0
                        }
1562
                    }
1563
1564
                    // TODO: don't clone?
1565
10
                    let diff = match self
1566
10
                        .pending_storage_changes
1567
10
                        .trie_diffs
1568
10
                        .get(&trie_to_flush.as_ref().map(|t| 
AsRef::<[u8]>::as_ref(&t)5
.
to_owned5
())) // TODO: overhead
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs6_0Bb_
Line
Count
Source
1568
5
                        .get(&trie_to_flush.as_ref().map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()))  // TODO: overhead
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs6_0Bb_
1569
                    {
1570
0
                        None => storage_diff::TrieDiff::empty(),
1571
10
                        Some(diff) => diff.clone(),
1572
                    };
1573
1574
10
                    debug_assert!(self.root_calculation.is_none()); // `Some` handled above.
1575
10
                    self.root_calculation = Some((
1576
10
                        trie_to_flush.map(|t| 
AsRef::<[u8]>::as_ref(&t)5
.
to_owned5
()),
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs7_0Bb_
Line
Count
Source
1576
5
                        trie_to_flush.map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()),
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs7_0Bb_
1577
10
                        trie_root_calculator::trie_root_calculator(trie_root_calculator::Config {
1578
10
                            diff,
1579
10
                            diff_trie_entries_version: self.state_trie_version,
1580
10
                            max_trie_recalculation_depth_hint: 16, // TODO: ?!
1581
10
                        }),
1582
                    ));
1583
10
                    continue;
1584
2.89k
                }
1585
            }
1586
1587
2.89k
            if 
matches!2.75k
(self.vm, host::HostVm::Finished(_))
1588
138
                && !self.offchain_storage_changes.is_empty()
1589
            {
1590
0
                return RuntimeCall::OffchainStorageSet(OffchainStorageSet { inner: self });
1591
2.89k
            }
1592
1593
2.89k
            match self.vm {
1594
1.44k
                host::HostVm::ReadyToRun(r) => self.vm = r.run(),
1595
1596
0
                host::HostVm::Error { error, prototype } => {
1597
0
                    return RuntimeCall::Finished(Err(Error {
1598
0
                        detail: error,
1599
0
                        prototype,
1600
0
                    }));
1601
                }
1602
1603
138
                host::HostVm::Finished(finished) => {
1604
138
                    debug_assert!(self.transactions_stack.is_empty()); // Guaranteed by `host`.
1605
138
                    debug_assert!(
1606
138
                        self.pending_storage_changes
1607
138
                            .stale_child_tries_root_hashes
1608
138
                            .is_empty()
1609
3
                            || (!self.calculate_trie_changes
1610
3
                                && self
1611
3
                                    .pending_storage_changes
1612
3
                                    .stale_child_tries_root_hashes
1613
3
                                    .len()
1614
3
                                    == 1
1615
3
                                && self
1616
3
                                    .pending_storage_changes
1617
3
                                    .stale_child_tries_root_hashes
1618
3
                                    .contains(&None))
1619
                    );
1620
138
                    debug_assert!(self.offchain_storage_changes.is_empty());
1621
1622
138
                    return RuntimeCall::Finished(Ok(Success {
1623
138
                        virtual_machine: SuccessVirtualMachine(finished),
1624
138
                        storage_changes: StorageChanges {
1625
138
                            inner: self.pending_storage_changes,
1626
138
                            calculate_trie_changes: self.calculate_trie_changes,
1627
138
                        },
1628
138
                        state_trie_version: self.state_trie_version,
1629
138
                    }));
1630
                }
1631
1632
687
                host::HostVm::ExternalStorageGet(req) => {
1633
687
                    let diff_search = self
1634
687
                        .pending_storage_changes
1635
687
                        .trie_diffs
1636
687
                        .get(&req.child_trie().map(|ct| 
ct.as_ref()6
.
to_vec6
()))
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs8_0Bb_
Line
Count
Source
1636
6
                        .get(&req.child_trie().map(|ct| ct.as_ref().to_vec()))
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs8_0Bb_
1637
687
                        .and_then(|diff| 
diff681
.
diff_get681
(
req.key().as_ref()681
));
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runs9_0Bb_
Line
Count
Source
1637
597
                        .and_then(|diff| diff.diff_get(req.key().as_ref()));
_RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runs9_0Bb_
Line
Count
Source
1637
84
                        .and_then(|diff| diff.diff_get(req.key().as_ref()));
1638
1639
687
                    if let Some((
value_in_diff436
, _)) = diff_search {
1640
436
                        self.vm = req.resume_full_value(value_in_diff);
1641
436
                    } else {
1642
251
                        self.vm = req.into();
1643
251
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1644
                    }
1645
                }
1646
1647
375
                host::HostVm::ExternalStorageSet(req) => {
1648
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1649
                    // is silently ignored, as per spec.
1650
375
                    if req.child_trie().is_none()
1651
371
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1652
                    {
1653
0
                        self.vm = req.resume();
1654
0
                        continue;
1655
375
                    }
1656
1657
                    // TOOD: to_owned overhead
1658
375
                    self.pending_storage_changes
1659
375
                        .stale_child_tries_root_hashes
1660
375
                        .insert(req.child_trie().map(|ct| 
ct.as_ref()4
.
to_owned4
()));
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsa_0Bb_
Line
Count
Source
1660
4
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsa_0Bb_
1661
1662
375
                    let trie = self
1663
375
                        .pending_storage_changes
1664
375
                        .trie_diffs
1665
375
                        .entry(req.child_trie().map(|ct| 
ct.as_ref()4
.
to_vec4
()))
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsb_0Bb_
Line
Count
Source
1665
4
                        .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsb_0Bb_
1666
375
                        .or_insert(storage_diff::TrieDiff::empty());
1667
1668
375
                    if let Some(
value304
) = req.value() {
1669
304
                        trie.diff_insert(req.key().as_ref(), value.as_ref(), ());
1670
304
                    } else {
1671
71
                        trie.diff_insert_erase(req.key().as_ref(), ());
1672
71
                    }
1673
1674
375
                    self.vm = req.resume()
1675
                }
1676
1677
71
                host::HostVm::ExternalStorageAppend(req) => {
1678
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1679
                    // is silently ignored, as per spec.
1680
71
                    if req.child_trie().is_none()
1681
71
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1682
                    {
1683
0
                        self.vm = req.resume();
1684
0
                        continue;
1685
71
                    }
1686
1687
                    // TOOD: to_owned overhead
1688
71
                    self.pending_storage_changes
1689
71
                        .stale_child_tries_root_hashes
1690
71
                        .insert(req.child_trie().map(|ct| 
ct.as_ref()0
.
to_owned0
()));
Unexecuted instantiation: _RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsc_0Bb_
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsc_0Bb_
1691
1692
71
                    let trie = self
1693
71
                        .pending_storage_changes
1694
71
                        .trie_diffs
1695
71
                        .entry(req.child_trie().map(|ct| 
ct.as_ref()0
.
to_vec0
()))
Unexecuted instantiation: _RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsd_0Bb_
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsd_0Bb_
1696
71
                        .or_insert(storage_diff::TrieDiff::empty());
1697
1698
71
                    let current_value = trie.diff_get(req.key().as_ref()).map(|(v, _)| v);
1699
1700
71
                    if let Some(
current_value63
) = current_value {
1701
63
                        let mut current_value = current_value.unwrap_or_default().to_vec();
1702
63
                        append_to_storage_value(&mut current_value, req.value().as_ref());
1703
63
                        trie.diff_insert(req.key().as_ref().to_vec(), current_value, ());
1704
63
                        self.vm = req.resume();
1705
63
                    } else {
1706
8
                        self.vm = req.into();
1707
8
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1708
                    }
1709
                }
1710
1711
6
                host::HostVm::ExternalStorageClearPrefix(req) => {
1712
                    // Any attempt at clear a prefix that "intersects" (see code) with
1713
                    // `CHILD_STORAGE_SPECIAL_PREFIX` is silently ignored, as per spec.
1714
6
                    if req.child_trie().is_none()
1715
5
                        && CHILD_STORAGE_SPECIAL_PREFIX.starts_with(req.prefix().as_ref())
1716
                    {
1717
0
                        self.vm = req.resume(0, false); // TODO: what's the correct return value for `some_keys_remain`?
1718
0
                        continue;
1719
6
                    }
1720
1721
                    // TODO: consider doing this only if at least one key was actually removed
1722
                    // TOOD: to_owned overhead
1723
6
                    self.pending_storage_changes
1724
6
                        .stale_child_tries_root_hashes
1725
6
                        .insert(req.child_trie().map(|ct| 
ct.as_ref()1
.
to_owned1
()));
_RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsf_0Bb_
Line
Count
Source
1725
1
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsf_0Bb_
1726
1727
6
                    let prefix = req.prefix().as_ref().to_owned();
1728
6
                    self.vm = req.into();
1729
6
                    return RuntimeCall::NextKey(NextKey {
1730
6
                        inner: self,
1731
6
                        key_overwrite: Some(prefix),
1732
6
                        keys_removed_so_far: 0,
1733
6
                    });
1734
                }
1735
1736
                host::HostVm::ExternalStorageRoot(_) => {
1737
                    // Handled above.
1738
0
                    unreachable!()
1739
                }
1740
1741
1
                host::HostVm::ExternalStorageNextKey(req) => {
1742
1
                    self.vm = req.into();
1743
1
                    return RuntimeCall::NextKey(NextKey {
1744
1
                        inner: self,
1745
1
                        key_overwrite: None,
1746
1
                        keys_removed_so_far: 0,
1747
1
                    });
1748
                }
1749
1750
0
                host::HostVm::ExternalOffchainIndexSet(req) => {
1751
0
                    self.pending_storage_changes
1752
0
                        .offchain_storage_changes
1753
0
                        .insert(
1754
0
                            req.key().as_ref().to_vec(),
1755
0
                            req.value().map(|v| v.as_ref().to_vec()),
Unexecuted instantiation: _RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsg_0Bb_
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsg_0Bb_
1756
                        );
1757
1758
0
                    self.vm = req.resume();
1759
                }
1760
1761
0
                host::HostVm::ExternalOffchainStorageGet(req) => {
1762
0
                    let current_value = self.offchain_storage_changes.get(req.key().as_ref());
1763
0
                    match current_value {
1764
0
                        Some(value) => self.vm = req.resume(value.as_ref().map(|v| &v[..])),
Unexecuted instantiation: _RNCNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB7_5Inner3runsh_0Bb_
Unexecuted instantiation: _RNCNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB7_5Inner3runsh_0Bb_
1765
                        None => {
1766
0
                            self.vm = req.into();
1767
0
                            return RuntimeCall::Offchain(OffchainContext::StorageGet(
1768
0
                                OffchainStorageGet { inner: self },
1769
0
                            ));
1770
                        }
1771
                    }
1772
                }
1773
1774
0
                host::HostVm::ExternalOffchainStorageSet(req) => {
1775
0
                    self.vm = req.into();
1776
0
                    return RuntimeCall::Offchain(OffchainContext::StorageSet(
1777
0
                        OffchainStorageCompareSet { inner: self },
1778
0
                    ));
1779
                }
1780
1781
6
                host::HostVm::SignatureVerification(req) => {
1782
6
                    self.vm = req.into();
1783
6
                    return RuntimeCall::SignatureVerification(SignatureVerification {
1784
6
                        inner: self,
1785
6
                    });
1786
                }
1787
1788
0
                host::HostVm::CallRuntimeVersion(req) => {
1789
                    // TODO: make the user execute this ; see https://github.com/paritytech/smoldot/issues/144
1790
                    // The code below compiles the provided WebAssembly runtime code, which is a
1791
                    // relatively expensive operation (in the order of milliseconds).
1792
                    // While it could be tempting to use a system cache, this function is expected
1793
                    // to be called only right before runtime upgrades. Considering that runtime
1794
                    // upgrades are quite uncommon and that a caching system is rather non-trivial
1795
                    // to set up, the approach of recompiling every single time is preferred here.
1796
                    // TODO: number of heap pages?! we use the default here, but not sure whether that's correct or if we have to take the current heap pages
1797
0
                    let vm_prototype = match host::HostVmPrototype::new(host::Config {
1798
0
                        module: req.wasm_code(),
1799
0
                        heap_pages: executor::DEFAULT_HEAP_PAGES,
1800
0
                        exec_hint: vm::ExecHint::ValidateAndExecuteOnce,
1801
0
                        allow_unresolved_imports: false, // TODO: what is a correct value here?
1802
0
                    }) {
1803
0
                        Ok(w) => w,
1804
                        Err(_) => {
1805
0
                            self.vm = req.resume(Err(()));
1806
0
                            continue;
1807
                        }
1808
                    };
1809
1810
0
                    self.vm = req.resume(Ok(vm_prototype.runtime_version().as_ref()));
1811
                }
1812
1813
14
                host::HostVm::StartStorageTransaction(tx) => {
1814
14
                    // TODO: this cloning is very expensive, but providing a more optimized implementation is very complicated
1815
14
                    self.transactions_stack
1816
14
                        .push(self.pending_storage_changes.clone());
1817
14
                    self.vm = tx.resume();
1818
14
                }
1819
1820
14
                host::HostVm::EndStorageTransaction { resume, rollback } => {
1821
                    // The inner implementation guarantees that a storage transaction can only
1822
                    // end if it has earlier been started.
1823
14
                    debug_assert!(!self.transactions_stack.is_empty());
1824
14
                    let rollback_diff = self.transactions_stack.pop().unwrap();
1825
1826
14
                    if rollback {
1827
0
                        self.pending_storage_changes = rollback_diff;
1828
14
                    }
1829
1830
14
                    self.vm = resume.resume();
1831
                }
1832
1833
132
                host::HostVm::GetMaxLogLevel(resume) => {
1834
132
                    self.vm = resume.resume(self.max_log_level);
1835
132
                }
1836
1837
0
                host::HostVm::LogEmit(req) => {
1838
0
                    self.vm = req.into();
1839
0
                    return RuntimeCall::LogEmit(LogEmit { inner: self });
1840
                }
1841
0
                host::HostVm::OffchainTimestamp(req) => {
1842
0
                    self.vm = req.into();
1843
0
                    return RuntimeCall::Offchain(OffchainContext::Timestamp(OffchainTimestamp {
1844
0
                        inner: self,
1845
0
                    }));
1846
                }
1847
0
                host::HostVm::OffchainRandomSeed(req) => {
1848
0
                    self.vm = req.into();
1849
0
                    return RuntimeCall::Offchain(OffchainContext::RandomSeed(
1850
0
                        OffchainRandomSeed { inner: self },
1851
0
                    ));
1852
                }
1853
0
                host::HostVm::OffchainSubmitTransaction(req) => {
1854
0
                    self.vm = req.into();
1855
0
                    return RuntimeCall::Offchain(OffchainContext::SubmitTransaction(
1856
0
                        OffchainSubmitTransaction { inner: self },
1857
0
                    ));
1858
                }
1859
            }
1860
        }
1861
15.8k
    }
_RNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_callNtB5_5Inner3run
Line
Count
Source
1363
15.6k
    fn run(mut self) -> RuntimeCall {
1364
        loop {
1365
18.2k
            match self.root_calculation.take() {
1366
2.22k
                None => {}
1367
8.23k
                Some((trie, trie_root_calculator::InProgress::ClosestDescendant(calc_req))) => {
1368
8.23k
                    self.root_calculation = Some((
1369
8.23k
                        trie,
1370
8.23k
                        trie_root_calculator::InProgress::ClosestDescendant(calc_req),
1371
8.23k
                    ));
1372
8.23k
                    return RuntimeCall::NextKey(NextKey {
1373
8.23k
                        inner: self,
1374
8.23k
                        key_overwrite: None,
1375
8.23k
                        keys_removed_so_far: 0,
1376
8.23k
                    });
1377
                }
1378
514
                Some((trie, trie_root_calculator::InProgress::StorageValue(calc_req))) => {
1379
514
                    if calc_req
1380
514
                        .key()
1381
514
                        .fold(0, |count, slice| count + slice.as_ref().len())
1382
                        % 2
1383
                        == 0
1384
                    {
1385
438
                        self.root_calculation = Some((
1386
438
                            trie,
1387
438
                            trie_root_calculator::InProgress::StorageValue(calc_req),
1388
438
                        ));
1389
438
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1390
                    } else {
1391
                        // If the number of nibbles in the key is uneven, we are sure that
1392
                        // there exists no storage value.
1393
76
                        self.root_calculation = Some((trie, calc_req.inject_value(None)));
1394
76
                        continue;
1395
                    }
1396
                }
1397
                Some((
1398
6.77k
                    trie,
1399
6.77k
                    trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1400
                )) => {
1401
6.77k
                    self.root_calculation = Some((
1402
6.77k
                        trie,
1403
6.77k
                        trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1404
6.77k
                    ));
1405
6.77k
                    return RuntimeCall::ClosestDescendantMerkleValue(
1406
6.77k
                        ClosestDescendantMerkleValue { inner: self },
1407
6.77k
                    );
1408
                }
1409
500
                Some((trie, trie_root_calculator::InProgress::TrieNodeInsertUpdateEvent(ev))) => {
1410
500
                    self.pending_storage_changes.tries_changes.insert(
1411
500
                        (trie.clone(), ev.key_as_vec()),
1412
                        PendingStorageChangesTrieNode::InsertUpdate {
1413
500
                            new_merkle_value: ev.merkle_value().to_owned(),
1414
500
                            partial_key: ev.partial_key().to_owned(),
1415
500
                            children_merkle_values: TryFrom::try_from(
1416
500
                                ev.children_merkle_values()
1417
500
                                    .map(|mv| mv.map(|mv| mv.to_owned()))
1418
500
                                    .collect::<Vec<_>>()
1419
500
                                    .into_boxed_slice(),
1420
                            )
1421
500
                            .unwrap(),
1422
                        },
1423
                    );
1424
1425
500
                    self.root_calculation = Some((trie, ev.resume()));
1426
500
                    continue;
1427
                }
1428
13
                Some((trie, trie_root_calculator::InProgress::TrieNodeRemoveEvent(ev))) => {
1429
13
                    self.pending_storage_changes.tries_changes.insert(
1430
13
                        (trie.clone(), ev.key_as_vec()),
1431
13
                        PendingStorageChangesTrieNode::Removed,
1432
                    );
1433
1434
13
                    self.root_calculation = Some((trie, ev.resume()));
1435
13
                    continue;
1436
                }
1437
10
                Some((trie, trie_root_calculator::InProgress::Finished { trie_root_hash })) => {
1438
10
                    self.pending_storage_changes
1439
10
                        .stale_child_tries_root_hashes
1440
10
                        .remove(&trie);
1441
1442
                    // If we've finished calculating a child trie, update its entry in the
1443
                    // main trie.
1444
10
                    if let Some(
child_trie5
) = &trie {
1445
5
                        let mut main_trie_key = Vec::with_capacity(
1446
5
                            DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX.len() + child_trie.len(),
1447
                        );
1448
5
                        main_trie_key.extend_from_slice(DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX);
1449
5
                        main_trie_key.extend_from_slice(child_trie);
1450
1451
5
                        if trie_root_hash != trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE {
1452
4
                            self.pending_storage_changes
1453
4
                                .trie_diffs
1454
4
                                .entry(None)
1455
4
                                .or_default()
1456
4
                                .diff_insert(main_trie_key, trie_root_hash.to_vec(), ());
1457
4
                        } else {
1458
1
                            self.pending_storage_changes
1459
1
                                .trie_diffs
1460
1
                                .entry(None)
1461
1
                                .or_default()
1462
1
                                .diff_insert_erase(main_trie_key, ());
1463
1
                        }
1464
1465
5
                        self.pending_storage_changes
1466
5
                            .stale_child_tries_root_hashes
1467
5
                            .insert(None);
1468
5
                    }
1469
1470
                    // Resume the VM execution only if the calculated trie is the one that was
1471
                    // requested by the runtime.
1472
10
                    if let host::HostVm::ExternalStorageRoot(req) = self.vm {
1473
                        // Code below is a bit convoluted due to borrow checker issues.
1474
10
                        let trie_match = match (req.child_trie(), trie) {
1475
5
                            (None, None) => true,
1476
0
                            (Some(a), Some(b)) if a.as_ref() == b => true,
1477
5
                            _ => false,
1478
                        };
1479
10
                        if trie_match {
1480
5
                            self.vm = req.resume(&trie_root_hash);
1481
5
                        } else {
1482
5
                            self.vm = host::HostVm::ExternalStorageRoot(req);
1483
5
                        }
1484
0
                    }
1485
1486
10
                    continue;
1487
                }
1488
            }
1489
1490
            // If the runtime requests the trie root hash of the main trie, we must first
1491
            // recalculate the trie root hash of every single child trie that has been modified
1492
            // since the previous trie root hash calculation.
1493
            // This is also done if execution is finished, in order for the diff provided as
1494
            // output to be accurate.
1495
            {
1496
2.22k
                let trie_to_flush: Option<Option<either::Either<_, &[u8]>>> = match &self.vm {
1497
                    host::HostVm::Finished(_) => {
1498
11
                        if let Some(
child_trie0
) = self
1499
11
                            .pending_storage_changes
1500
11
                            .stale_child_tries_root_hashes
1501
11
                            .iter()
1502
11
                            .find_map(|ct| ct.as_ref())
1503
                        {
1504
0
                            Some(Some(either::Right(child_trie)))
1505
11
                        } else if self
1506
11
                            .pending_storage_changes
1507
11
                            .stale_child_tries_root_hashes
1508
11
                            .contains(&None)
1509
3
                            && self.calculate_trie_changes
1510
                        {
1511
0
                            Some(None)
1512
                        } else {
1513
11
                            None
1514
                        }
1515
                    }
1516
10
                    host::HostVm::ExternalStorageRoot(req) => {
1517
10
                        if let Some(
child_trie0
) = req.child_trie() {
1518
0
                            Some(Some(either::Left(child_trie)))
1519
                        } else {
1520
                            // Find any child trie in `pending_storage_changes`. If `None` is
1521
                            // found, calculate the main trie.
1522
                            // It is important to calculate the child tries before the main tries.
1523
                            Some(
1524
10
                                self.pending_storage_changes
1525
10
                                    .stale_child_tries_root_hashes
1526
10
                                    .iter()
1527
10
                                    .find_map(|ct| ct.as_ref())
1528
10
                                    .map(|t| either::Right(&t[..])),
1529
                            )
1530
                        }
1531
                    }
1532
2.20k
                    _ => None,
1533
                };
1534
1535
2.22k
                if let Some(
trie_to_flush10
) = trie_to_flush {
1536
                    // Remove from `tries_changes` all the changes concerning this trie.
1537
                    // TODO: O(n) and generally not optimized
1538
                    {
1539
10
                        let to_remove = self
1540
10
                            .pending_storage_changes
1541
10
                            .tries_changes
1542
10
                            .range((
1543
                                ops::Bound::Included((
1544
10
                                    trie_to_flush
1545
10
                                        .as_ref()
1546
10
                                        .map(|t| AsRef::<[u8]>::as_ref(t).to_owned()),
1547
10
                                    Vec::new(),
1548
                                )),
1549
10
                                ops::Bound::Unbounded,
1550
                            ))
1551
10
                            .take_while(|((ct, _), _)| {
1552
                                ct.as_ref().map(|ct| &ct[..])
1553
                                    == trie_to_flush.as_ref().map(AsRef::<[u8]>::as_ref)
1554
                            })
1555
10
                            .map(|(k, _)| k.clone())
1556
10
                            .collect::<Vec<_>>();
1557
10
                        for 
to_remove0
in to_remove {
1558
0
                            self.pending_storage_changes
1559
0
                                .tries_changes
1560
0
                                .remove(&to_remove);
1561
0
                        }
1562
                    }
1563
1564
                    // TODO: don't clone?
1565
10
                    let diff = match self
1566
10
                        .pending_storage_changes
1567
10
                        .trie_diffs
1568
10
                        .get(&trie_to_flush.as_ref().map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()))  // TODO: overhead
1569
                    {
1570
0
                        None => storage_diff::TrieDiff::empty(),
1571
10
                        Some(diff) => diff.clone(),
1572
                    };
1573
1574
10
                    debug_assert!(self.root_calculation.is_none()); // `Some` handled above.
1575
10
                    self.root_calculation = Some((
1576
10
                        trie_to_flush.map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()),
1577
10
                        trie_root_calculator::trie_root_calculator(trie_root_calculator::Config {
1578
10
                            diff,
1579
10
                            diff_trie_entries_version: self.state_trie_version,
1580
10
                            max_trie_recalculation_depth_hint: 16, // TODO: ?!
1581
10
                        }),
1582
                    ));
1583
10
                    continue;
1584
2.21k
                }
1585
            }
1586
1587
2.21k
            if 
matches!2.20k
(self.vm, host::HostVm::Finished(_))
1588
11
                && !self.offchain_storage_changes.is_empty()
1589
            {
1590
0
                return RuntimeCall::OffchainStorageSet(OffchainStorageSet { inner: self });
1591
2.21k
            }
1592
1593
2.21k
            match self.vm {
1594
1.11k
                host::HostVm::ReadyToRun(r) => self.vm = r.run(),
1595
1596
0
                host::HostVm::Error { error, prototype } => {
1597
0
                    return RuntimeCall::Finished(Err(Error {
1598
0
                        detail: error,
1599
0
                        prototype,
1600
0
                    }));
1601
                }
1602
1603
11
                host::HostVm::Finished(finished) => {
1604
11
                    debug_assert!(self.transactions_stack.is_empty()); // Guaranteed by `host`.
1605
11
                    debug_assert!(
1606
11
                        self.pending_storage_changes
1607
11
                            .stale_child_tries_root_hashes
1608
11
                            .is_empty()
1609
3
                            || (!self.calculate_trie_changes
1610
3
                                && self
1611
3
                                    .pending_storage_changes
1612
3
                                    .stale_child_tries_root_hashes
1613
3
                                    .len()
1614
3
                                    == 1
1615
3
                                && self
1616
3
                                    .pending_storage_changes
1617
3
                                    .stale_child_tries_root_hashes
1618
3
                                    .contains(&None))
1619
                    );
1620
11
                    debug_assert!(self.offchain_storage_changes.is_empty());
1621
1622
11
                    return RuntimeCall::Finished(Ok(Success {
1623
11
                        virtual_machine: SuccessVirtualMachine(finished),
1624
11
                        storage_changes: StorageChanges {
1625
11
                            inner: self.pending_storage_changes,
1626
11
                            calculate_trie_changes: self.calculate_trie_changes,
1627
11
                        },
1628
11
                        state_trie_version: self.state_trie_version,
1629
11
                    }));
1630
                }
1631
1632
603
                host::HostVm::ExternalStorageGet(req) => {
1633
603
                    let diff_search = self
1634
603
                        .pending_storage_changes
1635
603
                        .trie_diffs
1636
603
                        .get(&req.child_trie().map(|ct| ct.as_ref().to_vec()))
1637
603
                        .and_then(|diff| diff.diff_get(req.key().as_ref()));
1638
1639
603
                    if let Some((
value_in_diff436
, _)) = diff_search {
1640
436
                        self.vm = req.resume_full_value(value_in_diff);
1641
436
                    } else {
1642
167
                        self.vm = req.into();
1643
167
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1644
                    }
1645
                }
1646
1647
375
                host::HostVm::ExternalStorageSet(req) => {
1648
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1649
                    // is silently ignored, as per spec.
1650
375
                    if req.child_trie().is_none()
1651
371
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1652
                    {
1653
0
                        self.vm = req.resume();
1654
0
                        continue;
1655
375
                    }
1656
1657
                    // TOOD: to_owned overhead
1658
375
                    self.pending_storage_changes
1659
375
                        .stale_child_tries_root_hashes
1660
375
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1661
1662
375
                    let trie = self
1663
375
                        .pending_storage_changes
1664
375
                        .trie_diffs
1665
375
                        .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
1666
375
                        .or_insert(storage_diff::TrieDiff::empty());
1667
1668
375
                    if let Some(
value304
) = req.value() {
1669
304
                        trie.diff_insert(req.key().as_ref(), value.as_ref(), ());
1670
304
                    } else {
1671
71
                        trie.diff_insert_erase(req.key().as_ref(), ());
1672
71
                    }
1673
1674
375
                    self.vm = req.resume()
1675
                }
1676
1677
71
                host::HostVm::ExternalStorageAppend(req) => {
1678
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1679
                    // is silently ignored, as per spec.
1680
71
                    if req.child_trie().is_none()
1681
71
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1682
                    {
1683
0
                        self.vm = req.resume();
1684
0
                        continue;
1685
71
                    }
1686
1687
                    // TOOD: to_owned overhead
1688
71
                    self.pending_storage_changes
1689
71
                        .stale_child_tries_root_hashes
1690
71
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1691
1692
71
                    let trie = self
1693
71
                        .pending_storage_changes
1694
71
                        .trie_diffs
1695
71
                        .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
1696
71
                        .or_insert(storage_diff::TrieDiff::empty());
1697
1698
71
                    let current_value = trie.diff_get(req.key().as_ref()).map(|(v, _)| v);
1699
1700
71
                    if let Some(
current_value63
) = current_value {
1701
63
                        let mut current_value = current_value.unwrap_or_default().to_vec();
1702
63
                        append_to_storage_value(&mut current_value, req.value().as_ref());
1703
63
                        trie.diff_insert(req.key().as_ref().to_vec(), current_value, ());
1704
63
                        self.vm = req.resume();
1705
63
                    } else {
1706
8
                        self.vm = req.into();
1707
8
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1708
                    }
1709
                }
1710
1711
6
                host::HostVm::ExternalStorageClearPrefix(req) => {
1712
                    // Any attempt at clear a prefix that "intersects" (see code) with
1713
                    // `CHILD_STORAGE_SPECIAL_PREFIX` is silently ignored, as per spec.
1714
6
                    if req.child_trie().is_none()
1715
5
                        && CHILD_STORAGE_SPECIAL_PREFIX.starts_with(req.prefix().as_ref())
1716
                    {
1717
0
                        self.vm = req.resume(0, false); // TODO: what's the correct return value for `some_keys_remain`?
1718
0
                        continue;
1719
6
                    }
1720
1721
                    // TODO: consider doing this only if at least one key was actually removed
1722
                    // TOOD: to_owned overhead
1723
6
                    self.pending_storage_changes
1724
6
                        .stale_child_tries_root_hashes
1725
6
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1726
1727
6
                    let prefix = req.prefix().as_ref().to_owned();
1728
6
                    self.vm = req.into();
1729
6
                    return RuntimeCall::NextKey(NextKey {
1730
6
                        inner: self,
1731
6
                        key_overwrite: Some(prefix),
1732
6
                        keys_removed_so_far: 0,
1733
6
                    });
1734
                }
1735
1736
                host::HostVm::ExternalStorageRoot(_) => {
1737
                    // Handled above.
1738
0
                    unreachable!()
1739
                }
1740
1741
1
                host::HostVm::ExternalStorageNextKey(req) => {
1742
1
                    self.vm = req.into();
1743
1
                    return RuntimeCall::NextKey(NextKey {
1744
1
                        inner: self,
1745
1
                        key_overwrite: None,
1746
1
                        keys_removed_so_far: 0,
1747
1
                    });
1748
                }
1749
1750
0
                host::HostVm::ExternalOffchainIndexSet(req) => {
1751
0
                    self.pending_storage_changes
1752
0
                        .offchain_storage_changes
1753
0
                        .insert(
1754
0
                            req.key().as_ref().to_vec(),
1755
0
                            req.value().map(|v| v.as_ref().to_vec()),
1756
                        );
1757
1758
0
                    self.vm = req.resume();
1759
                }
1760
1761
0
                host::HostVm::ExternalOffchainStorageGet(req) => {
1762
0
                    let current_value = self.offchain_storage_changes.get(req.key().as_ref());
1763
0
                    match current_value {
1764
0
                        Some(value) => self.vm = req.resume(value.as_ref().map(|v| &v[..])),
1765
                        None => {
1766
0
                            self.vm = req.into();
1767
0
                            return RuntimeCall::Offchain(OffchainContext::StorageGet(
1768
0
                                OffchainStorageGet { inner: self },
1769
0
                            ));
1770
                        }
1771
                    }
1772
                }
1773
1774
0
                host::HostVm::ExternalOffchainStorageSet(req) => {
1775
0
                    self.vm = req.into();
1776
0
                    return RuntimeCall::Offchain(OffchainContext::StorageSet(
1777
0
                        OffchainStorageCompareSet { inner: self },
1778
0
                    ));
1779
                }
1780
1781
6
                host::HostVm::SignatureVerification(req) => {
1782
6
                    self.vm = req.into();
1783
6
                    return RuntimeCall::SignatureVerification(SignatureVerification {
1784
6
                        inner: self,
1785
6
                    });
1786
                }
1787
1788
0
                host::HostVm::CallRuntimeVersion(req) => {
1789
                    // TODO: make the user execute this ; see https://github.com/paritytech/smoldot/issues/144
1790
                    // The code below compiles the provided WebAssembly runtime code, which is a
1791
                    // relatively expensive operation (in the order of milliseconds).
1792
                    // While it could be tempting to use a system cache, this function is expected
1793
                    // to be called only right before runtime upgrades. Considering that runtime
1794
                    // upgrades are quite uncommon and that a caching system is rather non-trivial
1795
                    // to set up, the approach of recompiling every single time is preferred here.
1796
                    // TODO: number of heap pages?! we use the default here, but not sure whether that's correct or if we have to take the current heap pages
1797
0
                    let vm_prototype = match host::HostVmPrototype::new(host::Config {
1798
0
                        module: req.wasm_code(),
1799
0
                        heap_pages: executor::DEFAULT_HEAP_PAGES,
1800
0
                        exec_hint: vm::ExecHint::ValidateAndExecuteOnce,
1801
0
                        allow_unresolved_imports: false, // TODO: what is a correct value here?
1802
0
                    }) {
1803
0
                        Ok(w) => w,
1804
                        Err(_) => {
1805
0
                            self.vm = req.resume(Err(()));
1806
0
                            continue;
1807
                        }
1808
                    };
1809
1810
0
                    self.vm = req.resume(Ok(vm_prototype.runtime_version().as_ref()));
1811
                }
1812
1813
14
                host::HostVm::StartStorageTransaction(tx) => {
1814
14
                    // TODO: this cloning is very expensive, but providing a more optimized implementation is very complicated
1815
14
                    self.transactions_stack
1816
14
                        .push(self.pending_storage_changes.clone());
1817
14
                    self.vm = tx.resume();
1818
14
                }
1819
1820
14
                host::HostVm::EndStorageTransaction { resume, rollback } => {
1821
                    // The inner implementation guarantees that a storage transaction can only
1822
                    // end if it has earlier been started.
1823
14
                    debug_assert!(!self.transactions_stack.is_empty());
1824
14
                    let rollback_diff = self.transactions_stack.pop().unwrap();
1825
1826
14
                    if rollback {
1827
0
                        self.pending_storage_changes = rollback_diff;
1828
14
                    }
1829
1830
14
                    self.vm = resume.resume();
1831
                }
1832
1833
5
                host::HostVm::GetMaxLogLevel(resume) => {
1834
5
                    self.vm = resume.resume(self.max_log_level);
1835
5
                }
1836
1837
0
                host::HostVm::LogEmit(req) => {
1838
0
                    self.vm = req.into();
1839
0
                    return RuntimeCall::LogEmit(LogEmit { inner: self });
1840
                }
1841
0
                host::HostVm::OffchainTimestamp(req) => {
1842
0
                    self.vm = req.into();
1843
0
                    return RuntimeCall::Offchain(OffchainContext::Timestamp(OffchainTimestamp {
1844
0
                        inner: self,
1845
0
                    }));
1846
                }
1847
0
                host::HostVm::OffchainRandomSeed(req) => {
1848
0
                    self.vm = req.into();
1849
0
                    return RuntimeCall::Offchain(OffchainContext::RandomSeed(
1850
0
                        OffchainRandomSeed { inner: self },
1851
0
                    ));
1852
                }
1853
0
                host::HostVm::OffchainSubmitTransaction(req) => {
1854
0
                    self.vm = req.into();
1855
0
                    return RuntimeCall::Offchain(OffchainContext::SubmitTransaction(
1856
0
                        OffchainSubmitTransaction { inner: self },
1857
0
                    ));
1858
                }
1859
            }
1860
        }
1861
15.6k
    }
_RNvMsh_NtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_callNtB5_5Inner3run
Line
Count
Source
1363
211
    fn run(mut self) -> RuntimeCall {
1364
        loop {
1365
676
            match self.root_calculation.take() {
1366
676
                None => {}
1367
0
                Some((trie, trie_root_calculator::InProgress::ClosestDescendant(calc_req))) => {
1368
0
                    self.root_calculation = Some((
1369
0
                        trie,
1370
0
                        trie_root_calculator::InProgress::ClosestDescendant(calc_req),
1371
0
                    ));
1372
0
                    return RuntimeCall::NextKey(NextKey {
1373
0
                        inner: self,
1374
0
                        key_overwrite: None,
1375
0
                        keys_removed_so_far: 0,
1376
0
                    });
1377
                }
1378
0
                Some((trie, trie_root_calculator::InProgress::StorageValue(calc_req))) => {
1379
0
                    if calc_req
1380
0
                        .key()
1381
0
                        .fold(0, |count, slice| count + slice.as_ref().len())
1382
                        % 2
1383
                        == 0
1384
                    {
1385
0
                        self.root_calculation = Some((
1386
0
                            trie,
1387
0
                            trie_root_calculator::InProgress::StorageValue(calc_req),
1388
0
                        ));
1389
0
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1390
                    } else {
1391
                        // If the number of nibbles in the key is uneven, we are sure that
1392
                        // there exists no storage value.
1393
0
                        self.root_calculation = Some((trie, calc_req.inject_value(None)));
1394
0
                        continue;
1395
                    }
1396
                }
1397
                Some((
1398
0
                    trie,
1399
0
                    trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1400
                )) => {
1401
0
                    self.root_calculation = Some((
1402
0
                        trie,
1403
0
                        trie_root_calculator::InProgress::ClosestDescendantMerkleValue(calc_req),
1404
0
                    ));
1405
0
                    return RuntimeCall::ClosestDescendantMerkleValue(
1406
0
                        ClosestDescendantMerkleValue { inner: self },
1407
0
                    );
1408
                }
1409
0
                Some((trie, trie_root_calculator::InProgress::TrieNodeInsertUpdateEvent(ev))) => {
1410
0
                    self.pending_storage_changes.tries_changes.insert(
1411
0
                        (trie.clone(), ev.key_as_vec()),
1412
                        PendingStorageChangesTrieNode::InsertUpdate {
1413
0
                            new_merkle_value: ev.merkle_value().to_owned(),
1414
0
                            partial_key: ev.partial_key().to_owned(),
1415
0
                            children_merkle_values: TryFrom::try_from(
1416
0
                                ev.children_merkle_values()
1417
0
                                    .map(|mv| mv.map(|mv| mv.to_owned()))
1418
0
                                    .collect::<Vec<_>>()
1419
0
                                    .into_boxed_slice(),
1420
                            )
1421
0
                            .unwrap(),
1422
                        },
1423
                    );
1424
1425
0
                    self.root_calculation = Some((trie, ev.resume()));
1426
0
                    continue;
1427
                }
1428
0
                Some((trie, trie_root_calculator::InProgress::TrieNodeRemoveEvent(ev))) => {
1429
0
                    self.pending_storage_changes.tries_changes.insert(
1430
0
                        (trie.clone(), ev.key_as_vec()),
1431
0
                        PendingStorageChangesTrieNode::Removed,
1432
                    );
1433
1434
0
                    self.root_calculation = Some((trie, ev.resume()));
1435
0
                    continue;
1436
                }
1437
0
                Some((trie, trie_root_calculator::InProgress::Finished { trie_root_hash })) => {
1438
0
                    self.pending_storage_changes
1439
0
                        .stale_child_tries_root_hashes
1440
0
                        .remove(&trie);
1441
1442
                    // If we've finished calculating a child trie, update its entry in the
1443
                    // main trie.
1444
0
                    if let Some(child_trie) = &trie {
1445
0
                        let mut main_trie_key = Vec::with_capacity(
1446
0
                            DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX.len() + child_trie.len(),
1447
                        );
1448
0
                        main_trie_key.extend_from_slice(DEFAULT_CHILD_STORAGE_SPECIAL_PREFIX);
1449
0
                        main_trie_key.extend_from_slice(child_trie);
1450
1451
0
                        if trie_root_hash != trie::EMPTY_BLAKE2_TRIE_MERKLE_VALUE {
1452
0
                            self.pending_storage_changes
1453
0
                                .trie_diffs
1454
0
                                .entry(None)
1455
0
                                .or_default()
1456
0
                                .diff_insert(main_trie_key, trie_root_hash.to_vec(), ());
1457
0
                        } else {
1458
0
                            self.pending_storage_changes
1459
0
                                .trie_diffs
1460
0
                                .entry(None)
1461
0
                                .or_default()
1462
0
                                .diff_insert_erase(main_trie_key, ());
1463
0
                        }
1464
1465
0
                        self.pending_storage_changes
1466
0
                            .stale_child_tries_root_hashes
1467
0
                            .insert(None);
1468
0
                    }
1469
1470
                    // Resume the VM execution only if the calculated trie is the one that was
1471
                    // requested by the runtime.
1472
0
                    if let host::HostVm::ExternalStorageRoot(req) = self.vm {
1473
                        // Code below is a bit convoluted due to borrow checker issues.
1474
0
                        let trie_match = match (req.child_trie(), trie) {
1475
0
                            (None, None) => true,
1476
0
                            (Some(a), Some(b)) if a.as_ref() == b => true,
1477
0
                            _ => false,
1478
                        };
1479
0
                        if trie_match {
1480
0
                            self.vm = req.resume(&trie_root_hash);
1481
0
                        } else {
1482
0
                            self.vm = host::HostVm::ExternalStorageRoot(req);
1483
0
                        }
1484
0
                    }
1485
1486
0
                    continue;
1487
                }
1488
            }
1489
1490
            // If the runtime requests the trie root hash of the main trie, we must first
1491
            // recalculate the trie root hash of every single child trie that has been modified
1492
            // since the previous trie root hash calculation.
1493
            // This is also done if execution is finished, in order for the diff provided as
1494
            // output to be accurate.
1495
            {
1496
676
                let trie_to_flush: Option<Option<either::Either<_, &[u8]>>> = match &self.vm {
1497
                    host::HostVm::Finished(_) => {
1498
127
                        if let Some(
child_trie0
) = self
1499
127
                            .pending_storage_changes
1500
127
                            .stale_child_tries_root_hashes
1501
127
                            .iter()
1502
127
                            .find_map(|ct| ct.as_ref())
1503
                        {
1504
0
                            Some(Some(either::Right(child_trie)))
1505
127
                        } else if self
1506
127
                            .pending_storage_changes
1507
127
                            .stale_child_tries_root_hashes
1508
127
                            .contains(&None)
1509
0
                            && self.calculate_trie_changes
1510
                        {
1511
0
                            Some(None)
1512
                        } else {
1513
127
                            None
1514
                        }
1515
                    }
1516
0
                    host::HostVm::ExternalStorageRoot(req) => {
1517
0
                        if let Some(child_trie) = req.child_trie() {
1518
0
                            Some(Some(either::Left(child_trie)))
1519
                        } else {
1520
                            // Find any child trie in `pending_storage_changes`. If `None` is
1521
                            // found, calculate the main trie.
1522
                            // It is important to calculate the child tries before the main tries.
1523
                            Some(
1524
0
                                self.pending_storage_changes
1525
0
                                    .stale_child_tries_root_hashes
1526
0
                                    .iter()
1527
0
                                    .find_map(|ct| ct.as_ref())
1528
0
                                    .map(|t| either::Right(&t[..])),
1529
                            )
1530
                        }
1531
                    }
1532
549
                    _ => None,
1533
                };
1534
1535
676
                if let Some(
trie_to_flush0
) = trie_to_flush {
1536
                    // Remove from `tries_changes` all the changes concerning this trie.
1537
                    // TODO: O(n) and generally not optimized
1538
                    {
1539
0
                        let to_remove = self
1540
0
                            .pending_storage_changes
1541
0
                            .tries_changes
1542
0
                            .range((
1543
                                ops::Bound::Included((
1544
0
                                    trie_to_flush
1545
0
                                        .as_ref()
1546
0
                                        .map(|t| AsRef::<[u8]>::as_ref(t).to_owned()),
1547
0
                                    Vec::new(),
1548
                                )),
1549
0
                                ops::Bound::Unbounded,
1550
                            ))
1551
0
                            .take_while(|((ct, _), _)| {
1552
                                ct.as_ref().map(|ct| &ct[..])
1553
                                    == trie_to_flush.as_ref().map(AsRef::<[u8]>::as_ref)
1554
                            })
1555
0
                            .map(|(k, _)| k.clone())
1556
0
                            .collect::<Vec<_>>();
1557
0
                        for to_remove in to_remove {
1558
0
                            self.pending_storage_changes
1559
0
                                .tries_changes
1560
0
                                .remove(&to_remove);
1561
0
                        }
1562
                    }
1563
1564
                    // TODO: don't clone?
1565
0
                    let diff = match self
1566
0
                        .pending_storage_changes
1567
0
                        .trie_diffs
1568
0
                        .get(&trie_to_flush.as_ref().map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()))  // TODO: overhead
1569
                    {
1570
0
                        None => storage_diff::TrieDiff::empty(),
1571
0
                        Some(diff) => diff.clone(),
1572
                    };
1573
1574
0
                    debug_assert!(self.root_calculation.is_none()); // `Some` handled above.
1575
0
                    self.root_calculation = Some((
1576
0
                        trie_to_flush.map(|t| AsRef::<[u8]>::as_ref(&t).to_owned()),
1577
0
                        trie_root_calculator::trie_root_calculator(trie_root_calculator::Config {
1578
0
                            diff,
1579
0
                            diff_trie_entries_version: self.state_trie_version,
1580
0
                            max_trie_recalculation_depth_hint: 16, // TODO: ?!
1581
0
                        }),
1582
                    ));
1583
0
                    continue;
1584
676
                }
1585
            }
1586
1587
676
            if 
matches!549
(self.vm, host::HostVm::Finished(_))
1588
127
                && !self.offchain_storage_changes.is_empty()
1589
            {
1590
0
                return RuntimeCall::OffchainStorageSet(OffchainStorageSet { inner: self });
1591
676
            }
1592
1593
676
            match self.vm {
1594
338
                host::HostVm::ReadyToRun(r) => self.vm = r.run(),
1595
1596
0
                host::HostVm::Error { error, prototype } => {
1597
0
                    return RuntimeCall::Finished(Err(Error {
1598
0
                        detail: error,
1599
0
                        prototype,
1600
0
                    }));
1601
                }
1602
1603
127
                host::HostVm::Finished(finished) => {
1604
127
                    debug_assert!(self.transactions_stack.is_empty()); // Guaranteed by `host`.
1605
127
                    debug_assert!(
1606
127
                        self.pending_storage_changes
1607
127
                            .stale_child_tries_root_hashes
1608
127
                            .is_empty()
1609
0
                            || (!self.calculate_trie_changes
1610
0
                                && self
1611
0
                                    .pending_storage_changes
1612
0
                                    .stale_child_tries_root_hashes
1613
0
                                    .len()
1614
0
                                    == 1
1615
0
                                && self
1616
0
                                    .pending_storage_changes
1617
0
                                    .stale_child_tries_root_hashes
1618
0
                                    .contains(&None))
1619
                    );
1620
127
                    debug_assert!(self.offchain_storage_changes.is_empty());
1621
1622
127
                    return RuntimeCall::Finished(Ok(Success {
1623
127
                        virtual_machine: SuccessVirtualMachine(finished),
1624
127
                        storage_changes: StorageChanges {
1625
127
                            inner: self.pending_storage_changes,
1626
127
                            calculate_trie_changes: self.calculate_trie_changes,
1627
127
                        },
1628
127
                        state_trie_version: self.state_trie_version,
1629
127
                    }));
1630
                }
1631
1632
84
                host::HostVm::ExternalStorageGet(req) => {
1633
84
                    let diff_search = self
1634
84
                        .pending_storage_changes
1635
84
                        .trie_diffs
1636
84
                        .get(&req.child_trie().map(|ct| ct.as_ref().to_vec()))
1637
84
                        .and_then(|diff| diff.diff_get(req.key().as_ref()));
1638
1639
84
                    if let Some((
value_in_diff0
, _)) = diff_search {
1640
0
                        self.vm = req.resume_full_value(value_in_diff);
1641
0
                    } else {
1642
84
                        self.vm = req.into();
1643
84
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1644
                    }
1645
                }
1646
1647
0
                host::HostVm::ExternalStorageSet(req) => {
1648
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1649
                    // is silently ignored, as per spec.
1650
0
                    if req.child_trie().is_none()
1651
0
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1652
                    {
1653
0
                        self.vm = req.resume();
1654
0
                        continue;
1655
0
                    }
1656
1657
                    // TOOD: to_owned overhead
1658
0
                    self.pending_storage_changes
1659
0
                        .stale_child_tries_root_hashes
1660
0
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1661
1662
0
                    let trie = self
1663
0
                        .pending_storage_changes
1664
0
                        .trie_diffs
1665
0
                        .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
1666
0
                        .or_insert(storage_diff::TrieDiff::empty());
1667
1668
0
                    if let Some(value) = req.value() {
1669
0
                        trie.diff_insert(req.key().as_ref(), value.as_ref(), ());
1670
0
                    } else {
1671
0
                        trie.diff_insert_erase(req.key().as_ref(), ());
1672
0
                    }
1673
1674
0
                    self.vm = req.resume()
1675
                }
1676
1677
0
                host::HostVm::ExternalStorageAppend(req) => {
1678
                    // Any attempt at writing a key that starts with `CHILD_STORAGE_SPECIAL_PREFIX`
1679
                    // is silently ignored, as per spec.
1680
0
                    if req.child_trie().is_none()
1681
0
                        && req.key().as_ref().starts_with(CHILD_STORAGE_SPECIAL_PREFIX)
1682
                    {
1683
0
                        self.vm = req.resume();
1684
0
                        continue;
1685
0
                    }
1686
1687
                    // TOOD: to_owned overhead
1688
0
                    self.pending_storage_changes
1689
0
                        .stale_child_tries_root_hashes
1690
0
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1691
1692
0
                    let trie = self
1693
0
                        .pending_storage_changes
1694
0
                        .trie_diffs
1695
0
                        .entry(req.child_trie().map(|ct| ct.as_ref().to_vec()))
1696
0
                        .or_insert(storage_diff::TrieDiff::empty());
1697
1698
0
                    let current_value = trie.diff_get(req.key().as_ref()).map(|(v, _)| v);
1699
1700
0
                    if let Some(current_value) = current_value {
1701
0
                        let mut current_value = current_value.unwrap_or_default().to_vec();
1702
0
                        append_to_storage_value(&mut current_value, req.value().as_ref());
1703
0
                        trie.diff_insert(req.key().as_ref().to_vec(), current_value, ());
1704
0
                        self.vm = req.resume();
1705
0
                    } else {
1706
0
                        self.vm = req.into();
1707
0
                        return RuntimeCall::StorageGet(StorageGet { inner: self });
1708
                    }
1709
                }
1710
1711
0
                host::HostVm::ExternalStorageClearPrefix(req) => {
1712
                    // Any attempt at clear a prefix that "intersects" (see code) with
1713
                    // `CHILD_STORAGE_SPECIAL_PREFIX` is silently ignored, as per spec.
1714
0
                    if req.child_trie().is_none()
1715
0
                        && CHILD_STORAGE_SPECIAL_PREFIX.starts_with(req.prefix().as_ref())
1716
                    {
1717
0
                        self.vm = req.resume(0, false); // TODO: what's the correct return value for `some_keys_remain`?
1718
0
                        continue;
1719
0
                    }
1720
1721
                    // TODO: consider doing this only if at least one key was actually removed
1722
                    // TOOD: to_owned overhead
1723
0
                    self.pending_storage_changes
1724
0
                        .stale_child_tries_root_hashes
1725
0
                        .insert(req.child_trie().map(|ct| ct.as_ref().to_owned()));
1726
1727
0
                    let prefix = req.prefix().as_ref().to_owned();
1728
0
                    self.vm = req.into();
1729
0
                    return RuntimeCall::NextKey(NextKey {
1730
0
                        inner: self,
1731
0
                        key_overwrite: Some(prefix),
1732
0
                        keys_removed_so_far: 0,
1733
0
                    });
1734
                }
1735
1736
                host::HostVm::ExternalStorageRoot(_) => {
1737
                    // Handled above.
1738
0
                    unreachable!()
1739
                }
1740
1741
0
                host::HostVm::ExternalStorageNextKey(req) => {
1742
0
                    self.vm = req.into();
1743
0
                    return RuntimeCall::NextKey(NextKey {
1744
0
                        inner: self,
1745
0
                        key_overwrite: None,
1746
0
                        keys_removed_so_far: 0,
1747
0
                    });
1748
                }
1749
1750
0
                host::HostVm::ExternalOffchainIndexSet(req) => {
1751
0
                    self.pending_storage_changes
1752
0
                        .offchain_storage_changes
1753
0
                        .insert(
1754
0
                            req.key().as_ref().to_vec(),
1755
0
                            req.value().map(|v| v.as_ref().to_vec()),
1756
                        );
1757
1758
0
                    self.vm = req.resume();
1759
                }
1760
1761
0
                host::HostVm::ExternalOffchainStorageGet(req) => {
1762
0
                    let current_value = self.offchain_storage_changes.get(req.key().as_ref());
1763
0
                    match current_value {
1764
0
                        Some(value) => self.vm = req.resume(value.as_ref().map(|v| &v[..])),
1765
                        None => {
1766
0
                            self.vm = req.into();
1767
0
                            return RuntimeCall::Offchain(OffchainContext::StorageGet(
1768
0
                                OffchainStorageGet { inner: self },
1769
0
                            ));
1770
                        }
1771
                    }
1772
                }
1773
1774
0
                host::HostVm::ExternalOffchainStorageSet(req) => {
1775
0
                    self.vm = req.into();
1776
0
                    return RuntimeCall::Offchain(OffchainContext::StorageSet(
1777
0
                        OffchainStorageCompareSet { inner: self },
1778
0
                    ));
1779
                }
1780
1781
0
                host::HostVm::SignatureVerification(req) => {
1782
0
                    self.vm = req.into();
1783
0
                    return RuntimeCall::SignatureVerification(SignatureVerification {
1784
0
                        inner: self,
1785
0
                    });
1786
                }
1787
1788
0
                host::HostVm::CallRuntimeVersion(req) => {
1789
                    // TODO: make the user execute this ; see https://github.com/paritytech/smoldot/issues/144
1790
                    // The code below compiles the provided WebAssembly runtime code, which is a
1791
                    // relatively expensive operation (in the order of milliseconds).
1792
                    // While it could be tempting to use a system cache, this function is expected
1793
                    // to be called only right before runtime upgrades. Considering that runtime
1794
                    // upgrades are quite uncommon and that a caching system is rather non-trivial
1795
                    // to set up, the approach of recompiling every single time is preferred here.
1796
                    // TODO: number of heap pages?! we use the default here, but not sure whether that's correct or if we have to take the current heap pages
1797
0
                    let vm_prototype = match host::HostVmPrototype::new(host::Config {
1798
0
                        module: req.wasm_code(),
1799
0
                        heap_pages: executor::DEFAULT_HEAP_PAGES,
1800
0
                        exec_hint: vm::ExecHint::ValidateAndExecuteOnce,
1801
0
                        allow_unresolved_imports: false, // TODO: what is a correct value here?
1802
0
                    }) {
1803
0
                        Ok(w) => w,
1804
                        Err(_) => {
1805
0
                            self.vm = req.resume(Err(()));
1806
0
                            continue;
1807
                        }
1808
                    };
1809
1810
0
                    self.vm = req.resume(Ok(vm_prototype.runtime_version().as_ref()));
1811
                }
1812
1813
0
                host::HostVm::StartStorageTransaction(tx) => {
1814
0
                    // TODO: this cloning is very expensive, but providing a more optimized implementation is very complicated
1815
0
                    self.transactions_stack
1816
0
                        .push(self.pending_storage_changes.clone());
1817
0
                    self.vm = tx.resume();
1818
0
                }
1819
1820
0
                host::HostVm::EndStorageTransaction { resume, rollback } => {
1821
                    // The inner implementation guarantees that a storage transaction can only
1822
                    // end if it has earlier been started.
1823
0
                    debug_assert!(!self.transactions_stack.is_empty());
1824
0
                    let rollback_diff = self.transactions_stack.pop().unwrap();
1825
1826
0
                    if rollback {
1827
0
                        self.pending_storage_changes = rollback_diff;
1828
0
                    }
1829
1830
0
                    self.vm = resume.resume();
1831
                }
1832
1833
127
                host::HostVm::GetMaxLogLevel(resume) => {
1834
127
                    self.vm = resume.resume(self.max_log_level);
1835
127
                }
1836
1837
0
                host::HostVm::LogEmit(req) => {
1838
0
                    self.vm = req.into();
1839
0
                    return RuntimeCall::LogEmit(LogEmit { inner: self });
1840
                }
1841
0
                host::HostVm::OffchainTimestamp(req) => {
1842
0
                    self.vm = req.into();
1843
0
                    return RuntimeCall::Offchain(OffchainContext::Timestamp(OffchainTimestamp {
1844
0
                        inner: self,
1845
0
                    }));
1846
                }
1847
0
                host::HostVm::OffchainRandomSeed(req) => {
1848
0
                    self.vm = req.into();
1849
0
                    return RuntimeCall::Offchain(OffchainContext::RandomSeed(
1850
0
                        OffchainRandomSeed { inner: self },
1851
0
                    ));
1852
                }
1853
0
                host::HostVm::OffchainSubmitTransaction(req) => {
1854
0
                    self.vm = req.into();
1855
0
                    return RuntimeCall::Offchain(OffchainContext::SubmitTransaction(
1856
0
                        OffchainSubmitTransaction { inner: self },
1857
0
                    ));
1858
                }
1859
            }
1860
        }
1861
211
    }
1862
}
1863
1864
/// Performs the action described by [`host::HostVm::ExternalStorageAppend`] on an
1865
/// encoded storage value.
1866
71
fn append_to_storage_value(value: &mut Vec<u8>, to_add: &[u8]) {
1867
55
    let (curr_len, curr_len_encoded_size) =
1868
71
        match util::nom_scale_compact_usize::<nom::error::Error<&[u8]>>(value) {
1869
55
            Ok((rest, l)) => (l, value.len() - rest.len()),
1870
            Err(_) => {
1871
16
                value.clear();
1872
16
                value.reserve(to_add.len() + 1);
1873
16
                value.extend_from_slice(util::encode_scale_compact_usize(1).as_ref());
1874
16
                value.extend_from_slice(to_add);
1875
16
                return;
1876
            }
1877
        };
1878
1879
    // Note: we use `checked_add`, as it is possible that the storage entry erroneously starts
1880
    // with `u64::MAX`.
1881
55
    let new_len = match curr_len.checked_add(1) {
1882
55
        Some(l) => l,
1883
        None => {
1884
0
            value.clear();
1885
0
            value.reserve(to_add.len() + 1);
1886
0
            value.extend_from_slice(util::encode_scale_compact_usize(1).as_ref());
1887
0
            value.extend_from_slice(to_add);
1888
0
            return;
1889
        }
1890
    };
1891
1892
55
    let new_len_encoded = util::encode_scale_compact_usize(new_len);
1893
1894
55
    let new_len_encoded_size = new_len_encoded.as_ref().len();
1895
55
    debug_assert!(
1896
55
        new_len_encoded_size == curr_len_encoded_size
1897
0
            || new_len_encoded_size == curr_len_encoded_size + 1
1898
    );
1899
1900
55
    value.reserve(to_add.len() + (new_len_encoded_size - curr_len_encoded_size));
1901
1902
    // Since `new_len_encoded_size` is either equal to `curr_len_encoded_size` or equal to
1903
    // `curr_len_encoded_size + 1`, we simply use `insert(0, _)` in the latter case.
1904
55
    if new_len_encoded_size != curr_len_encoded_size {
1905
0
        value.insert(0, 0);
1906
55
    }
1907
1908
55
    value[..new_len_encoded_size].copy_from_slice(new_len_encoded.as_ref());
1909
55
    value.extend_from_slice(to_add);
1910
71
}
_RNvNtNtCsjlkOsLH0Zfj_7smoldot8executor12runtime_call23append_to_storage_value
Line
Count
Source
1866
71
fn append_to_storage_value(value: &mut Vec<u8>, to_add: &[u8]) {
1867
55
    let (curr_len, curr_len_encoded_size) =
1868
71
        match util::nom_scale_compact_usize::<nom::error::Error<&[u8]>>(value) {
1869
55
            Ok((rest, l)) => (l, value.len() - rest.len()),
1870
            Err(_) => {
1871
16
                value.clear();
1872
16
                value.reserve(to_add.len() + 1);
1873
16
                value.extend_from_slice(util::encode_scale_compact_usize(1).as_ref());
1874
16
                value.extend_from_slice(to_add);
1875
16
                return;
1876
            }
1877
        };
1878
1879
    // Note: we use `checked_add`, as it is possible that the storage entry erroneously starts
1880
    // with `u64::MAX`.
1881
55
    let new_len = match curr_len.checked_add(1) {
1882
55
        Some(l) => l,
1883
        None => {
1884
0
            value.clear();
1885
0
            value.reserve(to_add.len() + 1);
1886
0
            value.extend_from_slice(util::encode_scale_compact_usize(1).as_ref());
1887
0
            value.extend_from_slice(to_add);
1888
0
            return;
1889
        }
1890
    };
1891
1892
55
    let new_len_encoded = util::encode_scale_compact_usize(new_len);
1893
1894
55
    let new_len_encoded_size = new_len_encoded.as_ref().len();
1895
55
    debug_assert!(
1896
55
        new_len_encoded_size == curr_len_encoded_size
1897
0
            || new_len_encoded_size == curr_len_encoded_size + 1
1898
    );
1899
1900
55
    value.reserve(to_add.len() + (new_len_encoded_size - curr_len_encoded_size));
1901
1902
    // Since `new_len_encoded_size` is either equal to `curr_len_encoded_size` or equal to
1903
    // `curr_len_encoded_size + 1`, we simply use `insert(0, _)` in the latter case.
1904
55
    if new_len_encoded_size != curr_len_encoded_size {
1905
0
        value.insert(0, 0);
1906
55
    }
1907
1908
55
    value[..new_len_encoded_size].copy_from_slice(new_len_encoded.as_ref());
1909
55
    value.extend_from_slice(to_add);
1910
71
}
Unexecuted instantiation: _RNvNtNtCsc1ywvx6YAnK_7smoldot8executor12runtime_call23append_to_storage_value