Coverage Report

Created: 2025-06-06 16:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/lib/src/executor/host.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 specific to the Substrate/Polkadot Runtime Environment.
19
//!
20
//! Contrary to [`VirtualMachine`](super::vm::VirtualMachine), this code is not just a generic
21
//! Wasm virtual machine, but is aware of the Substrate/Polkadot runtime environment. The host
22
//! functions that the Wasm code calls are automatically resolved and either handled or notified
23
//! to the user of this module.
24
//!
25
//! Any host function that requires pure CPU computations (for example building or verifying
26
//! a cryptographic signature) is directly handled by the code in this module. Other host
27
//! functions (for example accessing the state or printing a message) are instead handled by
28
//! interrupting the virtual machine and waiting for the user of this module to handle the call.
29
//!
30
//! > **Note**: The `ext_offchain_random_seed_version_1` and `ext_offchain_timestamp_version_1`
31
//! >           functions, which requires the host to respectively produce a random seed and
32
//! >           return the current time, must also be handled by the user. While these functions
33
//! >           could theoretically be handled directly by this module, it might be useful for
34
//! >           testing purposes to have the possibility to return a deterministic value.
35
//!
36
//! Contrary to most programs, runtime code doesn't have a singe `main` or `start` function.
37
//! Instead, it exposes several entry points. Which one to call indicates which action it has to
38
//! perform. Not all entry points are necessarily available on all runtimes.
39
//!
40
//! # Runtime requirements
41
//!
42
//! See the [documentation of the `vm` module](super::vm) for details about the requirements a
43
//! runtime must adhere to.
44
//!
45
//! In addition to the requirements described there, the WebAssembly runtime code can also be
46
//! zstandard-compressed and must also export a global symbol named `__heap_base`.
47
//! More details below.
48
//!
49
//! ## `Zstandard` compression
50
//!
51
//! The runtime code passed as parameter to [`HostVmPrototype::new`] can be compressed using the
52
//! [`zstd`](https://en.wikipedia.org/wiki/Zstandard) algorithm.
53
//!
54
//! If the code starts with the magic bytes `[82, 188, 83, 118, 70, 219, 142, 5]`, then it is
55
//! assumed that the rest of the data is a zstandard-compressed WebAssembly module.
56
//!
57
//! ## Runtime version
58
//!
59
//! Wasm files can contain so-called custom sections. A runtime can contain two custom sections
60
//! whose names are `"runtime_version"` and `"runtime_apis"`, in which case they must contain a
61
//! so-called runtime version.
62
//!
63
//! The runtime version contains important field that identifies a runtime.
64
//!
65
//! If no `"runtime_version"` and `"runtime_apis"` custom sections can be found, the
66
//! `Core_version` entry point is used as a fallback in order to obtain the runtime version. This
67
//! fallback mechanism is maintained for backwards compatibility purposes, but is considered
68
//! deprecated.
69
//!
70
//! ## Memory allocations
71
//!
72
//! One of the instructions available in WebAssembly code is
73
//! [the `memory.grow` instruction](https://webassembly.github.io/spec/core/bikeshed/#-hrefsyntax-instr-memorymathsfmemorygrow),
74
//! which allows increasing the size of the memory.
75
//!
76
//! WebAssembly code is normally intended to perform its own heap-management logic internally, and
77
//! use the `memory.grow` instruction if more memory is needed.
78
//!
79
//! In order to minimize the size of the runtime binary, and in order to accommodate for the API of
80
//! the host functions that return a buffer of variable length, the Substrate/Polkadot runtimes,
81
//! however, do not perform their heap management internally. Instead, they use the
82
//! `ext_allocator_malloc_version_1` and `ext_allocator_free_version_1` host functions for this
83
//! purpose. Calling `memory.grow` is forbidden.
84
//!
85
//! The runtime code must export a global symbol named `__heap_base` of type `i32`. Any memory
86
//! whose offset is below the value of `__heap_base` can be used at will by the program, while
87
//! any memory above `__heap_base` but below `__heap_base + heap_pages` (where `heap_pages` is
88
//! the value passed as parameter to [`HostVmPrototype::new`]) is available for use by the
89
//! implementation of `ext_allocator_malloc_version_1`.
90
//!
91
//! ## Entry points
92
//!
93
//! All entry points that can be called from the host (using, for example,
94
//! [`HostVmPrototype::run`]) have the same signature:
95
//!
96
//! ```ignore
97
//! (func $runtime_entry(param $data i32) (param $len i32) (result i64))
98
//! ```
99
//!
100
//! In order to call into the runtime, one must write a buffer of data containing the input
101
//! parameters into the Wasm virtual machine's memory, then pass a pointer and length of this
102
//! buffer as the parameters of the entry point.
103
//!
104
//! The function returns a 64 bits number. The 32 less significant bits represent a pointer to the
105
//! Wasm virtual machine's memory, and the 32 most significant bits a length. This pointer and
106
//! length designate a buffer containing the actual return value.
107
//!
108
//! ## Host functions
109
//!
110
//! The list of host functions available to the runtime is long and isn't documented here. See
111
//! the official specification for details.
112
//!
113
//! # Usage
114
//!
115
//! The first step is to create a [`HostVmPrototype`] object from the WebAssembly code. Creating
116
//! this object performs some initial steps, such as parsing and compiling the WebAssembly code.
117
//! You are encouraged to maintain a cache of [`HostVmPrototype`] objects (one instance per
118
//! WebAssembly byte code) in order to avoid performing these operations too often.
119
//!
120
//! To start calling the runtime, create a [`HostVm`] by calling [`HostVmPrototype::run`].
121
//!
122
//! While the Wasm runtime code has side-effects (such as storing values in the storage), the
123
//! [`HostVm`] itself is a pure state machine with no side effects.
124
//!
125
//! At any given point, you can examine the [`HostVm`] in order to know in which state the
126
//! execution currently is.
127
//! In case of a [`HostVm::ReadyToRun`] (which initially is the case when you create the
128
//! [`HostVm`]), you can execute the Wasm code by calling [`ReadyToRun::run`].
129
//! No background thread of any kind is used, and calling [`ReadyToRun::run`] directly performs
130
//! the execution of the Wasm code. If you need parallelism, you are encouraged to spawn a
131
//! background thread yourself and call this function from there.
132
//! [`ReadyToRun::run`] tries to make the execution progress as much as possible, and returns
133
//! the new state of the virtual machine once that is done.
134
//!
135
//! If the runtime has finished, or has crashed, or wants to perform an operation with side
136
//! effects, then the [`HostVm`] determines what to do next. For example, for
137
//! [`HostVm::ExternalStorageGet`], you must load a value from the storage and pass it back by
138
//! calling [`ExternalStorageGet::resume`].
139
//!
140
//! The Wasm execution is fully deterministic, and the outcome of the execution only depends on
141
//! the inputs. There is, for example, no implicit injection of randomness or of the current time.
142
//!
143
//! ## Example
144
//!
145
//! ```
146
//! use smoldot::executor::host::{
147
//!     Config, HeapPages, HostVm, HostVmPrototype, StorageProofSizeBehavior
148
//! };
149
//!
150
//! # let wasm_binary_code: &[u8] = return;
151
//!
152
//! // Start executing a function on the runtime.
153
//! let mut vm: HostVm = {
154
//!     let prototype = HostVmPrototype::new(Config {
155
//!         module: &wasm_binary_code,
156
//!         heap_pages: HeapPages::from(2048),
157
//!         exec_hint: smoldot::executor::vm::ExecHint::ValidateAndExecuteOnce,
158
//!         allow_unresolved_imports: false
159
//!     }).unwrap();
160
//!     prototype.run_no_param(
161
//!         "Core_version",
162
//!         StorageProofSizeBehavior::proof_recording_disabled()
163
//!     ).unwrap().into()
164
//! };
165
//!
166
//! // We need to answer the calls that the runtime might perform.
167
//! loop {
168
//!     match vm {
169
//!         // Calling `runner.run()` is what actually executes WebAssembly code and updates
170
//!         // the state.
171
//!         HostVm::ReadyToRun(runner) => vm = runner.run(),
172
//!
173
//!         HostVm::Finished(finished) => {
174
//!             // `finished.value()` here is an opaque blob of bytes returned by the runtime.
175
//!             // In the case of a call to `"Core_version"`, we know that it must be empty.
176
//!             assert!(finished.value().as_ref().is_empty());
177
//!             println!("Success!");
178
//!             break;
179
//!         },
180
//!
181
//!         // Errors can happen if the WebAssembly code panics or does something wrong.
182
//!         // In a real-life situation, the host should obviously not panic in these situations.
183
//!         HostVm::Error { .. } => {
184
//!             panic!("Error while executing code")
185
//!         },
186
//!
187
//!         // All the other variants correspond to function calls that the runtime might perform.
188
//!         // `ExternalStorageGet` is shown here as an example.
189
//!         HostVm::ExternalStorageGet(req) => {
190
//!             println!("Runtime requires the storage value at {:?}", req.key().as_ref());
191
//!             // Injects the value into the virtual machine and updates the state.
192
//!             vm = req.resume(None); // Just a stub
193
//!         }
194
//!         _ => unimplemented!()
195
//!     }
196
//! }
197
//! ```
198
199
use super::{allocator, vm};
200
use crate::{trie, util};
201
202
use alloc::{borrow::ToOwned as _, boxed::Box, string::String, sync::Arc, vec, vec::Vec};
203
use core::{fmt, iter, str};
204
use functions::HostFunction;
205
206
pub mod runtime_version;
207
208
pub use runtime_version::{
209
    CoreVersion, CoreVersionApisFromSliceErr, CoreVersionError, CoreVersionRef,
210
    FindEncodedEmbeddedRuntimeVersionApisError,
211
};
212
pub use trie::TrieEntryVersion;
213
pub use vm::HeapPages;
214
pub use zstd::Error as ModuleFormatError;
215
216
mod functions;
217
mod tests;
218
mod zstd;
219
220
/// Configuration for [`HostVmPrototype::new`].
221
pub struct Config<TModule> {
222
    /// Bytes of the WebAssembly module.
223
    ///
224
    /// The module can be either directly Wasm bytecode, or zstandard-compressed.
225
    pub module: TModule,
226
227
    /// Number of pages of heap available to the virtual machine.
228
    ///
229
    /// See the module-level documentation for an explanation.
230
    pub heap_pages: HeapPages,
231
232
    /// Hint used by the implementation to decide which kind of virtual machine to use.
233
    pub exec_hint: vm::ExecHint,
234
235
    /// If `true`, no [`vm::NewErr::UnresolvedFunctionImport`] error will be returned if the
236
    /// module trying to import functions that aren't recognized by the implementation. Instead,
237
    /// a [`Error::UnresolvedFunctionCalled`] error will be generated if the module tries to call
238
    /// an unresolved function.
239
    pub allow_unresolved_imports: bool,
240
}
241
242
/// Behavior if the `ext_storage_proof_size_storage_proof_size_version_1` host function is called.
243
///
244
/// When authoring a block or executing a block, this host function is expected to return the
245
/// current size of the proof. Smoldot unfortunately can't implement this due to the fact that
246
/// the proof generation algorithm is completely unspecified. For this reason, you should
247
/// use [`StorageProofSizeBehavior::Unimplemented`]. However, for testing purposes, using
248
/// `StorageProofSizeBehavior::ConstantReturnValue(0)` is acceptable.
249
///
250
/// In situations other than authoring or executing a block, use the value returned by
251
/// [`StorageProofSizeBehavior::proof_recording_disabled`].
252
///
253
#[derive(Debug, Clone, PartialEq, Eq)]
254
pub enum StorageProofSizeBehavior {
255
    /// The host function is unimplemented. An error is returned if it is called.
256
    Unimplemented,
257
    /// The host function returns the given value.
258
    ConstantReturnValue(u64),
259
}
260
261
impl StorageProofSizeBehavior {
262
    /// Returns the behavior to employ when proof recording is disabled, as defined in the
263
    /// specification.
264
171
    pub fn proof_recording_disabled() -> Self {
265
171
        StorageProofSizeBehavior::ConstantReturnValue(u64::MAX)
266
171
    }
_RNvMNtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB2_24StorageProofSizeBehavior24proof_recording_disabled
Line
Count
Source
264
44
    pub fn proof_recording_disabled() -> Self {
265
44
        StorageProofSizeBehavior::ConstantReturnValue(u64::MAX)
266
44
    }
_RNvMNtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB2_24StorageProofSizeBehavior24proof_recording_disabled
Line
Count
Source
264
127
    pub fn proof_recording_disabled() -> Self {
265
127
        StorageProofSizeBehavior::ConstantReturnValue(u64::MAX)
266
127
    }
267
}
268
269
/// Prototype for an [`HostVm`].
270
///
271
/// > **Note**: This struct implements `Clone`. Cloning a [`HostVmPrototype`] allocates memory
272
/// >           necessary for the clone to run.
273
#[derive(Clone)]
274
pub struct HostVmPrototype {
275
    /// Fields that are kept as is even during the execution.
276
    common: Box<VmCommon>,
277
278
    /// Inner virtual machine prototype.
279
    vm_proto: vm::VirtualMachinePrototype,
280
}
281
282
/// Fields that are kept as is even during the execution.
283
#[derive(Clone)]
284
struct VmCommon {
285
    /// Runtime version of this runtime.
286
    ///
287
    /// Always `Some`, except at initialization.
288
    runtime_version: Option<CoreVersion>,
289
290
    /// Initial value of the `__heap_base` global in the Wasm module. Used to initialize the memory
291
    /// allocator.
292
    heap_base: u32,
293
294
    /// List of functions that the Wasm code imports.
295
    ///
296
    /// The keys of this list (i.e. the `usize` indices) have been passed to the virtual machine
297
    /// executor. Whenever the Wasm code invokes a host function, we obtain its index, and look
298
    /// within this list to know what to do.
299
    registered_functions: Arc<[FunctionImport]>,
300
301
    /// Value of `heap_pages` passed to [`HostVmPrototype::new`].
302
    heap_pages: HeapPages,
303
304
    /// Total number of pages of Wasm memory. This is equal to `heap_base / 64k` (rounded up) plus
305
    /// `heap_pages`.
306
    memory_total_pages: HeapPages,
307
}
308
309
impl HostVmPrototype {
310
    /// Creates a new [`HostVmPrototype`]. Parses and potentially JITs the module.
311
154
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
154
        let 
module_bytes152
= zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
154
            .map_err(NewErr::BadFormat)
?2
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
152
        let 
runtime_version150
= match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
147
            Ok(Some(r)) => Some(r),
329
1
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
2
            ) => None,
333
2
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
2
                return Err(NewErr::RuntimeVersion(
335
2
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
2
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
144
        let (mut vm_proto, registered_functions) = {
355
150
            let mut registered_functions = Vec::new();
356
150
            let 
vm_proto144
= vm::VirtualMachinePrototype::new(vm::Config {
357
150
                module_bytes: &module_bytes[..],
358
150
                exec_hint: config.exec_hint,
359
150
                // This closure is called back for each function that the runtime imports.
360
2.95k
                symbols: &mut |mod_name, f_name, signature| {
361
2.95k
                    if mod_name != "env" {
362
0
                        return Err(());
363
2.95k
                    }
364
2.95k
365
2.95k
                    let id = registered_functions.len();
366
2.95k
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
2.94k
                        Some(
f2.93k
) if f.signature() == *signatur
e => FunctionImport::Resolved(f)2.93k
,
368
4
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
6
                            return Err(());
371
                        }
372
13
                        Some(_) | None => FunctionImport::Unresolved {
373
13
                            name: f_name.to_owned(),
374
13
                            module: mod_name.to_owned(),
375
13
                        },
376
                    });
377
2.94k
                    Ok(id)
378
2.95k
                },
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEE0Bb_
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Bb_
Line
Count
Source
360
46
                symbols: &mut |mod_name, f_name, signature| {
361
46
                    if mod_name != "env" {
362
0
                        return Err(());
363
46
                    }
364
46
365
46
                    let id = registered_functions.len();
366
46
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
46
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
46
                    Ok(id)
378
46
                },
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Bb_
Line
Count
Source
360
170
                symbols: &mut |mod_name, f_name, signature| {
361
170
                    if mod_name != "env" {
362
0
                        return Err(());
363
170
                    }
364
170
365
170
                    let id = registered_functions.len();
366
170
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
162
                        Some(
f158
) if f.signature() == *signatur
e => FunctionImport::Resolved(f)158
,
368
4
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
6
                            return Err(());
371
                        }
372
6
                        Some(_) | None => FunctionImport::Unresolved {
373
6
                            name: f_name.to_owned(),
374
6
                            module: mod_name.to_owned(),
375
6
                        },
376
                    });
377
164
                    Ok(id)
378
170
                },
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6_E0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6b_E0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhjd_E0Bb_
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0Bb_
Line
Count
Source
360
149
                symbols: &mut |mod_name, f_name, signature| {
361
149
                    if mod_name != "env" {
362
0
                        return Err(());
363
149
                    }
364
149
365
149
                    let id = registered_functions.len();
366
149
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
142
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
7
                        Some(_) | None => FunctionImport::Unresolved {
373
7
                            name: f_name.to_owned(),
374
7
                            module: mod_name.to_owned(),
375
7
                        },
376
                    });
377
149
                    Ok(id)
378
149
                },
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShE0Bb_
Line
Count
Source
360
96
                symbols: &mut |mod_name, f_name, signature| {
361
96
                    if mod_name != "env" {
362
0
                        return Err(());
363
96
                    }
364
96
365
96
                    let id = registered_functions.len();
366
96
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
96
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
96
                    Ok(id)
378
96
                },
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEE0Bb_
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Bb_
Line
Count
Source
360
609
                symbols: &mut |mod_name, f_name, signature| {
361
609
                    if mod_name != "env" {
362
0
                        return Err(());
363
609
                    }
364
609
365
609
                    let id = registered_functions.len();
366
609
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
609
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
609
                    Ok(id)
378
609
                },
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0Bb_
Line
Count
Source
360
609
                symbols: &mut |mod_name, f_name, signature| {
361
609
                    if mod_name != "env" {
362
0
                        return Err(());
363
609
                    }
364
609
365
609
                    let id = registered_functions.len();
366
609
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
609
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
609
                    Ok(id)
378
609
                },
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Cshebkd5t2Jvd_25json_rpc_general_requests
Line
Count
Source
360
551
                symbols: &mut |mod_name, f_name, signature| {
361
551
                    if mod_name != "env" {
362
0
                        return Err(());
363
551
                    }
364
551
365
551
                    let id = registered_functions.len();
366
551
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
551
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
551
                    Ok(id)
378
551
                },
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEE0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0Cshebkd5t2Jvd_25json_rpc_general_requests
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShE0Cshebkd5t2Jvd_25json_rpc_general_requests
Line
Count
Source
360
551
                symbols: &mut |mod_name, f_name, signature| {
361
551
                    if mod_name != "env" {
362
0
                        return Err(());
363
551
                    }
364
551
365
551
                    let id = registered_functions.len();
366
551
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
551
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
551
                    Ok(id)
378
551
                },
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0Cs5NPiOP1M6me_17smoldot_full_node
Line
Count
Source
360
58
                symbols: &mut |mod_name, f_name, signature| {
361
58
                    if mod_name != "env" {
362
0
                        return Err(());
363
58
                    }
364
58
365
58
                    let id = registered_functions.len();
366
58
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
58
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
58
                    Ok(id)
378
58
                },
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEE0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShE0CsfrWDnknO4Z6_6author
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEE0CshuONSvRyUMf_14json_rpc_basic
Line
Count
Source
360
58
                symbols: &mut |mod_name, f_name, signature| {
361
58
                    if mod_name != "env" {
362
0
                        return Err(());
363
58
                    }
364
58
365
58
                    let id = registered_functions.len();
366
58
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
58
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
58
                    Ok(id)
378
58
                },
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEE0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShE0CshuONSvRyUMf_14json_rpc_basic
_RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShE0CshuONSvRyUMf_14json_rpc_basic
Line
Count
Source
360
58
                symbols: &mut |mod_name, f_name, signature| {
361
58
                    if mod_name != "env" {
362
0
                        return Err(());
363
58
                    }
364
58
365
58
                    let id = registered_functions.len();
366
58
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
58
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
0
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
0
                            return Err(());
371
                        }
372
0
                        Some(_) | None => FunctionImport::Unresolved {
373
0
                            name: f_name.to_owned(),
374
0
                            module: mod_name.to_owned(),
375
0
                        },
376
                    });
377
58
                    Ok(id)
378
58
                },
379
150
            })
?6
;
380
144
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
144
        let 
heap_base142
= vm_proto
386
144
            .global_value("__heap_base")
387
144
            .map_err(|_| 
NewErr::HeapBaseNotFound2
)
?2
;
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Bb_
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Bb_
Line
Count
Source
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)?;
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6_Es_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6b_Es_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhjd_Es_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0Cs5NPiOP1M6me_17smoldot_full_node
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs_0CshuONSvRyUMf_14json_rpc_basic
388
389
142
        let memory_total_pages = if heap_base == 0 {
390
14
            config.heap_pages
391
        } else {
392
128
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
142
        if vm_proto
396
142
            .memory_max_pages()
397
142
            .map_or(false, |max| 
max < memory_total_pages2
)
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Bb_
_RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Bb_
Line
Count
Source
397
2
            .map_or(false, |max| max < memory_total_pages)
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6_Es0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhj6b_Es0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRAhjd_Es0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0Csi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB9_2vm11interpreterNtB1S_11Interpreter11read_memory12AccessOffsetB1G_EEEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0Bb_
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs0_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs0_0Cshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0Cs5NPiOP1M6me_17smoldot_full_node
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs0_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs0_0CsfrWDnknO4Z6_6author
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEs0_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEEs0_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRRShEs0_0CshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RNCINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_15HostVmPrototype3newRShEs0_0CshuONSvRyUMf_14json_rpc_basic
398
        {
399
2
            return Err(NewErr::MemoryMaxSizeTooLow);
400
140
        }
401
140
402
140
        let mut host_vm_prototype = HostVmPrototype {
403
140
            vm_proto,
404
140
            common: Box::new(VmCommon {
405
140
                runtime_version,
406
140
                heap_base,
407
140
                registered_functions,
408
140
                heap_pages: config.heap_pages,
409
140
                memory_total_pages,
410
140
            }),
411
140
        };
412
140
413
140
        // Call `Core_version` if no runtime version is known yet.
414
140
        if host_vm_prototype.common.runtime_version.is_none() {
415
3
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
3
                "Core_version",
417
3
                StorageProofSizeBehavior::proof_recording_disabled(),
418
3
            ) {
419
3
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
10
                match vm {
425
5
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
3
                    HostVm::Finished(finished) => {
427
3
                        let version =
428
3
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
3
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
3
                        host_vm_prototype = finished.into_prototype();
436
3
                        host_vm_prototype.common.runtime_version = Some(version);
437
3
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
2
                    HostVm::GetMaxLogLevel(resume) => {
442
2
                        vm = resume.resume(0); // Off
443
2
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
137
        }
456
457
        // Success!
458
140
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
140
        Ok(host_vm_prototype)
460
154
    }
Unexecuted instantiation: _RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB7_2vm11interpreterNtB1Q_11Interpreter11read_memory12AccessOffsetB1E_EEEB9_
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEB9_
Line
Count
Source
311
1
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
1
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
1
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
1
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
1
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
1
        let (mut vm_proto, registered_functions) = {
355
1
            let mut registered_functions = Vec::new();
356
1
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
1
                module_bytes: &module_bytes[..],
358
1
                exec_hint: config.exec_hint,
359
1
                // This closure is called back for each function that the runtime imports.
360
1
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
1
                },
379
1
            })
?0
;
380
1
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
1
        let heap_base = vm_proto
386
1
            .global_value("__heap_base")
387
1
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
1
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
1
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
1
        if vm_proto
396
1
            .memory_max_pages()
397
1
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
1
        }
401
1
402
1
        let mut host_vm_prototype = HostVmPrototype {
403
1
            vm_proto,
404
1
            common: Box::new(VmCommon {
405
1
                runtime_version,
406
1
                heap_base,
407
1
                registered_functions,
408
1
                heap_pages: config.heap_pages,
409
1
                memory_total_pages,
410
1
            }),
411
1
        };
412
1
413
1
        // Call `Core_version` if no runtime version is known yet.
414
1
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
1
        }
456
457
        // Success!
458
1
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
1
        Ok(host_vm_prototype)
460
1
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEB9_
Line
Count
Source
311
56
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
56
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
56
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
56
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
56
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
50
        let (mut vm_proto, registered_functions) = {
355
56
            let mut registered_functions = Vec::new();
356
56
            let 
vm_proto50
= vm::VirtualMachinePrototype::new(vm::Config {
357
56
                module_bytes: &module_bytes[..],
358
56
                exec_hint: config.exec_hint,
359
56
                // This closure is called back for each function that the runtime imports.
360
56
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
56
                },
379
56
            })
?6
;
380
50
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
50
        let 
heap_base48
= vm_proto
386
50
            .global_value("__heap_base")
387
50
            .map_err(|_| NewErr::HeapBaseNotFound)
?2
;
388
389
48
        let memory_total_pages = if heap_base == 0 {
390
12
            config.heap_pages
391
        } else {
392
36
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
48
        if vm_proto
396
48
            .memory_max_pages()
397
48
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
2
            return Err(NewErr::MemoryMaxSizeTooLow);
400
46
        }
401
46
402
46
        let mut host_vm_prototype = HostVmPrototype {
403
46
            vm_proto,
404
46
            common: Box::new(VmCommon {
405
46
                runtime_version,
406
46
                heap_base,
407
46
                registered_functions,
408
46
                heap_pages: config.heap_pages,
409
46
                memory_total_pages,
410
46
            }),
411
46
        };
412
46
413
46
        // Call `Core_version` if no runtime version is known yet.
414
46
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
46
        }
456
457
        // Success!
458
46
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
46
        Ok(host_vm_prototype)
460
56
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRAhj6_EB9_
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let 
runtime_version0
= match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
0
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
2
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
2
                return Err(NewErr::RuntimeVersion(
335
2
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
2
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
0
        let (mut vm_proto, registered_functions) = {
355
0
            let mut registered_functions = Vec::new();
356
0
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
0
                module_bytes: &module_bytes[..],
358
0
                exec_hint: config.exec_hint,
359
0
                // This closure is called back for each function that the runtime imports.
360
0
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
0
                },
379
0
            })?;
380
0
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
0
        let heap_base = vm_proto
386
0
            .global_value("__heap_base")
387
0
            .map_err(|_| NewErr::HeapBaseNotFound)?;
388
389
0
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
0
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
0
        if vm_proto
396
0
            .memory_max_pages()
397
0
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
0
        }
401
0
402
0
        let mut host_vm_prototype = HostVmPrototype {
403
0
            vm_proto,
404
0
            common: Box::new(VmCommon {
405
0
                runtime_version,
406
0
                heap_base,
407
0
                registered_functions,
408
0
                heap_pages: config.heap_pages,
409
0
                memory_total_pages,
410
0
            }),
411
0
        };
412
0
413
0
        // Call `Core_version` if no runtime version is known yet.
414
0
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
0
        }
456
457
        // Success!
458
0
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
0
        Ok(host_vm_prototype)
460
2
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRAhj6b_EB9_
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
2
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
2
        let (mut vm_proto, registered_functions) = {
355
2
            let mut registered_functions = Vec::new();
356
2
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
2
                module_bytes: &module_bytes[..],
358
2
                exec_hint: config.exec_hint,
359
2
                // This closure is called back for each function that the runtime imports.
360
2
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
2
                },
379
2
            })
?0
;
380
2
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
2
        let heap_base = vm_proto
386
2
            .global_value("__heap_base")
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
2
        let memory_total_pages = if heap_base == 0 {
390
2
            config.heap_pages
391
        } else {
392
0
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
2
        if vm_proto
396
2
            .memory_max_pages()
397
2
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
2
        }
401
2
402
2
        let mut host_vm_prototype = HostVmPrototype {
403
2
            vm_proto,
404
2
            common: Box::new(VmCommon {
405
2
                runtime_version,
406
2
                heap_base,
407
2
                registered_functions,
408
2
                heap_pages: config.heap_pages,
409
2
                memory_total_pages,
410
2
            }),
411
2
        };
412
2
413
2
        // Call `Core_version` if no runtime version is known yet.
414
2
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
2
        }
456
457
        // Success!
458
2
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
2
        Ok(host_vm_prototype)
460
2
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRAhjd_EB9_
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let 
module_bytes0
= zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)?;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
0
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
0
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
0
        let (mut vm_proto, registered_functions) = {
355
0
            let mut registered_functions = Vec::new();
356
0
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
0
                module_bytes: &module_bytes[..],
358
0
                exec_hint: config.exec_hint,
359
0
                // This closure is called back for each function that the runtime imports.
360
0
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
0
                },
379
0
            })?;
380
0
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
0
        let heap_base = vm_proto
386
0
            .global_value("__heap_base")
387
0
            .map_err(|_| NewErr::HeapBaseNotFound)?;
388
389
0
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
0
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
0
        if vm_proto
396
0
            .memory_max_pages()
397
0
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
0
        }
401
0
402
0
        let mut host_vm_prototype = HostVmPrototype {
403
0
            vm_proto,
404
0
            common: Box::new(VmCommon {
405
0
                runtime_version,
406
0
                heap_base,
407
0
                registered_functions,
408
0
                heap_pages: config.heap_pages,
409
0
                memory_total_pages,
410
0
            }),
411
0
        };
412
0
413
0
        // Call `Core_version` if no runtime version is known yet.
414
0
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
0
        }
456
457
        // Success!
458
0
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
0
        Ok(host_vm_prototype)
460
2
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShEB9_
Line
Count
Source
311
3
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
3
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
3
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
3
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
0
            Ok(Some(r)) => Some(r),
329
1
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
2
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
3
        let (mut vm_proto, registered_functions) = {
355
3
            let mut registered_functions = Vec::new();
356
3
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
3
                module_bytes: &module_bytes[..],
358
3
                exec_hint: config.exec_hint,
359
3
                // This closure is called back for each function that the runtime imports.
360
3
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
3
                },
379
3
            })
?0
;
380
3
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
3
        let heap_base = vm_proto
386
3
            .global_value("__heap_base")
387
3
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
3
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
3
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
3
        if vm_proto
396
3
            .memory_max_pages()
397
3
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
3
        }
401
3
402
3
        let mut host_vm_prototype = HostVmPrototype {
403
3
            vm_proto,
404
3
            common: Box::new(VmCommon {
405
3
                runtime_version,
406
3
                heap_base,
407
3
                registered_functions,
408
3
                heap_pages: config.heap_pages,
409
3
                memory_total_pages,
410
3
            }),
411
3
        };
412
3
413
3
        // Call `Core_version` if no runtime version is known yet.
414
3
        if host_vm_prototype.common.runtime_version.is_none() {
415
3
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
3
                "Core_version",
417
3
                StorageProofSizeBehavior::proof_recording_disabled(),
418
3
            ) {
419
3
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
10
                match vm {
425
5
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
3
                    HostVm::Finished(finished) => {
427
3
                        let version =
428
3
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
3
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
3
                        host_vm_prototype = finished.into_prototype();
436
3
                        host_vm_prototype.common.runtime_version = Some(version);
437
3
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
2
                    HostVm::GetMaxLogLevel(resume) => {
442
2
                        vm = resume.resume(0); // Off
443
2
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
0
        }
456
457
        // Success!
458
3
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
3
        Ok(host_vm_prototype)
460
3
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype3newRShEB9_
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
2
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
2
        let (mut vm_proto, registered_functions) = {
355
2
            let mut registered_functions = Vec::new();
356
2
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
2
                module_bytes: &module_bytes[..],
358
2
                exec_hint: config.exec_hint,
359
2
                // This closure is called back for each function that the runtime imports.
360
2
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
2
                },
379
2
            })
?0
;
380
2
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
2
        let heap_base = vm_proto
386
2
            .global_value("__heap_base")
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
2
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
2
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
2
        if vm_proto
396
2
            .memory_max_pages()
397
2
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
2
        }
401
2
402
2
        let mut host_vm_prototype = HostVmPrototype {
403
2
            vm_proto,
404
2
            common: Box::new(VmCommon {
405
2
                runtime_version,
406
2
                heap_base,
407
2
                registered_functions,
408
2
                heap_pages: config.heap_pages,
409
2
                memory_total_pages,
410
2
            }),
411
2
        };
412
2
413
2
        // Call `Core_version` if no runtime version is known yet.
414
2
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
2
        }
456
457
        // Success!
458
2
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
2
        Ok(host_vm_prototype)
460
2
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEECsi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShECsi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtCs5MhOSyk0iiL_6either6EitherRShINtNvMs5_NtNtB7_2vm11interpreterNtB1Q_11Interpreter11read_memory12AccessOffsetB1E_EEEB9_
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEB9_
Line
Count
Source
311
21
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
21
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
21
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
21
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
21
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
21
        let (mut vm_proto, registered_functions) = {
355
21
            let mut registered_functions = Vec::new();
356
21
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
21
                module_bytes: &module_bytes[..],
358
21
                exec_hint: config.exec_hint,
359
21
                // This closure is called back for each function that the runtime imports.
360
21
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
21
                },
379
21
            })
?0
;
380
21
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
21
        let heap_base = vm_proto
386
21
            .global_value("__heap_base")
387
21
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
21
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
21
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
21
        if vm_proto
396
21
            .memory_max_pages()
397
21
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
21
        }
401
21
402
21
        let mut host_vm_prototype = HostVmPrototype {
403
21
            vm_proto,
404
21
            common: Box::new(VmCommon {
405
21
                runtime_version,
406
21
                heap_base,
407
21
                registered_functions,
408
21
                heap_pages: config.heap_pages,
409
21
                memory_total_pages,
410
21
            }),
411
21
        };
412
21
413
21
        // Call `Core_version` if no runtime version is known yet.
414
21
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
21
        }
456
457
        // Success!
458
21
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
21
        Ok(host_vm_prototype)
460
21
    }
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShEB9_
Line
Count
Source
311
21
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
21
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
21
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
21
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
21
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
21
        let (mut vm_proto, registered_functions) = {
355
21
            let mut registered_functions = Vec::new();
356
21
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
21
                module_bytes: &module_bytes[..],
358
21
                exec_hint: config.exec_hint,
359
21
                // This closure is called back for each function that the runtime imports.
360
21
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
21
                },
379
21
            })
?0
;
380
21
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
21
        let heap_base = vm_proto
386
21
            .global_value("__heap_base")
387
21
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
21
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
21
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
21
        if vm_proto
396
21
            .memory_max_pages()
397
21
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
21
        }
401
21
402
21
        let mut host_vm_prototype = HostVmPrototype {
403
21
            vm_proto,
404
21
            common: Box::new(VmCommon {
405
21
                runtime_version,
406
21
                heap_base,
407
21
                registered_functions,
408
21
                heap_pages: config.heap_pages,
409
21
                memory_total_pages,
410
21
            }),
411
21
        };
412
21
413
21
        // Call `Core_version` if no runtime version is known yet.
414
21
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
21
        }
456
457
        // Success!
458
21
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
21
        Ok(host_vm_prototype)
460
21
    }
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEECshebkd5t2Jvd_25json_rpc_general_requests
Line
Count
Source
311
19
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
19
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
19
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
19
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
19
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
19
        let (mut vm_proto, registered_functions) = {
355
19
            let mut registered_functions = Vec::new();
356
19
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
19
                module_bytes: &module_bytes[..],
358
19
                exec_hint: config.exec_hint,
359
19
                // This closure is called back for each function that the runtime imports.
360
19
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
19
                },
379
19
            })
?0
;
380
19
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
19
        let heap_base = vm_proto
386
19
            .global_value("__heap_base")
387
19
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
19
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
19
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
19
        if vm_proto
396
19
            .memory_max_pages()
397
19
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
19
        }
401
19
402
19
        let mut host_vm_prototype = HostVmPrototype {
403
19
            vm_proto,
404
19
            common: Box::new(VmCommon {
405
19
                runtime_version,
406
19
                heap_base,
407
19
                registered_functions,
408
19
                heap_pages: config.heap_pages,
409
19
                memory_total_pages,
410
19
            }),
411
19
        };
412
19
413
19
        // Call `Core_version` if no runtime version is known yet.
414
19
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
19
        }
456
457
        // Success!
458
19
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
19
        Ok(host_vm_prototype)
460
19
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEECshebkd5t2Jvd_25json_rpc_general_requests
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShECshebkd5t2Jvd_25json_rpc_general_requests
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRShECshebkd5t2Jvd_25json_rpc_general_requests
Line
Count
Source
311
19
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
19
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
19
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
19
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
19
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
19
        let (mut vm_proto, registered_functions) = {
355
19
            let mut registered_functions = Vec::new();
356
19
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
19
                module_bytes: &module_bytes[..],
358
19
                exec_hint: config.exec_hint,
359
19
                // This closure is called back for each function that the runtime imports.
360
19
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
19
                },
379
19
            })
?0
;
380
19
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
19
        let heap_base = vm_proto
386
19
            .global_value("__heap_base")
387
19
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
19
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
19
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
19
        if vm_proto
396
19
            .memory_max_pages()
397
19
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
19
        }
401
19
402
19
        let mut host_vm_prototype = HostVmPrototype {
403
19
            vm_proto,
404
19
            common: Box::new(VmCommon {
405
19
                runtime_version,
406
19
                heap_base,
407
19
                registered_functions,
408
19
                heap_pages: config.heap_pages,
409
19
                memory_total_pages,
410
19
            }),
411
19
        };
412
19
413
19
        // Call `Core_version` if no runtime version is known yet.
414
19
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
19
        }
456
457
        // Success!
458
19
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
19
        Ok(host_vm_prototype)
460
19
    }
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEECs5NPiOP1M6me_17smoldot_full_node
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
2
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
2
        let (mut vm_proto, registered_functions) = {
355
2
            let mut registered_functions = Vec::new();
356
2
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
2
                module_bytes: &module_bytes[..],
358
2
                exec_hint: config.exec_hint,
359
2
                // This closure is called back for each function that the runtime imports.
360
2
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
2
                },
379
2
            })
?0
;
380
2
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
2
        let heap_base = vm_proto
386
2
            .global_value("__heap_base")
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
2
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
2
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
2
        if vm_proto
396
2
            .memory_max_pages()
397
2
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
2
        }
401
2
402
2
        let mut host_vm_prototype = HostVmPrototype {
403
2
            vm_proto,
404
2
            common: Box::new(VmCommon {
405
2
                runtime_version,
406
2
                heap_base,
407
2
                registered_functions,
408
2
                heap_pages: config.heap_pages,
409
2
                memory_total_pages,
410
2
            }),
411
2
        };
412
2
413
2
        // Call `Core_version` if no runtime version is known yet.
414
2
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
2
        }
456
457
        // Success!
458
2
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
2
        Ok(host_vm_prototype)
460
2
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEECsfrWDnknO4Z6_6author
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEECsfrWDnknO4Z6_6author
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShECsfrWDnknO4Z6_6author
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRShECsfrWDnknO4Z6_6author
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEECshuONSvRyUMf_14json_rpc_basic
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
2
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
2
        let (mut vm_proto, registered_functions) = {
355
2
            let mut registered_functions = Vec::new();
356
2
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
2
                module_bytes: &module_bytes[..],
358
2
                exec_hint: config.exec_hint,
359
2
                // This closure is called back for each function that the runtime imports.
360
2
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
2
                },
379
2
            })
?0
;
380
2
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
2
        let heap_base = vm_proto
386
2
            .global_value("__heap_base")
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
2
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
2
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
2
        if vm_proto
396
2
            .memory_max_pages()
397
2
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
2
        }
401
2
402
2
        let mut host_vm_prototype = HostVmPrototype {
403
2
            vm_proto,
404
2
            common: Box::new(VmCommon {
405
2
                runtime_version,
406
2
                heap_base,
407
2
                registered_functions,
408
2
                heap_pages: config.heap_pages,
409
2
                memory_total_pages,
410
2
            }),
411
2
        };
412
2
413
2
        // Call `Core_version` if no runtime version is known yet.
414
2
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
2
        }
456
457
        // Success!
458
2
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
2
        Ok(host_vm_prototype)
460
2
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRINtNtCs8GO9KFlE3Dq_5alloc6borrow3CowShEECshuONSvRyUMf_14json_rpc_basic
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRRShECshuONSvRyUMf_14json_rpc_basic
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype3newRShECshuONSvRyUMf_14json_rpc_basic
Line
Count
Source
311
2
    pub fn new(config: Config<impl AsRef<[u8]>>) -> Result<Self, NewErr> {
312
        // The maximum allowed size for the decompressed Wasm code needs to be the same amongst
313
        // all implementations.
314
        // See <https://github.com/paritytech/substrate/blob/f9d10fabe04d598d68f8b097cc4905adbb1ad630/primitives/maybe-compressed-blob/src/lib.rs#L37>.
315
        // Hopefully, this value doesn't get changed without the Substrate team informing everyone.
316
2
        let module_bytes = zstd::zstd_decode_if_necessary(config.module.as_ref(), 50 * 1024 * 1024)
317
2
            .map_err(NewErr::BadFormat)
?0
;
318
319
        // Try to find the runtime version as Wasm custom sections.
320
        // An error is returned if the sections have a wrong format, in which case we fail the
321
        // initialization. `Ok(None)` can also be returned, in which case the sections are
322
        // missing, and we will instead try to retrieve the version through a runtime call later
323
        // down this function.
324
        // In the case of `CustomSectionsPresenceMismatch`, indicating that one section is present
325
        // but not the other, we must ignore the custom sections. This is necessary due to some
326
        // historical accidents.
327
2
        let runtime_version = match runtime_version::find_embedded_runtime_version(&module_bytes) {
328
2
            Ok(Some(r)) => Some(r),
329
0
            Ok(None) => None,
330
            Err(
331
                runtime_version::FindEmbeddedRuntimeVersionError::CustomSectionsPresenceMismatch,
332
0
            ) => None,
333
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::FindSections(err)) => {
334
0
                return Err(NewErr::RuntimeVersion(
335
0
                    FindEmbeddedRuntimeVersionError::FindSections(err),
336
0
                ));
337
            }
338
0
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err)) => {
339
0
                return Err(NewErr::RuntimeVersion(
340
0
                    FindEmbeddedRuntimeVersionError::RuntimeApisDecode(err),
341
0
                ));
342
            }
343
            Err(runtime_version::FindEmbeddedRuntimeVersionError::RuntimeVersionDecode) => {
344
0
                return Err(NewErr::RuntimeVersion(
345
0
                    FindEmbeddedRuntimeVersionError::RuntimeVersionDecode,
346
0
                ));
347
            }
348
        };
349
350
        // Initialize the virtual machine.
351
        // Each symbol requested by the Wasm runtime will be put in `registered_functions`. Later,
352
        // when a function is invoked, the Wasm virtual machine will pass indices within that
353
        // array.
354
2
        let (mut vm_proto, registered_functions) = {
355
2
            let mut registered_functions = Vec::new();
356
2
            let vm_proto = vm::VirtualMachinePrototype::new(vm::Config {
357
2
                module_bytes: &module_bytes[..],
358
2
                exec_hint: config.exec_hint,
359
2
                // This closure is called back for each function that the runtime imports.
360
2
                symbols: &mut |mod_name, f_name, signature| {
361
                    if mod_name != "env" {
362
                        return Err(());
363
                    }
364
365
                    let id = registered_functions.len();
366
                    registered_functions.push(match HostFunction::by_name(f_name) {
367
                        Some(f) if f.signature() == *signature => FunctionImport::Resolved(f),
368
                        Some(_) | None if !config.allow_unresolved_imports => {
369
                            // TODO: return a better error if there is a signature mismatch
370
                            return Err(());
371
                        }
372
                        Some(_) | None => FunctionImport::Unresolved {
373
                            name: f_name.to_owned(),
374
                            module: mod_name.to_owned(),
375
                        },
376
                    });
377
                    Ok(id)
378
2
                },
379
2
            })
?0
;
380
2
            (vm_proto, registered_functions.into())
381
        };
382
383
        // In the runtime environment, Wasm blobs must export a global symbol named
384
        // `__heap_base` indicating where the memory allocator is allowed to allocate memory.
385
2
        let heap_base = vm_proto
386
2
            .global_value("__heap_base")
387
2
            .map_err(|_| NewErr::HeapBaseNotFound)
?0
;
388
389
2
        let memory_total_pages = if heap_base == 0 {
390
0
            config.heap_pages
391
        } else {
392
2
            HeapPages::new((heap_base - 1) / (64 * 1024)) + config.heap_pages + HeapPages::new(1)
393
        };
394
395
2
        if vm_proto
396
2
            .memory_max_pages()
397
2
            .map_or(false, |max| max < memory_total_pages)
398
        {
399
0
            return Err(NewErr::MemoryMaxSizeTooLow);
400
2
        }
401
2
402
2
        let mut host_vm_prototype = HostVmPrototype {
403
2
            vm_proto,
404
2
            common: Box::new(VmCommon {
405
2
                runtime_version,
406
2
                heap_base,
407
2
                registered_functions,
408
2
                heap_pages: config.heap_pages,
409
2
                memory_total_pages,
410
2
            }),
411
2
        };
412
2
413
2
        // Call `Core_version` if no runtime version is known yet.
414
2
        if host_vm_prototype.common.runtime_version.is_none() {
415
0
            let mut vm: HostVm = match host_vm_prototype.run_no_param(
416
0
                "Core_version",
417
0
                StorageProofSizeBehavior::proof_recording_disabled(),
418
0
            ) {
419
0
                Ok(vm) => vm.into(),
420
0
                Err((err, _)) => return Err(NewErr::CoreVersion(CoreVersionError::Start(err))),
421
            };
422
423
            loop {
424
0
                match vm {
425
0
                    HostVm::ReadyToRun(r) => vm = r.run(),
426
0
                    HostVm::Finished(finished) => {
427
0
                        let version =
428
0
                            match CoreVersion::from_slice(finished.value().as_ref().to_vec()) {
429
0
                                Ok(v) => v,
430
                                Err(_) => {
431
0
                                    return Err(NewErr::CoreVersion(CoreVersionError::Decode));
432
                                }
433
                            };
434
435
0
                        host_vm_prototype = finished.into_prototype();
436
0
                        host_vm_prototype.common.runtime_version = Some(version);
437
0
                        break;
438
                    }
439
440
                    // Emitted log lines are ignored.
441
0
                    HostVm::GetMaxLogLevel(resume) => {
442
0
                        vm = resume.resume(0); // Off
443
0
                    }
444
0
                    HostVm::LogEmit(log) => vm = log.resume(),
445
446
0
                    HostVm::Error { error, .. } => {
447
0
                        return Err(NewErr::CoreVersion(CoreVersionError::Run(error)));
448
                    }
449
450
                    // Getting the runtime version is a very core operation, and very few
451
                    // external calls are allowed.
452
0
                    _ => return Err(NewErr::CoreVersion(CoreVersionError::ForbiddenHostFunction)),
453
                }
454
            }
455
2
        }
456
457
        // Success!
458
2
        debug_assert!(host_vm_prototype.common.runtime_version.is_some());
459
2
        Ok(host_vm_prototype)
460
2
    }
461
462
    /// Returns the number of heap pages that were passed to [`HostVmPrototype::new`].
463
0
    pub fn heap_pages(&self) -> HeapPages {
464
0
        self.common.heap_pages
465
0
    }
Unexecuted instantiation: _RNvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB4_15HostVmPrototype10heap_pages
Unexecuted instantiation: _RNvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB4_15HostVmPrototype10heap_pages
466
467
    /// Returns the runtime version found in the module.
468
229
    pub fn runtime_version(&self) -> &CoreVersion {
469
229
        self.common
470
229
            .runtime_version
471
229
            .as_ref()
472
229
            .unwrap_or_else(|| unreachable!())
473
229
    }
_RNvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB4_15HostVmPrototype15runtime_version
Line
Count
Source
468
17
    pub fn runtime_version(&self) -> &CoreVersion {
469
17
        self.common
470
17
            .runtime_version
471
17
            .as_ref()
472
17
            .unwrap_or_else(|| unreachable!())
473
17
    }
_RNvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB4_15HostVmPrototype15runtime_version
Line
Count
Source
468
212
    pub fn runtime_version(&self) -> &CoreVersion {
469
212
        self.common
470
212
            .runtime_version
471
212
            .as_ref()
472
212
            .unwrap_or_else(|| unreachable!())
473
212
    }
474
475
    /// Starts the VM, calling the function passed as parameter.
476
    ///
477
    /// See the documentation of [`StorageProofSizeBehavior`] for an explanation of
478
    /// the `storage_proof_size_behavior` parameter.
479
30
    pub fn run(
480
30
        self,
481
30
        function_to_call: &str,
482
30
        storage_proof_size_behavior: StorageProofSizeBehavior,
483
30
        data: &[u8],
484
30
    ) -> Result<ReadyToRun, (StartErr, Self)> {
485
30
        self.run_vectored(
486
30
            function_to_call,
487
30
            storage_proof_size_behavior,
488
30
            iter::once(data),
489
30
        )
490
30
    }
_RNvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB4_15HostVmPrototype3run
Line
Count
Source
479
30
    pub fn run(
480
30
        self,
481
30
        function_to_call: &str,
482
30
        storage_proof_size_behavior: StorageProofSizeBehavior,
483
30
        data: &[u8],
484
30
    ) -> Result<ReadyToRun, (StartErr, Self)> {
485
30
        self.run_vectored(
486
30
            function_to_call,
487
30
            storage_proof_size_behavior,
488
30
            iter::once(data),
489
30
        )
490
30
    }
Unexecuted instantiation: _RNvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB4_15HostVmPrototype3run
491
492
    /// Same as [`HostVmPrototype::run`], except that the function doesn't need any parameter.
493
    ///
494
    /// See the documentation of [`StorageProofSizeBehavior`] for an explanation of
495
    /// the `storage_proof_size_behavior` parameter.
496
9
    pub fn run_no_param(
497
9
        self,
498
9
        function_to_call: &str,
499
9
        storage_proof_size_behavior: StorageProofSizeBehavior,
500
9
    ) -> Result<ReadyToRun, (StartErr, Self)> {
501
9
        self.run_vectored(
502
9
            function_to_call,
503
9
            storage_proof_size_behavior,
504
9
            iter::empty::<Vec<u8>>(),
505
9
        )
506
9
    }
_RNvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB4_15HostVmPrototype12run_no_param
Line
Count
Source
496
9
    pub fn run_no_param(
497
9
        self,
498
9
        function_to_call: &str,
499
9
        storage_proof_size_behavior: StorageProofSizeBehavior,
500
9
    ) -> Result<ReadyToRun, (StartErr, Self)> {
501
9
        self.run_vectored(
502
9
            function_to_call,
503
9
            storage_proof_size_behavior,
504
9
            iter::empty::<Vec<u8>>(),
505
9
        )
506
9
    }
Unexecuted instantiation: _RNvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB4_15HostVmPrototype12run_no_param
507
508
    /// Same as [`HostVmPrototype::run`], except that the function parameter can be passed as
509
    /// a list of buffers. All the buffers will be concatenated in memory.
510
    ///
511
    /// See the documentation of [`StorageProofSizeBehavior`] for an explanation of
512
    /// the `storage_proof_size_behavior` parameter.
513
179
    pub fn run_vectored(
514
179
        mut self,
515
179
        function_to_call: &str,
516
179
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
179
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
179
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
179
        // Determine the total length of `data`.
520
179
        let mut data_len_u32: u32 = 0;
521
179
        for 
data66
in data.clone() {
522
66
            let len = match u32::try_from(data.as_ref().len()) {
523
66
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
66
            data_len_u32 = match data_len_u32.checked_add(len) {
527
66
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
179
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
179
537
179
        // Prepare the virtual machine for execution.
538
179
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
179
        let data_ptr = match allocator.allocate(
542
179
            &mut MemAccess {
543
179
                vm: MemAccessVm::Prepare(&mut vm),
544
179
                memory_total_pages: self.common.memory_total_pages,
545
179
            },
546
179
            data_len_u32,
547
179
        ) {
548
179
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
179
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
179
            .checked_sub(u32::from(vm.memory_size()))
559
179
        {
560
179
            // If the memory can't be grown, it indicates a bug in the allocator.
561
179
            vm.grow_memory(HeapPages::from(to_grow))
562
179
                .unwrap_or_else(|_| unreachable!());
563
179
        
}0
564
565
        // Writing the input data into the VM.
566
179
        let mut data_ptr_iter = data_ptr;
567
245
        for 
data66
in data {
568
66
            let data = data.as_ref();
569
66
            vm.write_memory(data_ptr_iter, data)
570
66
                .unwrap_or_else(|_| unreachable!());
571
66
            data_ptr_iter = data_ptr_iter
572
66
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
66
                .unwrap_or_else(|| unreachable!());
574
66
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
179
        let 
vm175
= match vm.start(
579
179
            function_to_call,
580
179
            &[
581
179
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
179
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
179
            ],
584
179
        ) {
585
175
            Ok(vm) => vm,
586
4
            Err((error, vm_proto)) => {
587
4
                self.vm_proto = vm_proto;
588
4
                return Err((error.into(), self));
589
            }
590
        };
591
592
175
        Ok(ReadyToRun {
593
175
            resume_value: None,
594
175
            inner: Box::new(Inner {
595
175
                common: self.common,
596
175
                vm,
597
175
                storage_transaction_depth: 0,
598
175
                signatures_batch_verification: None,
599
175
                allocator,
600
175
                storage_proof_size_behavior,
601
175
            }),
602
175
        })
603
179
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherIB1k_RShINtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_EEIB1k_B1W_IB1k_INtNtCs8GO9KFlE3Dq_5alloc3vec3VechEB1T_EEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB3M_3map3MapIB3I_IB3I_IB3I_INtNtNtB3O_7sources4once4OnceB1O_EB55_EB55_EB55_ENcNtB1j_4Left0EIB4A_IB3I_IB56_B2N_EINtNtB3M_7flatten7FlatMapNtNtB9_6header8LogsIterIB4A_INtNtNtB3Q_5array4iter8IntoIterB2W_Kj2_ENcNtB2N_5Right0ENCNvMs2_B6S_NtB6S_9DigestRef14scale_encoding0EENcNtB1j_5Right0EEEB9_
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
7
        for data in 
data.clone()1
{
522
7
            let len = match u32::try_from(data.as_ref().len()) {
523
7
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
7
            data_len_u32 = match data_len_u32.checked_add(len) {
527
7
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
8
        for 
data7
in data {
568
7
            let data = data.as_ref();
569
7
            vm.write_memory(data_ptr_iter, data)
570
7
                .unwrap_or_else(|_| unreachable!());
571
7
            data_ptr_iter = data_ptr_iter
572
7
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
7
                .unwrap_or_else(|| unreachable!());
574
7
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherINtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_EIB1k_Ahj8_IB1k_B1O_B2J_EEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB39_3map3MapINtNtNtB3b_7sources4once4OnceB1O_ENcNtB1j_4Left0EIB3X_INtNtB39_7flatten7FlatMapINtNtNtB3d_5array4iter8IntoIterTB2J_B2J_EKj1_EIB35_IB3X_IB4e_B2J_ENcNtB2E_4Left0EIB3X_IB35_IB3X_B4d_NcNtB2O_4Left0EIB3X_B6o_NcNtB2O_5Right0EENcNtB2E_5Right0EENCINvMs_NtNtB9_6author7runtimeNtB8a_18InherentExtrinsics25inject_raw_inherents_listB2J_B5u_E0ENcNtB1j_5Right0EEEB9_
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
4
        for data in 
data.clone()1
{
522
4
            let len = match u32::try_from(data.as_ref().len()) {
523
4
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
4
            data_len_u32 = match data_len_u32.checked_add(len) {
527
4
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
5
        for 
data4
in data {
568
4
            let data = data.as_ref();
569
4
            vm.write_memory(data_ptr_iter, data)
570
4
                .unwrap_or_else(|_| unreachable!());
571
4
            data_ptr_iter = data_ptr_iter
572
4
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
4
                .unwrap_or_else(|| unreachable!());
574
4
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherRAhj1_IB1k_RShRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB2F_INtNtB2J_3map3MapINtNtNtB2L_7sources4once4OnceB1O_ENcNtB1j_4Left0EIB3C_IB3C_IB3T_B22_ENcNtB1U_5Right0ENcNtB1j_5Right0EEIB3C_IB3C_IB3T_B1Z_ENcNtB1U_4Left0EB5f_EEEB9_
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
3
        for data in 
data.clone()1
{
522
3
            let len = match u32::try_from(data.as_ref().len()) {
523
3
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
3
            data_len_u32 = match data_len_u32.checked_add(len) {
527
3
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
4
        for 
data3
in data {
568
3
            let data = data.as_ref();
569
3
            vm.write_memory(data_ptr_iter, data)
570
3
                .unwrap_or_else(|_| unreachable!());
571
3
            data_ptr_iter = data_ptr_iter
572
3
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
3
                .unwrap_or_else(|| unreachable!());
574
3
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEIB1k_B1O_INtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_EEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB3q_INtNtNtB3w_7sources4once4OnceB1j_EB4m_EINtNtB3u_3map3MapINtNtNtB3y_5slice4iter4IterNtNtNtB7_12runtime_call5tests9HexStringENCNvB5J_s_14execute_blockss0_0EEEB9_
Line
Count
Source
513
4
    pub fn run_vectored(
514
4
        mut self,
515
4
        function_to_call: &str,
516
4
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
4
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
4
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
4
        // Determine the total length of `data`.
520
4
        let mut data_len_u32: u32 = 0;
521
17
        for data in 
data.clone()4
{
522
17
            let len = match u32::try_from(data.as_ref().len()) {
523
17
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
17
            data_len_u32 = match data_len_u32.checked_add(len) {
527
17
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
4
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
4
537
4
        // Prepare the virtual machine for execution.
538
4
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
4
        let data_ptr = match allocator.allocate(
542
4
            &mut MemAccess {
543
4
                vm: MemAccessVm::Prepare(&mut vm),
544
4
                memory_total_pages: self.common.memory_total_pages,
545
4
            },
546
4
            data_len_u32,
547
4
        ) {
548
4
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
4
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
4
            .checked_sub(u32::from(vm.memory_size()))
559
4
        {
560
4
            // If the memory can't be grown, it indicates a bug in the allocator.
561
4
            vm.grow_memory(HeapPages::from(to_grow))
562
4
                .unwrap_or_else(|_| unreachable!());
563
4
        
}0
564
565
        // Writing the input data into the VM.
566
4
        let mut data_ptr_iter = data_ptr;
567
21
        for 
data17
in data {
568
17
            let data = data.as_ref();
569
17
            vm.write_memory(data_ptr_iter, data)
570
17
                .unwrap_or_else(|_| unreachable!());
571
17
            data_ptr_iter = data_ptr_iter
572
17
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
17
                .unwrap_or_else(|| unreachable!());
574
17
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
4
        let vm = match vm.start(
579
4
            function_to_call,
580
4
            &[
581
4
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
4
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
4
            ],
584
4
        ) {
585
4
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
4
        Ok(ReadyToRun {
593
4
            resume_value: None,
594
4
            inner: Box::new(Inner {
595
4
                common: self.common,
596
4
                vm,
597
4
                storage_transaction_depth: 0,
598
4
                signatures_batch_verification: None,
599
4
                allocator,
600
4
                storage_proof_size_behavior,
601
4
            }),
602
4
        })
603
4
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources5empty5EmptyB1j_EEB9_
Line
Count
Source
513
11
    pub fn run_vectored(
514
11
        mut self,
515
11
        function_to_call: &str,
516
11
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
11
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
11
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
11
        // Determine the total length of `data`.
520
11
        let mut data_len_u32: u32 = 0;
521
11
        for 
data0
in data.clone() {
522
0
            let len = match u32::try_from(data.as_ref().len()) {
523
0
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
0
            data_len_u32 = match data_len_u32.checked_add(len) {
527
0
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
11
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
11
537
11
        // Prepare the virtual machine for execution.
538
11
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
11
        let data_ptr = match allocator.allocate(
542
11
            &mut MemAccess {
543
11
                vm: MemAccessVm::Prepare(&mut vm),
544
11
                memory_total_pages: self.common.memory_total_pages,
545
11
            },
546
11
            data_len_u32,
547
11
        ) {
548
11
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
11
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
11
            .checked_sub(u32::from(vm.memory_size()))
559
11
        {
560
11
            // If the memory can't be grown, it indicates a bug in the allocator.
561
11
            vm.grow_memory(HeapPages::from(to_grow))
562
11
                .unwrap_or_else(|_| unreachable!());
563
11
        
}0
564
565
        // Writing the input data into the VM.
566
11
        let mut data_ptr_iter = data_ptr;
567
11
        for 
data0
in data {
568
0
            let data = data.as_ref();
569
0
            vm.write_memory(data_ptr_iter, data)
570
0
                .unwrap_or_else(|_| unreachable!());
571
0
            data_ptr_iter = data_ptr_iter
572
0
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
0
                .unwrap_or_else(|| unreachable!());
574
0
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
11
        let 
vm7
= match vm.start(
579
11
            function_to_call,
580
11
            &[
581
11
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
11
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
11
            ],
584
11
        ) {
585
7
            Ok(vm) => vm,
586
4
            Err((error, vm_proto)) => {
587
4
                self.vm_proto = vm_proto;
588
4
                return Err((error.into(), self));
589
            }
590
        };
591
592
7
        Ok(ReadyToRun {
593
7
            resume_value: None,
594
7
            inner: Box::new(Inner {
595
7
                common: self.common,
596
7
                vm,
597
7
                storage_transaction_depth: 0,
598
7
                signatures_batch_verification: None,
599
7
                allocator,
600
7
                storage_proof_size_behavior,
601
7
            }),
602
7
        })
603
11
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EEB9_
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
1
        for data in data.clone() {
522
1
            let len = match u32::try_from(data.as_ref().len()) {
523
1
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
1
            data_len_u32 = match data_len_u32.checked_add(len) {
527
1
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
2
        for 
data1
in data {
568
1
            let data = data.as_ref();
569
1
            vm.write_memory(data_ptr_iter, data)
570
1
                .unwrap_or_else(|_| unreachable!());
571
1
            data_ptr_iter = data_ptr_iter
572
1
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
1
                .unwrap_or_else(|| unreachable!());
574
1
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtCs2va5m0jqTTM_4core5array4iter8IntoIterB1j_Kj2_EEB9_
Line
Count
Source
513
2
    pub fn run_vectored(
514
2
        mut self,
515
2
        function_to_call: &str,
516
2
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
2
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
2
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
2
        // Determine the total length of `data`.
520
2
        let mut data_len_u32: u32 = 0;
521
4
        for data in 
data.clone()2
{
522
4
            let len = match u32::try_from(data.as_ref().len()) {
523
4
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
4
            data_len_u32 = match data_len_u32.checked_add(len) {
527
4
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
2
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
2
537
2
        // Prepare the virtual machine for execution.
538
2
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
2
        let data_ptr = match allocator.allocate(
542
2
            &mut MemAccess {
543
2
                vm: MemAccessVm::Prepare(&mut vm),
544
2
                memory_total_pages: self.common.memory_total_pages,
545
2
            },
546
2
            data_len_u32,
547
2
        ) {
548
2
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
2
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
2
            .checked_sub(u32::from(vm.memory_size()))
559
2
        {
560
2
            // If the memory can't be grown, it indicates a bug in the allocator.
561
2
            vm.grow_memory(HeapPages::from(to_grow))
562
2
                .unwrap_or_else(|_| unreachable!());
563
2
        
}0
564
565
        // Writing the input data into the VM.
566
2
        let mut data_ptr_iter = data_ptr;
567
6
        for 
data4
in data {
568
4
            let data = data.as_ref();
569
4
            vm.write_memory(data_ptr_iter, data)
570
4
                .unwrap_or_else(|_| unreachable!());
571
4
            data_ptr_iter = data_ptr_iter
572
4
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
4
                .unwrap_or_else(|| unreachable!());
574
4
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
2
        let vm = match vm.start(
579
2
            function_to_call,
580
2
            &[
581
2
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
2
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
2
            ],
584
2
        ) {
585
2
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
2
        Ok(ReadyToRun {
593
2
            resume_value: None,
594
2
            inner: Box::new(Inner {
595
2
                common: self.common,
596
2
                vm,
597
2
                storage_transaction_depth: 0,
598
2
                signatures_batch_verification: None,
599
2
                allocator,
600
2
                storage_proof_size_behavior,
601
2
            }),
602
2
        })
603
2
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EEB9_
Line
Count
Source
513
30
    pub fn run_vectored(
514
30
        mut self,
515
30
        function_to_call: &str,
516
30
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
30
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
30
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
30
        // Determine the total length of `data`.
520
30
        let mut data_len_u32: u32 = 0;
521
30
        for data in data.clone() {
522
30
            let len = match u32::try_from(data.as_ref().len()) {
523
30
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
30
            data_len_u32 = match data_len_u32.checked_add(len) {
527
30
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
30
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
30
537
30
        // Prepare the virtual machine for execution.
538
30
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
30
        let data_ptr = match allocator.allocate(
542
30
            &mut MemAccess {
543
30
                vm: MemAccessVm::Prepare(&mut vm),
544
30
                memory_total_pages: self.common.memory_total_pages,
545
30
            },
546
30
            data_len_u32,
547
30
        ) {
548
30
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
30
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
30
            .checked_sub(u32::from(vm.memory_size()))
559
30
        {
560
30
            // If the memory can't be grown, it indicates a bug in the allocator.
561
30
            vm.grow_memory(HeapPages::from(to_grow))
562
30
                .unwrap_or_else(|_| unreachable!());
563
30
        
}0
564
565
        // Writing the input data into the VM.
566
30
        let mut data_ptr_iter = data_ptr;
567
60
        for 
data30
in data {
568
30
            let data = data.as_ref();
569
30
            vm.write_memory(data_ptr_iter, data)
570
30
                .unwrap_or_else(|_| unreachable!());
571
30
            data_ptr_iter = data_ptr_iter
572
30
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
30
                .unwrap_or_else(|| unreachable!());
574
30
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
30
        let vm = match vm.start(
579
30
            function_to_call,
580
30
            &[
581
30
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
30
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
30
            ],
584
30
        ) {
585
30
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
30
        Ok(ReadyToRun {
593
30
            resume_value: None,
594
30
            inner: Box::new(Inner {
595
30
                common: self.common,
596
30
                vm,
597
30
                storage_transaction_depth: 0,
598
30
                signatures_batch_verification: None,
599
30
                allocator,
600
30
                storage_proof_size_behavior,
601
30
            }),
602
30
        })
603
30
    }
_RINvMs_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources5empty5EmptyB1j_EEB9_
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
1
        for 
data0
in data.clone() {
522
0
            let len = match u32::try_from(data.as_ref().len()) {
523
0
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
0
            data_len_u32 = match data_len_u32.checked_add(len) {
527
0
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
1
        for 
data0
in data {
568
0
            let data = data.as_ref();
569
0
            vm.write_memory(data_ptr_iter, data)
570
0
                .unwrap_or_else(|_| unreachable!());
571
0
            data_ptr_iter = data_ptr_iter
572
0
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
0
                .unwrap_or_else(|| unreachable!());
574
0
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EECsi8ZZk7cbLT3_18smoldot_light_wasm
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherIB1k_RShINtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_EEIB1k_B1W_IB1k_INtNtCs8GO9KFlE3Dq_5alloc3vec3VechEB1T_EEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB3M_3map3MapIB3I_IB3I_IB3I_INtNtNtB3O_7sources4once4OnceB1O_EB55_EB55_EB55_ENcNtB1j_4Left0EIB4A_IB3I_IB56_B2N_EINtNtB3M_7flatten7FlatMapNtNtB9_6header8LogsIterIB4A_INtNtNtB3Q_5array4iter8IntoIterB2W_Kj2_ENcNtB2N_5Right0ENCNvMs2_B6S_NtB6S_9DigestRef14scale_encoding0EENcNtB1j_5Right0EEEB9_
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtCs5MhOSyk0iiL_6either6EitherINtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_EIB1k_Ahj8_IB1k_B1O_B2J_EEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB39_3map3MapINtNtNtB3b_7sources4once4OnceB1O_ENcNtB1j_4Left0EIB3X_INtNtB39_7flatten7FlatMapINtNtNtB3d_5array4iter8IntoIterTB2J_B2J_EKj1_EIB35_IB3X_IB4e_B2J_ENcNtB2E_4Left0EIB3X_IB35_IB3X_B4d_NcNtB2O_4Left0EIB3X_B6o_NcNtB2O_5Right0EENcNtB2E_5Right0EENCINvMs_NtNtB9_6author7runtimeNtB8a_18InherentExtrinsics25inject_raw_inherents_listB2J_B5u_E0ENcNtB1j_5Right0EEEB9_
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources5empty5EmptyB1j_EEB9_
Line
Count
Source
513
126
    pub fn run_vectored(
514
126
        mut self,
515
126
        function_to_call: &str,
516
126
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
126
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
126
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
126
        // Determine the total length of `data`.
520
126
        let mut data_len_u32: u32 = 0;
521
126
        for 
data0
in data.clone() {
522
0
            let len = match u32::try_from(data.as_ref().len()) {
523
0
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
0
            data_len_u32 = match data_len_u32.checked_add(len) {
527
0
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
126
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
126
537
126
        // Prepare the virtual machine for execution.
538
126
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
126
        let data_ptr = match allocator.allocate(
542
126
            &mut MemAccess {
543
126
                vm: MemAccessVm::Prepare(&mut vm),
544
126
                memory_total_pages: self.common.memory_total_pages,
545
126
            },
546
126
            data_len_u32,
547
126
        ) {
548
126
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
126
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
126
            .checked_sub(u32::from(vm.memory_size()))
559
126
        {
560
126
            // If the memory can't be grown, it indicates a bug in the allocator.
561
126
            vm.grow_memory(HeapPages::from(to_grow))
562
126
                .unwrap_or_else(|_| unreachable!());
563
126
        
}0
564
565
        // Writing the input data into the VM.
566
126
        let mut data_ptr_iter = data_ptr;
567
126
        for 
data0
in data {
568
0
            let data = data.as_ref();
569
0
            vm.write_memory(data_ptr_iter, data)
570
0
                .unwrap_or_else(|_| unreachable!());
571
0
            data_ptr_iter = data_ptr_iter
572
0
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
0
                .unwrap_or_else(|| unreachable!());
574
0
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
126
        let vm = match vm.start(
579
126
            function_to_call,
580
126
            &[
581
126
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
126
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
126
            ],
584
126
        ) {
585
126
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
126
        Ok(ReadyToRun {
593
126
            resume_value: None,
594
126
            inner: Box::new(Inner {
595
126
                common: self.common,
596
126
                vm,
597
126
                storage_transaction_depth: 0,
598
126
                signatures_batch_verification: None,
599
126
                allocator,
600
126
                storage_proof_size_behavior,
601
126
            }),
602
126
        })
603
126
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EEB9_
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EEB9_
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources5empty5EmptyB1j_EEB9_
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EECshebkd5t2Jvd_25json_rpc_general_requests
_RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources5empty5EmptyB1j_EECs5NPiOP1M6me_17smoldot_full_node
Line
Count
Source
513
1
    pub fn run_vectored(
514
1
        mut self,
515
1
        function_to_call: &str,
516
1
        storage_proof_size_behavior: StorageProofSizeBehavior,
517
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
518
1
    ) -> Result<ReadyToRun, (StartErr, Self)> {
519
1
        // Determine the total length of `data`.
520
1
        let mut data_len_u32: u32 = 0;
521
1
        for 
data0
in data.clone() {
522
0
            let len = match u32::try_from(data.as_ref().len()) {
523
0
                Ok(v) => v,
524
0
                Err(_) => return Err((StartErr::DataSizeOverflow, self)),
525
            };
526
0
            data_len_u32 = match data_len_u32.checked_add(len) {
527
0
                Some(v) => v,
528
0
                None => return Err((StartErr::DataSizeOverflow, self)),
529
            };
530
        }
531
532
        // Initialize the state of the memory allocator. This is the allocator that is used in
533
        // order to allocate space for the input data, and also later used when the Wasm code
534
        // requests variable-length data.
535
1
        let mut allocator = allocator::FreeingBumpHeapAllocator::new(self.common.heap_base);
536
1
537
1
        // Prepare the virtual machine for execution.
538
1
        let mut vm = self.vm_proto.prepare();
539
540
        // Write the input data in the VM's memory using the allocator.
541
1
        let data_ptr = match allocator.allocate(
542
1
            &mut MemAccess {
543
1
                vm: MemAccessVm::Prepare(&mut vm),
544
1
                memory_total_pages: self.common.memory_total_pages,
545
1
            },
546
1
            data_len_u32,
547
1
        ) {
548
1
            Ok(p) => p,
549
            Err(_) => {
550
0
                self.vm_proto = vm.into_prototype();
551
0
                return Err((StartErr::DataSizeOverflow, self));
552
            }
553
        };
554
555
        // While the allocator has reserved memory, it might have reserved more memory than its
556
        // current size.
557
1
        if let Some(to_grow) = ((data_ptr + data_len_u32).saturating_sub(1) / (64 * 1024) + 1)
558
1
            .checked_sub(u32::from(vm.memory_size()))
559
1
        {
560
1
            // If the memory can't be grown, it indicates a bug in the allocator.
561
1
            vm.grow_memory(HeapPages::from(to_grow))
562
1
                .unwrap_or_else(|_| unreachable!());
563
1
        
}0
564
565
        // Writing the input data into the VM.
566
1
        let mut data_ptr_iter = data_ptr;
567
1
        for 
data0
in data {
568
0
            let data = data.as_ref();
569
0
            vm.write_memory(data_ptr_iter, data)
570
0
                .unwrap_or_else(|_| unreachable!());
571
0
            data_ptr_iter = data_ptr_iter
572
0
                .checked_add(u32::try_from(data.len()).unwrap_or_else(|_| unreachable!()))
573
0
                .unwrap_or_else(|| unreachable!());
574
0
        }
575
576
        // Now start executing the function. We pass as parameter the location and size of the
577
        // input data.
578
1
        let vm = match vm.start(
579
1
            function_to_call,
580
1
            &[
581
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_ptr.to_ne_bytes())),
582
1
                vm::WasmValue::I32(i32::from_ne_bytes(data_len_u32.to_ne_bytes())),
583
1
            ],
584
1
        ) {
585
1
            Ok(vm) => vm,
586
0
            Err((error, vm_proto)) => {
587
0
                self.vm_proto = vm_proto;
588
0
                return Err((error.into(), self));
589
            }
590
        };
591
592
1
        Ok(ReadyToRun {
593
1
            resume_value: None,
594
1
            inner: Box::new(Inner {
595
1
                common: self.common,
596
1
                vm,
597
1
                storage_transaction_depth: 0,
598
1
                signatures_batch_verification: None,
599
1
                allocator,
600
1
                storage_proof_size_behavior,
601
1
            }),
602
1
        })
603
1
    }
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EECsfrWDnknO4Z6_6author
Unexecuted instantiation: _RINvMs_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototype12run_vectoredRRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1j_EECshuONSvRyUMf_14json_rpc_basic
604
}
605
606
impl fmt::Debug for HostVmPrototype {
607
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
608
0
        f.debug_tuple("HostVmPrototype").finish()
609
0
    }
Unexecuted instantiation: _RNvXs0_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_15HostVmPrototypeNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs0_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_15HostVmPrototypeNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
610
}
611
612
/// Running virtual machine.
613
#[must_use]
614
#[derive(derive_more::From, Debug)]
615
pub enum HostVm {
616
    /// Wasm virtual machine is ready to be run. Call [`ReadyToRun::run`] to make progress.
617
    #[from]
618
    ReadyToRun(ReadyToRun),
619
    /// Function execution has succeeded. Contains the return value of the call.
620
    ///
621
    /// The trie root hash of all the child tries must be recalculated and written to the main trie
622
    /// similar to when a [`ExternalStorageRoot`] with a `child_trie` of `None` is generated. See
623
    /// the documentation of [`ExternalStorageRoot`].
624
    #[from]
625
    Finished(Finished),
626
    /// The Wasm blob did something that doesn't conform to the runtime environment.
627
    Error {
628
        /// Virtual machine ready to be used again.
629
        prototype: HostVmPrototype,
630
        /// Error that happened.
631
        error: Error,
632
    },
633
    /// Must load an storage value.
634
    #[from]
635
    ExternalStorageGet(ExternalStorageGet),
636
    /// Must set an storage value.
637
    #[from]
638
    ExternalStorageSet(ExternalStorageSet),
639
    /// See documentation of [`ExternalStorageAppend`].
640
    #[from]
641
    ExternalStorageAppend(ExternalStorageAppend),
642
    /// Must remove all the storage values starting with a certain prefix.
643
    #[from]
644
    ExternalStorageClearPrefix(ExternalStorageClearPrefix),
645
    /// Must provide the trie root hash of the storage and write the trie root hash of child tries
646
    /// to the main trie.
647
    #[from]
648
    ExternalStorageRoot(ExternalStorageRoot),
649
    /// Need to provide the storage key that follows a specific one.
650
    #[from]
651
    ExternalStorageNextKey(ExternalStorageNextKey),
652
    /// Must set off-chain index value.
653
    #[from]
654
    ExternalOffchainIndexSet(ExternalOffchainIndexSet),
655
    /// Must load an offchain storage value.
656
    #[from]
657
    ExternalOffchainStorageGet(ExternalOffchainStorageGet),
658
    /// Must set value of an off-chain storage entry.
659
    #[from]
660
    ExternalOffchainStorageSet(ExternalOffchainStorageSet),
661
    /// Need to provide the current timestamp.
662
    #[from]
663
    OffchainTimestamp(OffchainTimestamp),
664
    /// Must return random seed.
665
    #[from]
666
    OffchainRandomSeed(OffchainRandomSeed),
667
    /// Submit a transaction from offchain worker.
668
    #[from]
669
    OffchainSubmitTransaction(OffchainSubmitTransaction),
670
    /// Need to verify whether a signature is valid.
671
    #[from]
672
    SignatureVerification(SignatureVerification),
673
    /// Need to call `Core_version` on the given Wasm code and return the raw output (i.e.
674
    /// still SCALE-encoded), or an error if the call has failed.
675
    #[from]
676
    CallRuntimeVersion(CallRuntimeVersion),
677
    /// Declares the start of a storage transaction. See [`HostVm::EndStorageTransaction`].
678
    #[from]
679
    StartStorageTransaction(StartStorageTransaction),
680
    /// Ends a storage transaction. All changes made to the storage (e.g. through a
681
    /// [`HostVm::ExternalStorageSet`]) since the previous
682
    /// [`HostVm::StartStorageTransaction`] must be rolled back if `rollback` is true.
683
    ///
684
    /// Guaranteed by the code in this module to never happen if no transaction is in progress.
685
    /// If the runtime attempts to end a non-existing transaction, an [`HostVm::Error`] is
686
    /// generated instead.
687
    EndStorageTransaction {
688
        /// Object used to resume execution.
689
        resume: EndStorageTransaction,
690
        /// If true, changes must be rolled back.
691
        rollback: bool,
692
    },
693
    /// Need to provide the maximum log level.
694
    #[from]
695
    GetMaxLogLevel(GetMaxLogLevel),
696
    /// Runtime has emitted a log entry.
697
    #[from]
698
    LogEmit(LogEmit),
699
}
700
701
impl HostVm {
702
    /// Cancels execution of the virtual machine and returns back the prototype.
703
0
    pub fn into_prototype(self) -> HostVmPrototype {
704
0
        match self {
705
0
            HostVm::ReadyToRun(inner) => inner.inner.into_prototype(),
706
0
            HostVm::Finished(inner) => inner.inner.into_prototype(),
707
0
            HostVm::Error { prototype, .. } => prototype,
708
0
            HostVm::ExternalStorageGet(inner) => inner.inner.into_prototype(),
709
0
            HostVm::ExternalStorageSet(inner) => inner.inner.into_prototype(),
710
0
            HostVm::ExternalStorageAppend(inner) => inner.inner.into_prototype(),
711
0
            HostVm::ExternalStorageClearPrefix(inner) => inner.inner.into_prototype(),
712
0
            HostVm::ExternalStorageRoot(inner) => inner.inner.into_prototype(),
713
0
            HostVm::ExternalStorageNextKey(inner) => inner.inner.into_prototype(),
714
0
            HostVm::ExternalOffchainIndexSet(inner) => inner.inner.into_prototype(),
715
0
            HostVm::ExternalOffchainStorageGet(inner) => inner.inner.into_prototype(),
716
0
            HostVm::ExternalOffchainStorageSet(inner) => inner.inner.into_prototype(),
717
0
            HostVm::OffchainTimestamp(inner) => inner.inner.into_prototype(),
718
0
            HostVm::OffchainRandomSeed(inner) => inner.inner.into_prototype(),
719
0
            HostVm::OffchainSubmitTransaction(inner) => inner.inner.into_prototype(),
720
0
            HostVm::SignatureVerification(inner) => inner.inner.into_prototype(),
721
0
            HostVm::CallRuntimeVersion(inner) => inner.inner.into_prototype(),
722
0
            HostVm::StartStorageTransaction(inner) => inner.inner.into_prototype(),
723
0
            HostVm::EndStorageTransaction { resume, .. } => resume.inner.into_prototype(),
724
0
            HostVm::GetMaxLogLevel(inner) => inner.inner.into_prototype(),
725
0
            HostVm::LogEmit(inner) => inner.inner.into_prototype(),
726
        }
727
0
    }
Unexecuted instantiation: _RNvMs1_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_6HostVm14into_prototype
Unexecuted instantiation: _RNvMs1_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_6HostVm14into_prototype
728
}
729
730
/// Virtual machine is ready to run.
731
pub struct ReadyToRun {
732
    inner: Box<Inner>,
733
    resume_value: Option<vm::WasmValue>,
734
}
735
736
impl ReadyToRun {
737
    /// Runs the virtual machine until something important happens.
738
    ///
739
    /// > **Note**: This is when the actual CPU-heavy computation happens.
740
1.49k
    pub fn run(mut self) -> HostVm {
741
        loop {
742
34.4k
            match self.run_once() {
743
32.9k
                HostVm::ReadyToRun(r) => self = r,
744
1.49k
                other => return other,
745
1.49k
            }
746
1.49k
        }
747
1.49k
    }
_RNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_10ReadyToRun3run
Line
Count
Source
740
1.15k
    pub fn run(mut self) -> HostVm {
741
        loop {
742
29.2k
            match self.run_once() {
743
28.0k
                HostVm::ReadyToRun(r) => self = r,
744
1.15k
                other => return other,
745
1.15k
            }
746
1.15k
        }
747
1.15k
    }
_RNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_10ReadyToRun3run
Line
Count
Source
740
338
    pub fn run(mut self) -> HostVm {
741
        loop {
742
5.20k
            match self.run_once() {
743
4.86k
                HostVm::ReadyToRun(r) => self = r,
744
338
                other => return other,
745
338
            }
746
338
        }
747
338
    }
748
749
34.4k
    fn run_once(mut self) -> HostVm {
750
        // `vm::ExecOutcome::Interrupted` is by far the variant that requires the most
751
        // handling code. As such, special-case all other variants before.
752
34.4k
        let (
id, params34.2k
) = match self.inner.vm.run(self.resume_value) {
753
34.2k
            Ok(vm::ExecOutcome::Interrupted { id, params }) => (id, params),
754
755
            Ok(vm::ExecOutcome::Finished {
756
169
                return_value: Ok(Some(vm::WasmValue::I64(ret))),
757
169
            }) => {
758
169
                // Wasm virtual machine has successfully returned.
759
169
760
169
                if self.inner.storage_transaction_depth > 0 {
761
0
                    return HostVm::Error {
762
0
                        prototype: self.inner.into_prototype(),
763
0
                        error: Error::FinishedWithPendingTransaction,
764
0
                    };
765
169
                }
766
169
767
169
                // Turn the `i64` into a `u64`, not changing any bit.
768
169
                let ret = u64::from_ne_bytes(ret.to_ne_bytes());
769
169
770
169
                // According to the runtime environment specification, the return value is two
771
169
                // consecutive I32s representing the length and size of the SCALE-encoded
772
169
                // return value.
773
169
                let value_size = u32::try_from(ret >> 32).unwrap_or_else(|_| unreachable!());
774
169
                let value_ptr = u32::try_from(ret & 0xffff_ffff).unwrap_or_else(|_| unreachable!());
775
169
776
169
                if value_size.saturating_add(value_ptr)
777
169
                    <= u32::from(self.inner.vm.memory_size()) * 64 * 1024
778
                {
779
165
                    return HostVm::Finished(Finished {
780
165
                        inner: self.inner,
781
165
                        value_ptr,
782
165
                        value_size,
783
165
                    });
784
4
                }
785
4
                let error = Error::ReturnedPtrOutOfRange {
786
4
                    pointer: value_ptr,
787
4
                    size: value_size,
788
4
                    memory_size: u32::from(self.inner.vm.memory_size()) * 64 * 1024,
789
4
                };
790
4
791
4
                return HostVm::Error {
792
4
                    prototype: self.inner.into_prototype(),
793
4
                    error,
794
4
                };
795
            }
796
797
            Ok(vm::ExecOutcome::Finished {
798
2
                return_value: Ok(return_value),
799
2
            }) => {
800
2
                // The Wasm function has successfully returned, but the specs require that it
801
2
                // returns a `i64`.
802
2
                return HostVm::Error {
803
2
                    prototype: self.inner.into_prototype(),
804
2
                    error: Error::BadReturnValue {
805
2
                        actual: return_value.map(|v| v.ty()),
_RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces0_0Bb_
Line
Count
Source
805
2
                        actual: return_value.map(|v| v.ty()),
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces0_0Bb_
806
2
                    },
807
2
                };
808
            }
809
810
            Ok(vm::ExecOutcome::Finished {
811
2
                return_value: Err(err),
812
2
            }) => {
813
2
                return HostVm::Error {
814
2
                    error: Error::Trap(err),
815
2
                    prototype: self.inner.into_prototype(),
816
2
                };
817
            }
818
819
            Err(vm::RunErr::BadValueTy { .. }) => {
820
                // Tried to inject back the value returned by a host function, but it doesn't
821
                // match what the Wasm code expects. Given that we check the host function
822
                // signatures at initialization, this indicates a bug in this implementation.
823
0
                unreachable!()
824
            }
825
826
            Err(vm::RunErr::Poisoned) => {
827
                // Can only happen if there's a bug somewhere.
828
0
                unreachable!()
829
            }
830
        };
831
832
        // The Wasm code has called an host_fn. The `id` is a value that we passed
833
        // at initialization, and corresponds to an index in `registered_functions`.
834
34.2k
        let 
host_fn34.2k
= match self.inner.common.registered_functions.get(id) {
835
34.2k
            Some(FunctionImport::Resolved(f)) => *f,
836
2
            Some(FunctionImport::Unresolved { name, module }) => {
837
2
                return HostVm::Error {
838
2
                    error: Error::UnresolvedFunctionCalled {
839
2
                        function: name.clone(),
840
2
                        module_name: module.clone(),
841
2
                    },
842
2
                    prototype: self.inner.into_prototype(),
843
2
                };
844
            }
845
0
            None => unreachable!(),
846
        };
847
848
        // Passed a parameter index. Produces an `impl AsRef<[u8]>`.
849
        macro_rules! expect_pointer_size {
850
            ($num:expr) => {{
851
                let val = match &params[$num] {
852
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
853
                    // The signatures are checked at initialization and the Wasm VM ensures that
854
                    // the proper parameter types are provided.
855
                    _ => unreachable!(),
856
                };
857
858
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
859
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
860
861
                let result = self.inner.vm.read_memory(ptr, len);
862
                match result {
863
                    Ok(v) => v,
864
                    Err(vm::OutOfBoundsError) => {
865
                        drop(result);
866
                        return HostVm::Error {
867
                            error: Error::ParamOutOfRange {
868
                                function: host_fn.name(),
869
                                param_num: $num,
870
                                pointer: ptr,
871
                                length: len,
872
                            },
873
                            prototype: self.inner.into_prototype(),
874
                        };
875
                    }
876
                }
877
            }};
878
        }
879
880
        macro_rules! expect_pointer_size_raw {
881
            ($num:expr) => {{
882
                let val = match &params[$num] {
883
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
884
                    // The signatures are checked at initialization and the Wasm VM ensures that
885
                    // the proper parameter types are provided.
886
                    _ => unreachable!(),
887
                };
888
889
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
890
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
891
892
                if len.saturating_add(ptr) > u32::from(self.inner.vm.memory_size()) * 64 * 1024 {
893
                    return HostVm::Error {
894
                        error: Error::ParamOutOfRange {
895
                            function: host_fn.name(),
896
                            param_num: $num,
897
                            pointer: ptr,
898
                            length: len,
899
                        },
900
                        prototype: self.inner.into_prototype(),
901
                    };
902
                }
903
904
                (ptr, len)
905
            }};
906
        }
907
908
        macro_rules! expect_pointer_constant_size {
909
            ($num:expr, $size:expr) => {{
910
                let ptr = match params[$num] {
911
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
912
                    // The signatures are checked at initialization and the Wasm VM ensures that
913
                    // the proper parameter types are provided.
914
                    _ => unreachable!(),
915
                };
916
917
                let result = self.inner.vm.read_memory(ptr, $size);
918
                match result {
919
                    Ok(v) => {
920
                        *<&[u8; $size]>::try_from(v.as_ref()).unwrap_or_else(|_| unreachable!())
921
                    }
922
                    Err(vm::OutOfBoundsError) => {
923
                        drop(result);
924
                        return HostVm::Error {
925
                            error: Error::ParamOutOfRange {
926
                                function: host_fn.name(),
927
                                param_num: $num,
928
                                pointer: ptr,
929
                                length: $size,
930
                            },
931
                            prototype: self.inner.into_prototype(),
932
                        };
933
                    }
934
                }
935
            }};
936
        }
937
938
        macro_rules! expect_pointer_constant_size_raw {
939
            ($num:expr, $size:expr) => {{
940
                let ptr = match params[$num] {
941
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
942
                    // The signatures are checked at initialization and the Wasm VM ensures that
943
                    // the proper parameter types are provided.
944
                    _ => unreachable!(),
945
                };
946
947
                if u32::saturating_add($size, ptr)
948
                    > u32::from(self.inner.vm.memory_size()) * 64 * 1024
949
                {
950
                    return HostVm::Error {
951
                        error: Error::ParamOutOfRange {
952
                            function: host_fn.name(),
953
                            param_num: $num,
954
                            pointer: ptr,
955
                            length: $size,
956
                        },
957
                        prototype: self.inner.into_prototype(),
958
                    };
959
                }
960
961
                ptr
962
            }};
963
        }
964
965
        macro_rules! expect_u32 {
966
            ($num:expr) => {{
967
                match &params[$num] {
968
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
969
                    // The signatures are checked at initialization and the Wasm VM ensures that
970
                    // the proper parameter types are provided.
971
                    _ => unreachable!(),
972
                }
973
            }};
974
        }
975
976
        macro_rules! expect_offchain_storage_kind {
977
            ($num:expr) => {{
978
                match &params[$num] {
979
                    // `0` indicates `StorageKind::PERSISTENT`, the only kind of offchain
980
                    // storage that is available.
981
                    vm::WasmValue::I32(0) => true,
982
                    // `1` indicates `StorageKind::LOCAL`, which is valid but has never been
983
                    // implemented in Substrate.
984
                    vm::WasmValue::I32(1) => false,
985
                    vm::WasmValue::I32(_) => {
986
                        return HostVm::Error {
987
                            error: Error::ParamDecodeError,
988
                            prototype: self.inner.into_prototype(),
989
                        };
990
                    }
991
                    // The signatures are checked at initialization and the Wasm VM ensures that
992
                    // the proper parameter types are provided.
993
                    _ => unreachable!(),
994
                }
995
            }};
996
        }
997
998
        macro_rules! expect_state_version {
999
            ($num:expr) => {{
1000
                match &params[$num] {
1001
                    vm::WasmValue::I32(0) => TrieEntryVersion::V0,
1002
                    vm::WasmValue::I32(1) => TrieEntryVersion::V1,
1003
                    vm::WasmValue::I32(_) => {
1004
                        return HostVm::Error {
1005
                            error: Error::ParamDecodeError,
1006
                            prototype: self.inner.into_prototype(),
1007
                        };
1008
                    }
1009
                    // The signatures are checked at initialization and the Wasm VM ensures that
1010
                    // the proper parameter types are provided.
1011
                    _ => unreachable!(),
1012
                }
1013
            }};
1014
        }
1015
1016
        // TODO: implement all functions and remove this macro
1017
        macro_rules! host_fn_not_implemented {
1018
            () => {{
1019
                return HostVm::Error {
1020
                    error: Error::HostFunctionNotImplemented {
1021
                        function: host_fn.name(),
1022
                    },
1023
                    prototype: self.inner.into_prototype(),
1024
                };
1025
            }};
1026
        }
1027
1028
        // Handle the function calls.
1029
        // Some of these enum variants simply change the state of `self`, while most of them
1030
        // instead return an `ExternalVm` to the user.
1031
34.2k
        match host_fn {
1032
            HostFunction::ext_storage_set_version_1 => {
1033
300
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1034
300
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1035
300
                HostVm::ExternalStorageSet(ExternalStorageSet {
1036
300
                    key_ptr,
1037
300
                    key_size,
1038
300
                    child_trie_ptr_size: None,
1039
300
                    value: Some((value_ptr, value_size)),
1040
300
                    inner: self.inner,
1041
300
                })
1042
            }
1043
            HostFunction::ext_storage_get_version_1 => {
1044
655
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1045
655
                HostVm::ExternalStorageGet(ExternalStorageGet {
1046
655
                    key_ptr,
1047
655
                    key_size,
1048
655
                    child_trie_ptr_size: None,
1049
655
                    calling: id,
1050
655
                    value_out_ptr: None,
1051
655
                    offset: 0,
1052
655
                    max_size: u32::MAX,
1053
655
                    inner: self.inner,
1054
655
                })
1055
            }
1056
            HostFunction::ext_storage_read_version_1 => {
1057
10
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1058
10
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(1);
1059
10
                let offset = expect_u32!(2);
1060
10
                HostVm::ExternalStorageGet(ExternalStorageGet {
1061
10
                    key_ptr,
1062
10
                    key_size,
1063
10
                    child_trie_ptr_size: None,
1064
10
                    calling: id,
1065
10
                    value_out_ptr: Some(value_out_ptr),
1066
10
                    offset,
1067
10
                    max_size: value_out_size,
1068
10
                    inner: self.inner,
1069
10
                })
1070
            }
1071
            HostFunction::ext_storage_clear_version_1 => {
1072
71
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1073
71
                HostVm::ExternalStorageSet(ExternalStorageSet {
1074
71
                    key_ptr,
1075
71
                    key_size,
1076
71
                    child_trie_ptr_size: None,
1077
71
                    value: None,
1078
71
                    inner: self.inner,
1079
71
                })
1080
            }
1081
            HostFunction::ext_storage_exists_version_1 => {
1082
16
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1083
16
                HostVm::ExternalStorageGet(ExternalStorageGet {
1084
16
                    key_ptr,
1085
16
                    key_size,
1086
16
                    child_trie_ptr_size: None,
1087
16
                    calling: id,
1088
16
                    value_out_ptr: None,
1089
16
                    offset: 0,
1090
16
                    max_size: 0,
1091
16
                    inner: self.inner,
1092
16
                })
1093
            }
1094
            HostFunction::ext_storage_clear_prefix_version_1 => {
1095
1
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1096
1
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1097
1
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1098
1
                    child_trie_ptr_size: None,
1099
1
                    inner: self.inner,
1100
1
                    max_keys_to_remove: None,
1101
1
                    calling: id,
1102
1
                })
1103
            }
1104
            HostFunction::ext_storage_clear_prefix_version_2 => {
1105
4
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1106
1107
4
                let max_keys_to_remove = {
1108
4
                    let input = expect_pointer_size!(1);
1109
4
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1110
4
                        nom::Parser::parse(
1111
4
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1112
4
                                nom::number::streaming::le_u32,
1113
4
                            )),
1114
4
                            input.as_ref(),
1115
4
                        )
1116
4
                        .map(|(_, parse_result)| parse_result);
_RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces1_0Bb_
Line
Count
Source
1116
4
                        .map(|(_, parse_result)| parse_result);
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces1_0Bb_
1117
4
1118
4
                    match parsing_result {
1119
4
                        Ok(val) => Ok(val),
1120
0
                        Err(_) => Err(()),
1121
                    }
1122
                };
1123
1124
4
                let max_keys_to_remove = match max_keys_to_remove {
1125
4
                    Ok(l) => l,
1126
                    Err(()) => {
1127
0
                        return HostVm::Error {
1128
0
                            error: Error::ParamDecodeError,
1129
0
                            prototype: self.inner.into_prototype(),
1130
0
                        };
1131
                    }
1132
                };
1133
1134
4
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1135
4
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1136
4
                    child_trie_ptr_size: None,
1137
4
                    inner: self.inner,
1138
4
                    max_keys_to_remove,
1139
4
                    calling: id,
1140
4
                })
1141
            }
1142
            HostFunction::ext_storage_root_version_1 => {
1143
1
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1144
1
                    inner: self.inner,
1145
1
                    calling: id,
1146
1
                    child_trie_ptr_size: None,
1147
1
                })
1148
            }
1149
            HostFunction::ext_storage_root_version_2 => {
1150
                // The `ext_storage_root_version_2` host function gets passed as parameter the
1151
                // state version of the runtime. This is in fact completely unnecessary as the
1152
                // same information is found in the runtime specification, and this parameter
1153
                // should be considered as a historical accident. We verify that the version
1154
                // provided as parameter is the same as the one in the specification.
1155
4
                let version_param = expect_state_version!(0);
1156
4
                let version_spec = self
1157
4
                    .inner
1158
4
                    .common
1159
4
                    .runtime_version
1160
4
                    .as_ref()
1161
4
                    .unwrap_or_else(|| unreachable!())
1162
4
                    .decode()
1163
4
                    .state_version
1164
4
                    .unwrap_or(TrieEntryVersion::V0);
1165
4
1166
4
                if version_param != version_spec {
1167
0
                    return HostVm::Error {
1168
0
                        error: Error::StateVersionMismatch {
1169
0
                            parameter: version_param,
1170
0
                            specification: version_spec,
1171
0
                        },
1172
0
                        prototype: self.inner.into_prototype(),
1173
0
                    };
1174
4
                }
1175
4
1176
4
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1177
4
                    inner: self.inner,
1178
4
                    calling: id,
1179
4
                    child_trie_ptr_size: None,
1180
4
                })
1181
            }
1182
            HostFunction::ext_storage_changes_root_version_1 => {
1183
                // The changes trie is an obsolete attempt at having a second trie containing, for
1184
                // each storage item, the latest block height where this item has been modified.
1185
                // When this function returns `None`, it indicates that the changes trie is
1186
                // disabled. While this function used to be called by the runtimes of
1187
                // Westend/Polkadot/Kusama (and maybe others), it has never returned anything else
1188
                // but `None`. The entire changes trie mechanism was ultimately removed in
1189
                // October 2021.
1190
                // This function is no longer called by recent runtimes, but must be preserved for
1191
                // backwards compatibility.
1192
1
                self.inner.alloc_write_and_return_pointer_size(
1193
1
                    HostFunction::ext_storage_changes_root_version_1.name(),
1194
1
                    iter::once(&[0][..]),
1195
1
                )
1196
            }
1197
            HostFunction::ext_storage_next_key_version_1 => {
1198
1
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1199
1
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1200
1
                    key_ptr,
1201
1
                    key_size,
1202
1
                    child_trie_ptr_size: None,
1203
1
                    inner: self.inner,
1204
1
                })
1205
            }
1206
            HostFunction::ext_storage_append_version_1 => {
1207
71
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1208
71
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1209
71
                HostVm::ExternalStorageAppend(ExternalStorageAppend {
1210
71
                    key_ptr,
1211
71
                    key_size,
1212
71
                    value_ptr,
1213
71
                    value_size,
1214
71
                    inner: self.inner,
1215
71
                })
1216
            }
1217
            HostFunction::ext_storage_start_transaction_version_1 => {
1218
                // TODO: a maximum depth is important in order to prevent a malicious runtime from crashing the client, but the depth needs to be the same as in Substrate; figure out
1219
14
                self.inner.storage_transaction_depth += 1;
1220
14
                HostVm::StartStorageTransaction(StartStorageTransaction { inner: self.inner })
1221
            }
1222
            HostFunction::ext_storage_rollback_transaction_version_1 => {
1223
0
                if self.inner.storage_transaction_depth == 0 {
1224
0
                    return HostVm::Error {
1225
0
                        error: Error::NoActiveTransaction,
1226
0
                        prototype: self.inner.into_prototype(),
1227
0
                    };
1228
0
                }
1229
0
1230
0
                self.inner.storage_transaction_depth -= 1;
1231
0
                HostVm::EndStorageTransaction {
1232
0
                    resume: EndStorageTransaction { inner: self.inner },
1233
0
                    rollback: true,
1234
0
                }
1235
            }
1236
            HostFunction::ext_storage_commit_transaction_version_1 => {
1237
14
                if self.inner.storage_transaction_depth == 0 {
1238
0
                    return HostVm::Error {
1239
0
                        error: Error::NoActiveTransaction,
1240
0
                        prototype: self.inner.into_prototype(),
1241
0
                    };
1242
14
                }
1243
14
1244
14
                self.inner.storage_transaction_depth -= 1;
1245
14
                HostVm::EndStorageTransaction {
1246
14
                    resume: EndStorageTransaction { inner: self.inner },
1247
14
                    rollback: false,
1248
14
                }
1249
            }
1250
            HostFunction::ext_storage_proof_size_storage_proof_size_version_1 => {
1251
0
                match self.inner.storage_proof_size_behavior {
1252
0
                    StorageProofSizeBehavior::ConstantReturnValue(value) => {
1253
0
                        HostVm::ReadyToRun(ReadyToRun {
1254
0
                            inner: self.inner,
1255
0
                            resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(
1256
0
                                value.to_ne_bytes(),
1257
0
                            ))),
1258
0
                        })
1259
                    }
1260
0
                    StorageProofSizeBehavior::Unimplemented => HostVm::Error {
1261
0
                        error: Error::HostFunctionNotImplemented {
1262
0
                            function: host_fn.name(),
1263
0
                        },
1264
0
                        prototype: self.inner.into_prototype(),
1265
0
                    },
1266
                }
1267
            }
1268
            HostFunction::ext_default_child_storage_get_version_1 => {
1269
2
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1270
2
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1271
2
                HostVm::ExternalStorageGet(ExternalStorageGet {
1272
2
                    key_ptr,
1273
2
                    key_size,
1274
2
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1275
2
                    calling: id,
1276
2
                    value_out_ptr: None,
1277
2
                    offset: 0,
1278
2
                    max_size: u32::MAX,
1279
2
                    inner: self.inner,
1280
2
                })
1281
            }
1282
            HostFunction::ext_default_child_storage_read_version_1 => {
1283
4
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1284
4
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1285
4
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(2);
1286
4
                let offset = expect_u32!(3);
1287
4
                HostVm::ExternalStorageGet(ExternalStorageGet {
1288
4
                    key_ptr,
1289
4
                    key_size,
1290
4
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1291
4
                    calling: id,
1292
4
                    value_out_ptr: Some(value_out_ptr),
1293
4
                    offset,
1294
4
                    max_size: value_out_size,
1295
4
                    inner: self.inner,
1296
4
                })
1297
            }
1298
            HostFunction::ext_default_child_storage_storage_kill_version_1 => {
1299
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1300
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1301
0
                    prefix_ptr_size: None,
1302
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1303
0
                    inner: self.inner,
1304
0
                    max_keys_to_remove: None,
1305
0
                    calling: id,
1306
0
                })
1307
            }
1308
            HostFunction::ext_default_child_storage_storage_kill_version_2
1309
            | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
1310
1
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1311
1312
1
                let max_keys_to_remove = {
1313
1
                    let input = expect_pointer_size!(1);
1314
1
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1315
1
                        nom::Parser::parse(
1316
1
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1317
1
                                nom::number::streaming::le_u32,
1318
1
                            )),
1319
1
                            input.as_ref(),
1320
1
                        )
1321
1
                        .map(|(_, parse_result)| parse_result);
_RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces3_0Bb_
Line
Count
Source
1321
1
                        .map(|(_, parse_result)| parse_result);
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces3_0Bb_
1322
1
1323
1
                    match parsing_result {
1324
1
                        Ok(val) => Ok(val),
1325
0
                        Err(_) => Err(()),
1326
                    }
1327
                };
1328
1329
1
                let max_keys_to_remove = match max_keys_to_remove {
1330
1
                    Ok(l) => l,
1331
                    Err(()) => {
1332
0
                        return HostVm::Error {
1333
0
                            error: Error::ParamDecodeError,
1334
0
                            prototype: self.inner.into_prototype(),
1335
0
                        };
1336
                    }
1337
                };
1338
1339
1
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1340
1
                    prefix_ptr_size: None,
1341
1
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1342
1
                    inner: self.inner,
1343
1
                    max_keys_to_remove,
1344
1
                    calling: id,
1345
1
                })
1346
            }
1347
            HostFunction::ext_default_child_storage_clear_prefix_version_1 => {
1348
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1349
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1350
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1351
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1352
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1353
0
                    inner: self.inner,
1354
0
                    max_keys_to_remove: None,
1355
0
                    calling: id,
1356
0
                })
1357
            }
1358
            HostFunction::ext_default_child_storage_clear_prefix_version_2 => {
1359
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1360
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1361
1362
0
                let max_keys_to_remove = {
1363
0
                    let input = expect_pointer_size!(2);
1364
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1365
0
                        nom::Parser::parse(
1366
0
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1367
0
                                nom::number::streaming::le_u32,
1368
0
                            )),
1369
0
                            input.as_ref(),
1370
0
                        )
1371
0
                        .map(|(_, parse_result)| parse_result);
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces4_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces4_0Bb_
1372
0
1373
0
                    match parsing_result {
1374
0
                        Ok(val) => Ok(val),
1375
0
                        Err(_) => Err(()),
1376
                    }
1377
                };
1378
1379
0
                let max_keys_to_remove = match max_keys_to_remove {
1380
0
                    Ok(l) => l,
1381
                    Err(()) => {
1382
0
                        return HostVm::Error {
1383
0
                            error: Error::ParamDecodeError,
1384
0
                            prototype: self.inner.into_prototype(),
1385
0
                        };
1386
                    }
1387
                };
1388
1389
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1390
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1391
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1392
0
                    inner: self.inner,
1393
0
                    max_keys_to_remove,
1394
0
                    calling: id,
1395
0
                })
1396
            }
1397
            HostFunction::ext_default_child_storage_set_version_1 => {
1398
4
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1399
4
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1400
4
                let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1401
4
                HostVm::ExternalStorageSet(ExternalStorageSet {
1402
4
                    key_ptr,
1403
4
                    key_size,
1404
4
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1405
4
                    value: Some((value_ptr, value_size)),
1406
4
                    inner: self.inner,
1407
4
                })
1408
            }
1409
            HostFunction::ext_default_child_storage_clear_version_1 => {
1410
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1411
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1412
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1413
0
                    key_ptr,
1414
0
                    key_size,
1415
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1416
0
                    value: None,
1417
0
                    inner: self.inner,
1418
0
                })
1419
            }
1420
            HostFunction::ext_default_child_storage_exists_version_1 => {
1421
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1422
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1423
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1424
0
                    key_ptr,
1425
0
                    key_size,
1426
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1427
0
                    calling: id,
1428
0
                    value_out_ptr: None,
1429
0
                    offset: 0,
1430
0
                    max_size: 0,
1431
0
                    inner: self.inner,
1432
0
                })
1433
            }
1434
            HostFunction::ext_default_child_storage_next_key_version_1 => {
1435
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1436
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1437
0
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1438
0
                    key_ptr,
1439
0
                    key_size,
1440
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1441
0
                    inner: self.inner,
1442
0
                })
1443
            }
1444
            HostFunction::ext_default_child_storage_root_version_1 => {
1445
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1446
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1447
0
                    inner: self.inner,
1448
0
                    calling: id,
1449
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1450
0
                })
1451
            }
1452
            HostFunction::ext_default_child_storage_root_version_2 => {
1453
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1454
1455
                // The `ext_default_child_storage_root_version_2` host function gets passed as
1456
                // parameter the state version of the runtime. This is in fact completely
1457
                // unnecessary as the same information is found in the runtime specification, and
1458
                // this parameter should be considered as a historical accident. We verify that the
1459
                // version provided as parameter is the same as the one in the specification.
1460
0
                let version_param = expect_state_version!(1);
1461
0
                let version_spec = self
1462
0
                    .inner
1463
0
                    .common
1464
0
                    .runtime_version
1465
0
                    .as_ref()
1466
0
                    .unwrap_or_else(|| unreachable!())
1467
0
                    .decode()
1468
0
                    .state_version
1469
0
                    .unwrap_or(TrieEntryVersion::V0);
1470
0
1471
0
                if version_param != version_spec {
1472
0
                    return HostVm::Error {
1473
0
                        error: Error::StateVersionMismatch {
1474
0
                            parameter: version_param,
1475
0
                            specification: version_spec,
1476
0
                        },
1477
0
                        prototype: self.inner.into_prototype(),
1478
0
                    };
1479
0
                }
1480
0
1481
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1482
0
                    inner: self.inner,
1483
0
                    calling: id,
1484
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1485
0
                })
1486
            }
1487
0
            HostFunction::ext_crypto_ed25519_public_keys_version_1 => host_fn_not_implemented!(),
1488
0
            HostFunction::ext_crypto_ed25519_generate_version_1 => host_fn_not_implemented!(),
1489
0
            HostFunction::ext_crypto_ed25519_sign_version_1 => host_fn_not_implemented!(),
1490
            HostFunction::ext_crypto_ed25519_verify_version_1
1491
            | HostFunction::ext_crypto_ed25519_batch_verify_version_1 => {
1492
0
                let is_batch_verification = matches!(
1493
0
                    host_fn,
1494
                    HostFunction::ext_crypto_ed25519_batch_verify_version_1
1495
                );
1496
1497
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1498
0
                    return HostVm::Error {
1499
0
                        error: Error::BatchVerifyWithoutStarting,
1500
0
                        prototype: self.inner.into_prototype(),
1501
0
                    };
1502
0
                }
1503
1504
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1505
                HostVm::SignatureVerification(SignatureVerification {
1506
0
                    algorithm: SignatureVerificationAlgorithm::Ed25519,
1507
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1508
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1509
0
                    message_ptr,
1510
0
                    message_size,
1511
0
                    inner: self.inner,
1512
0
                    is_batch_verification,
1513
                })
1514
            }
1515
0
            HostFunction::ext_crypto_sr25519_public_keys_version_1 => host_fn_not_implemented!(),
1516
0
            HostFunction::ext_crypto_sr25519_generate_version_1 => host_fn_not_implemented!(),
1517
0
            HostFunction::ext_crypto_sr25519_sign_version_1 => host_fn_not_implemented!(),
1518
            HostFunction::ext_crypto_sr25519_verify_version_1
1519
            | HostFunction::ext_crypto_sr25519_batch_verify_version_1 => {
1520
0
                let is_batch_verification = matches!(
1521
0
                    host_fn,
1522
                    HostFunction::ext_crypto_sr25519_batch_verify_version_1
1523
                );
1524
1525
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1526
0
                    return HostVm::Error {
1527
0
                        error: Error::BatchVerifyWithoutStarting,
1528
0
                        prototype: self.inner.into_prototype(),
1529
0
                    };
1530
0
                }
1531
1532
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1533
                HostVm::SignatureVerification(SignatureVerification {
1534
0
                    algorithm: SignatureVerificationAlgorithm::Sr25519V1,
1535
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1536
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1537
0
                    message_ptr,
1538
0
                    message_size,
1539
0
                    inner: self.inner,
1540
0
                    is_batch_verification,
1541
                })
1542
            }
1543
            HostFunction::ext_crypto_sr25519_verify_version_2 => {
1544
6
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1545
                HostVm::SignatureVerification(SignatureVerification {
1546
6
                    algorithm: SignatureVerificationAlgorithm::Sr25519V2,
1547
6
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1548
6
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1549
6
                    message_ptr,
1550
6
                    message_size,
1551
6
                    inner: self.inner,
1552
                    is_batch_verification: false,
1553
                })
1554
            }
1555
0
            HostFunction::ext_crypto_ecdsa_generate_version_1 => host_fn_not_implemented!(),
1556
            HostFunction::ext_crypto_ecdsa_sign_version_1 => {
1557
                // NOTE: safe to unwrap here because we supply the nn to blake2b fn
1558
0
                let data = <[u8; 32]>::try_from(
1559
0
                    blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
1560
0
                        .as_bytes(),
1561
0
                )
1562
0
                .unwrap_or_else(|_| unreachable!());
1563
0
                let message = libsecp256k1::Message::parse(&data);
1564
1565
0
                if let Ok(sc) =
1566
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1567
                {
1568
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1569
0
1570
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1571
0
                    self.inner.alloc_write_and_return_pointer(
1572
0
                        host_fn.name(),
1573
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1574
0
                    )
1575
                } else {
1576
0
                    HostVm::Error {
1577
0
                        error: Error::ParamDecodeError,
1578
0
                        prototype: self.inner.into_prototype(),
1579
0
                    }
1580
                }
1581
            }
1582
0
            HostFunction::ext_crypto_ecdsa_public_keys_version_1 => host_fn_not_implemented!(),
1583
            HostFunction::ext_crypto_ecdsa_verify_version_1
1584
            | HostFunction::ext_crypto_ecdsa_batch_verify_version_1 => {
1585
0
                let is_batch_verification = matches!(
1586
0
                    host_fn,
1587
                    HostFunction::ext_crypto_ecdsa_batch_verify_version_1
1588
                );
1589
1590
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1591
0
                    return HostVm::Error {
1592
0
                        error: Error::BatchVerifyWithoutStarting,
1593
0
                        prototype: self.inner.into_prototype(),
1594
0
                    };
1595
0
                }
1596
1597
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1598
                HostVm::SignatureVerification(SignatureVerification {
1599
0
                    algorithm: SignatureVerificationAlgorithm::Ecdsa,
1600
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1601
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1602
0
                    message_ptr,
1603
0
                    message_size,
1604
0
                    inner: self.inner,
1605
0
                    is_batch_verification,
1606
                })
1607
            }
1608
0
            HostFunction::ext_crypto_ecdsa_verify_version_2 => host_fn_not_implemented!(),
1609
            HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => {
1610
                // TODO: seems misimplemented, see https://spec.polkadot.network/#id-ext_crypto_ecdsa_sign_prehashed
1611
0
                let message = libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));
1612
1613
0
                if let Ok(sc) =
1614
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1615
                {
1616
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1617
0
1618
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1619
0
                    self.inner.alloc_write_and_return_pointer(
1620
0
                        host_fn.name(),
1621
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1622
0
                    )
1623
                } else {
1624
0
                    HostVm::Error {
1625
0
                        error: Error::ParamDecodeError,
1626
0
                        prototype: self.inner.into_prototype(),
1627
0
                    }
1628
                }
1629
            }
1630
            HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => {
1631
                HostVm::SignatureVerification(SignatureVerification {
1632
0
                    algorithm: SignatureVerificationAlgorithm::EcdsaPrehashed,
1633
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1634
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1635
0
                    message_ptr: expect_pointer_constant_size_raw!(1, 32),
1636
                    message_size: 32,
1637
0
                    inner: self.inner,
1638
                    is_batch_verification: false,
1639
                })
1640
            }
1641
1642
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1
1643
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => {
1644
0
                let sig = expect_pointer_constant_size!(0, 65);
1645
0
                let msg = expect_pointer_constant_size!(1, 32);
1646
0
                let is_v2 = matches!(
1647
0
                    host_fn,
1648
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2
1649
                );
1650
1651
0
                let result = {
1652
0
                    let rs = if is_v2 {
1653
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1654
                    } else {
1655
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1656
                    };
1657
1658
0
                    if let Ok(rs) = rs {
1659
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1660
0
                            sig[64] - 27
1661
                        } else {
1662
0
                            sig[64]
1663
                        });
1664
1665
0
                        if let Ok(v) = v {
1666
0
                            let pubkey = libsecp256k1::recover(
1667
0
                                &libsecp256k1::Message::parse_slice(&msg)
1668
0
                                    .unwrap_or_else(|_| unreachable!()),
1669
0
                                &rs,
1670
0
                                &v,
1671
0
                            );
1672
1673
0
                            if let Ok(pubkey) = pubkey {
1674
0
                                let mut res = Vec::with_capacity(65);
1675
0
                                res.push(0);
1676
0
                                res.extend_from_slice(&pubkey.serialize()[1..65]);
1677
0
                                res
1678
                            } else {
1679
0
                                vec![1, 2]
1680
                            }
1681
                        } else {
1682
0
                            vec![1, 1]
1683
                        }
1684
                    } else {
1685
0
                        vec![1, 0]
1686
                    }
1687
                };
1688
1689
0
                self.inner
1690
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1691
            }
1692
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_1
1693
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2 => {
1694
0
                let sig = expect_pointer_constant_size!(0, 65);
1695
0
                let msg = expect_pointer_constant_size!(1, 32);
1696
0
                let is_v2 = matches!(
1697
0
                    host_fn,
1698
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2
1699
                );
1700
1701
0
                let result = {
1702
0
                    let rs = if is_v2 {
1703
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1704
                    } else {
1705
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1706
                    };
1707
1708
0
                    if let Ok(rs) = rs {
1709
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1710
0
                            sig[64] - 27
1711
                        } else {
1712
0
                            sig[64]
1713
                        });
1714
1715
0
                        if let Ok(v) = v {
1716
0
                            let pubkey = libsecp256k1::recover(
1717
0
                                &libsecp256k1::Message::parse_slice(&msg)
1718
0
                                    .unwrap_or_else(|_| unreachable!()),
1719
0
                                &rs,
1720
0
                                &v,
1721
0
                            );
1722
1723
0
                            if let Ok(pubkey) = pubkey {
1724
0
                                let mut res = Vec::with_capacity(34);
1725
0
                                res.push(0);
1726
0
                                res.extend_from_slice(&pubkey.serialize_compressed());
1727
0
                                res
1728
                            } else {
1729
0
                                vec![1, 2]
1730
                            }
1731
                        } else {
1732
0
                            vec![1, 1]
1733
                        }
1734
                    } else {
1735
0
                        vec![1, 0]
1736
                    }
1737
                };
1738
1739
0
                self.inner
1740
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1741
            }
1742
            HostFunction::ext_crypto_start_batch_verify_version_1 => {
1743
4
                if self.inner.signatures_batch_verification.is_some() {
1744
0
                    return HostVm::Error {
1745
0
                        error: Error::AlreadyBatchVerify,
1746
0
                        prototype: self.inner.into_prototype(),
1747
0
                    };
1748
4
                }
1749
4
1750
4
                self.inner.signatures_batch_verification = Some(true);
1751
4
1752
4
                HostVm::ReadyToRun(ReadyToRun {
1753
4
                    resume_value: None,
1754
4
                    inner: self.inner,
1755
4
                })
1756
            }
1757
            HostFunction::ext_crypto_finish_batch_verify_version_1 => {
1758
4
                let Some(outcome) = self.inner.signatures_batch_verification.take() else {
1759
0
                    return HostVm::Error {
1760
0
                        error: Error::NoBatchVerify,
1761
0
                        prototype: self.inner.into_prototype(),
1762
0
                    };
1763
                };
1764
1765
                HostVm::ReadyToRun(ReadyToRun {
1766
4
                    resume_value: Some(vm::WasmValue::I32(if outcome { 1 } else { 
00
})),
1767
4
                    inner: self.inner,
1768
                })
1769
            }
1770
            HostFunction::ext_hashing_keccak_256_version_1 => {
1771
2
                let hash =
1772
2
                    <sha3::Keccak256 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1773
2
                self.inner
1774
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1775
            }
1776
            HostFunction::ext_hashing_keccak_512_version_1 => {
1777
2
                let hash =
1778
2
                    <sha3::Keccak512 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1779
2
                self.inner
1780
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1781
            }
1782
            HostFunction::ext_hashing_sha2_256_version_1 => {
1783
2
                let hash = <sha2::Sha256 as sha2::Digest>::digest(expect_pointer_size!(0).as_ref());
1784
2
                self.inner
1785
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1786
            }
1787
            HostFunction::ext_hashing_blake2_128_version_1 => {
1788
148
                let out = {
1789
148
                    let data = expect_pointer_size!(0);
1790
148
                    blake2_rfc::blake2b::blake2b(16, &[], data.as_ref())
1791
148
                };
1792
148
1793
148
                self.inner
1794
148
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1795
            }
1796
            HostFunction::ext_hashing_blake2_256_version_1 => {
1797
30
                let out = {
1798
30
                    let data = expect_pointer_size!(0);
1799
30
                    blake2_rfc::blake2b::blake2b(32, &[], data.as_ref())
1800
30
                };
1801
30
1802
30
                self.inner
1803
30
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1804
            }
1805
            HostFunction::ext_hashing_twox_64_version_1 => {
1806
67
                let r0 = {
1807
67
                    let data = expect_pointer_size!(0);
1808
67
                    twox_hash::XxHash64::oneshot(0, data.as_ref())
1809
67
                };
1810
67
1811
67
                self.inner
1812
67
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&r0.to_le_bytes()))
1813
            }
1814
            HostFunction::ext_hashing_twox_128_version_1 => {
1815
1.81k
                let [r0, r1] = {
1816
1.81k
                    let data = expect_pointer_size!(0);
1817
1.81k
                    let data = data.as_ref();
1818
1.81k
                    [
1819
1.81k
                        twox_hash::XxHash64::oneshot(0, data),
1820
1.81k
                        twox_hash::XxHash64::oneshot(1, data),
1821
1.81k
                    ]
1822
1.81k
                };
1823
1.81k
1824
1.81k
                self.inner.alloc_write_and_return_pointer(
1825
1.81k
                    host_fn.name(),
1826
1.81k
                    iter::once(&r0.to_le_bytes()).chain(iter::once(&r1.to_le_bytes())),
1827
1.81k
                )
1828
            }
1829
            HostFunction::ext_hashing_twox_256_version_1 => {
1830
2
                let [r0, r1, r2, r3] = {
1831
2
                    let data = expect_pointer_size!(0);
1832
2
                    let data = data.as_ref();
1833
2
                    [
1834
2
                        twox_hash::XxHash64::oneshot(0, data),
1835
2
                        twox_hash::XxHash64::oneshot(1, data),
1836
2
                        twox_hash::XxHash64::oneshot(2, data),
1837
2
                        twox_hash::XxHash64::oneshot(3, data),
1838
2
                    ]
1839
2
                };
1840
2
1841
2
                self.inner.alloc_write_and_return_pointer(
1842
2
                    host_fn.name(),
1843
2
                    iter::once(&r0.to_le_bytes())
1844
2
                        .chain(iter::once(&r1.to_le_bytes()))
1845
2
                        .chain(iter::once(&r2.to_le_bytes()))
1846
2
                        .chain(iter::once(&r3.to_le_bytes())),
1847
2
                )
1848
            }
1849
            HostFunction::ext_offchain_index_set_version_1 => {
1850
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1851
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1852
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1853
0
                    key_ptr,
1854
0
                    key_size,
1855
0
                    value: Some((value_ptr, value_size)),
1856
0
                    inner: self.inner,
1857
0
                })
1858
            }
1859
            HostFunction::ext_offchain_index_clear_version_1 => {
1860
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1861
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1862
0
                    key_ptr,
1863
0
                    key_size,
1864
0
                    value: None,
1865
0
                    inner: self.inner,
1866
0
                })
1867
            }
1868
0
            HostFunction::ext_offchain_is_validator_version_1 => HostVm::ReadyToRun(ReadyToRun {
1869
0
                inner: self.inner,
1870
0
                resume_value: Some(vm::WasmValue::I32(1)), // TODO: ask the API user
1871
0
            }),
1872
            HostFunction::ext_offchain_submit_transaction_version_1 => {
1873
0
                let (tx_ptr, tx_size) = expect_pointer_size_raw!(0);
1874
0
                HostVm::OffchainSubmitTransaction(OffchainSubmitTransaction {
1875
0
                    inner: self.inner,
1876
0
                    calling: id,
1877
0
                    tx_ptr,
1878
0
                    tx_size,
1879
0
                })
1880
            }
1881
            HostFunction::ext_offchain_network_state_version_1 => {
1882
0
                host_fn_not_implemented!()
1883
            }
1884
            HostFunction::ext_offchain_timestamp_version_1 => {
1885
0
                HostVm::OffchainTimestamp(OffchainTimestamp { inner: self.inner })
1886
            }
1887
            HostFunction::ext_offchain_sleep_until_version_1 => {
1888
0
                host_fn_not_implemented!()
1889
            }
1890
            HostFunction::ext_offchain_random_seed_version_1 => {
1891
0
                HostVm::OffchainRandomSeed(OffchainRandomSeed {
1892
0
                    inner: self.inner,
1893
0
                    calling: id,
1894
0
                })
1895
            }
1896
            HostFunction::ext_offchain_local_storage_set_version_1 => {
1897
0
                if expect_offchain_storage_kind!(0) {
1898
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1899
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1900
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1901
0
                        key_ptr,
1902
0
                        key_size,
1903
0
                        value: Some((value_ptr, value_size)),
1904
0
                        old_value: None,
1905
0
                        inner: self.inner,
1906
0
                    })
1907
                } else {
1908
0
                    HostVm::ReadyToRun(ReadyToRun {
1909
0
                        inner: self.inner,
1910
0
                        resume_value: None,
1911
0
                    })
1912
                }
1913
            }
1914
            HostFunction::ext_offchain_local_storage_compare_and_set_version_1 => {
1915
0
                if expect_offchain_storage_kind!(0) {
1916
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1917
0
                    let (old_value_ptr, old_value_size) = expect_pointer_size_raw!(2);
1918
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(3);
1919
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1920
0
                        key_ptr,
1921
0
                        key_size,
1922
0
                        value: Some((value_ptr, value_size)),
1923
0
                        old_value: Some((old_value_ptr, old_value_size)),
1924
0
                        inner: self.inner,
1925
0
                    })
1926
                } else {
1927
0
                    HostVm::ReadyToRun(ReadyToRun {
1928
0
                        inner: self.inner,
1929
0
                        resume_value: Some(vm::WasmValue::I32(0)),
1930
0
                    })
1931
                }
1932
            }
1933
            HostFunction::ext_offchain_local_storage_get_version_1 => {
1934
0
                if expect_offchain_storage_kind!(0) {
1935
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1936
0
                    HostVm::ExternalOffchainStorageGet(ExternalOffchainStorageGet {
1937
0
                        key_ptr,
1938
0
                        key_size,
1939
0
                        calling: id,
1940
0
                        inner: self.inner,
1941
0
                    })
1942
                } else {
1943
                    // Write a SCALE-encoded `None`.
1944
0
                    self.inner
1945
0
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
1946
                }
1947
            }
1948
            HostFunction::ext_offchain_local_storage_clear_version_1 => {
1949
0
                if expect_offchain_storage_kind!(0) {
1950
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1951
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1952
0
                        key_ptr,
1953
0
                        key_size,
1954
0
                        value: None,
1955
0
                        old_value: None,
1956
0
                        inner: self.inner,
1957
0
                    })
1958
                } else {
1959
0
                    HostVm::ReadyToRun(ReadyToRun {
1960
0
                        inner: self.inner,
1961
0
                        resume_value: None,
1962
0
                    })
1963
                }
1964
            }
1965
0
            HostFunction::ext_offchain_http_request_start_version_1 => host_fn_not_implemented!(),
1966
            HostFunction::ext_offchain_http_request_add_header_version_1 => {
1967
0
                host_fn_not_implemented!()
1968
            }
1969
            HostFunction::ext_offchain_http_request_write_body_version_1 => {
1970
0
                host_fn_not_implemented!()
1971
            }
1972
0
            HostFunction::ext_offchain_http_response_wait_version_1 => host_fn_not_implemented!(),
1973
            HostFunction::ext_offchain_http_response_headers_version_1 => {
1974
0
                host_fn_not_implemented!()
1975
            }
1976
            HostFunction::ext_offchain_http_response_read_body_version_1 => {
1977
0
                host_fn_not_implemented!()
1978
            }
1979
            HostFunction::ext_trie_blake2_256_root_version_1
1980
            | HostFunction::ext_trie_blake2_256_root_version_2
1981
            | HostFunction::ext_trie_keccak_256_root_version_1
1982
            | HostFunction::ext_trie_keccak_256_root_version_2 => {
1983
0
                let state_version = if matches!(
1984
0
                    host_fn,
1985
                    HostFunction::ext_trie_blake2_256_root_version_2
1986
                        | HostFunction::ext_trie_keccak_256_root_version_2
1987
                ) {
1988
0
                    expect_state_version!(1)
1989
                } else {
1990
0
                    TrieEntryVersion::V0
1991
                };
1992
1993
0
                let result = {
1994
0
                    let input = expect_pointer_size!(0);
1995
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1996
0
                        nom::Parser::parse(
1997
0
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
1998
0
                                crate::util::nom_scale_compact_usize,
1999
0
                                |num_elems| {
2000
0
                                    nom::multi::many_m_n(
2001
0
                                        num_elems,
2002
0
                                        num_elems,
2003
0
                                        (
2004
0
                                            nom::combinator::flat_map(
2005
0
                                                crate::util::nom_scale_compact_usize,
2006
0
                                                nom::bytes::streaming::take,
2007
0
                                            ),
2008
0
                                            nom::combinator::flat_map(
2009
0
                                                crate::util::nom_scale_compact_usize,
2010
0
                                                nom::bytes::streaming::take,
2011
0
                                            ),
2012
0
                                        ),
2013
0
                                    )
2014
0
                                },
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces9_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_onces9_0Bb_
2015
0
                            )),
2016
0
                            input.as_ref(),
2017
0
                        )
2018
0
                        .map(|(_, parse_result)| parse_result);
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesa_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesa_0Bb_
2019
0
2020
0
                    match parsing_result {
2021
0
                        Ok(elements) => Ok(trie::trie_root(
2022
0
                            state_version,
2023
0
                            if matches!(
2024
0
                                host_fn,
2025
                                HostFunction::ext_trie_blake2_256_root_version_1
2026
                                    | HostFunction::ext_trie_blake2_256_root_version_2
2027
                            ) {
2028
0
                                trie::HashFunction::Blake2
2029
                            } else {
2030
0
                                trie::HashFunction::Keccak256
2031
                            },
2032
0
                            &elements[..],
2033
                        )),
2034
0
                        Err(_) => Err(()),
2035
                    }
2036
                };
2037
2038
0
                match result {
2039
0
                    Ok(out) => self
2040
0
                        .inner
2041
0
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2042
0
                    Err(()) => HostVm::Error {
2043
0
                        error: Error::ParamDecodeError,
2044
0
                        prototype: self.inner.into_prototype(),
2045
0
                    },
2046
                }
2047
            }
2048
            HostFunction::ext_trie_blake2_256_ordered_root_version_1
2049
            | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2050
            | HostFunction::ext_trie_keccak_256_ordered_root_version_1
2051
            | HostFunction::ext_trie_keccak_256_ordered_root_version_2 => {
2052
5
                let state_version = if 
matches!1
(
2053
5
                    host_fn,
2054
                    HostFunction::ext_trie_blake2_256_ordered_root_version_2
2055
                        | HostFunction::ext_trie_keccak_256_ordered_root_version_2
2056
                ) {
2057
4
                    expect_state_version!(1)
2058
                } else {
2059
1
                    TrieEntryVersion::V0
2060
                };
2061
2062
5
                let result = {
2063
5
                    let input = expect_pointer_size!(0);
2064
5
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
2065
5
                        nom::Parser::parse(
2066
5
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
2067
5
                                crate::util::nom_scale_compact_usize,
2068
5
                                |num_elems| {
2069
5
                                    nom::multi::many_m_n(
2070
5
                                        num_elems,
2071
5
                                        num_elems,
2072
5
                                        nom::combinator::flat_map(
2073
5
                                            crate::util::nom_scale_compact_usize,
2074
5
                                            nom::bytes::streaming::take,
2075
5
                                        ),
2076
5
                                    )
2077
5
                                },
_RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesb_0Bb_
Line
Count
Source
2068
5
                                |num_elems| {
2069
5
                                    nom::multi::many_m_n(
2070
5
                                        num_elems,
2071
5
                                        num_elems,
2072
5
                                        nom::combinator::flat_map(
2073
5
                                            crate::util::nom_scale_compact_usize,
2074
5
                                            nom::bytes::streaming::take,
2075
5
                                        ),
2076
5
                                    )
2077
5
                                },
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesb_0Bb_
2078
5
                            )),
2079
5
                            input.as_ref(),
2080
5
                        )
2081
5
                        .map(|(_, parse_result)| parse_result);
_RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesc_0Bb_
Line
Count
Source
2081
5
                        .map(|(_, parse_result)| parse_result);
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesc_0Bb_
2082
5
2083
5
                    match parsing_result {
2084
5
                        Ok(elements) => Ok(trie::ordered_root(
2085
5
                            state_version,
2086
0
                            if matches!(
2087
5
                                host_fn,
2088
                                HostFunction::ext_trie_blake2_256_ordered_root_version_1
2089
                                    | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2090
                            ) {
2091
5
                                trie::HashFunction::Blake2
2092
                            } else {
2093
0
                                trie::HashFunction::Keccak256
2094
                            },
2095
5
                            &elements[..],
2096
                        )),
2097
0
                        Err(_) => Err(()),
2098
                    }
2099
                };
2100
2101
5
                match result {
2102
5
                    Ok(out) => self
2103
5
                        .inner
2104
5
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2105
0
                    Err(()) => HostVm::Error {
2106
0
                        error: Error::ParamDecodeError,
2107
0
                        prototype: self.inner.into_prototype(),
2108
0
                    },
2109
                }
2110
            }
2111
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_1 => host_fn_not_implemented!(),
2112
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_2 => host_fn_not_implemented!(),
2113
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_1 => host_fn_not_implemented!(),
2114
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_2 => host_fn_not_implemented!(),
2115
            HostFunction::ext_misc_print_num_version_1 => {
2116
0
                let num = match params[0] {
2117
0
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
2118
                    // The signatures are checked at initialization and the Wasm VM ensures that
2119
                    // the proper parameter types are provided.
2120
0
                    _ => unreachable!(),
2121
                };
2122
2123
0
                HostVm::LogEmit(LogEmit {
2124
0
                    inner: self.inner,
2125
0
                    log_entry: LogEmitInner::Num(num),
2126
0
                })
2127
            }
2128
            HostFunction::ext_misc_print_utf8_version_1 => {
2129
0
                let (str_ptr, str_size) = expect_pointer_size_raw!(0);
2130
2131
0
                let utf8_check = str::from_utf8(
2132
0
                    self.inner
2133
0
                        .vm
2134
0
                        .read_memory(str_ptr, str_size)
2135
0
                        .unwrap_or_else(|_| unreachable!())
2136
0
                        .as_ref(),
2137
0
                )
2138
0
                .map(|_| ());
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncese_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncese_0Bb_
2139
0
                if let Err(error) = utf8_check {
2140
0
                    return HostVm::Error {
2141
0
                        error: Error::Utf8Error {
2142
0
                            function: host_fn.name(),
2143
0
                            param_num: 2,
2144
0
                            error,
2145
0
                        },
2146
0
                        prototype: self.inner.into_prototype(),
2147
0
                    };
2148
0
                }
2149
0
2150
0
                HostVm::LogEmit(LogEmit {
2151
0
                    inner: self.inner,
2152
0
                    log_entry: LogEmitInner::Utf8 { str_ptr, str_size },
2153
0
                })
2154
            }
2155
            HostFunction::ext_misc_print_hex_version_1 => {
2156
0
                let (data_ptr, data_size) = expect_pointer_size_raw!(0);
2157
0
                HostVm::LogEmit(LogEmit {
2158
0
                    inner: self.inner,
2159
0
                    log_entry: LogEmitInner::Hex {
2160
0
                        data_ptr,
2161
0
                        data_size,
2162
0
                    },
2163
0
                })
2164
            }
2165
            HostFunction::ext_misc_runtime_version_version_1 => {
2166
0
                let (wasm_blob_ptr, wasm_blob_size) = expect_pointer_size_raw!(0);
2167
0
                HostVm::CallRuntimeVersion(CallRuntimeVersion {
2168
0
                    inner: self.inner,
2169
0
                    wasm_blob_ptr,
2170
0
                    wasm_blob_size,
2171
0
                })
2172
            }
2173
            HostFunction::ext_allocator_malloc_version_1 => {
2174
14.1k
                let size = expect_u32!(0);
2175
2176
14.1k
                let ptr = match self.inner.alloc(host_fn.name(), size) {
2177
14.1k
                    Ok(p) => p,
2178
0
                    Err(error) => {
2179
0
                        return HostVm::Error {
2180
0
                            error,
2181
0
                            prototype: self.inner.into_prototype(),
2182
0
                        };
2183
                    }
2184
                };
2185
2186
14.1k
                let ptr_i32 = i32::from_ne_bytes(ptr.to_ne_bytes());
2187
14.1k
                HostVm::ReadyToRun(ReadyToRun {
2188
14.1k
                    resume_value: Some(vm::WasmValue::I32(ptr_i32)),
2189
14.1k
                    inner: self.inner,
2190
14.1k
                })
2191
            }
2192
            HostFunction::ext_allocator_free_version_1 => {
2193
16.7k
                let pointer = expect_u32!(0);
2194
16.7k
                match self.inner.allocator.deallocate(
2195
16.7k
                    &mut MemAccess {
2196
16.7k
                        vm: MemAccessVm::Running(&mut self.inner.vm),
2197
16.7k
                        memory_total_pages: self.inner.common.memory_total_pages,
2198
16.7k
                    },
2199
16.7k
                    pointer,
2200
16.7k
                ) {
2201
16.7k
                    Ok(()) => {}
2202
                    Err(_) => {
2203
0
                        return HostVm::Error {
2204
0
                            error: Error::FreeError { pointer },
2205
0
                            prototype: self.inner.into_prototype(),
2206
0
                        };
2207
                    }
2208
                };
2209
2210
16.7k
                HostVm::ReadyToRun(ReadyToRun {
2211
16.7k
                    resume_value: None,
2212
16.7k
                    inner: self.inner,
2213
16.7k
                })
2214
            }
2215
            HostFunction::ext_logging_log_version_1 => {
2216
0
                let log_level = expect_u32!(0);
2217
2218
0
                let (target_str_ptr, target_str_size) = expect_pointer_size_raw!(1);
2219
0
                let target_utf8_check = str::from_utf8(
2220
0
                    self.inner
2221
0
                        .vm
2222
0
                        .read_memory(target_str_ptr, target_str_size)
2223
0
                        .unwrap_or_else(|_| unreachable!())
2224
0
                        .as_ref(),
2225
0
                )
2226
0
                .map(|_| ());
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesg_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesg_0Bb_
2227
0
                if let Err(error) = target_utf8_check {
2228
0
                    return HostVm::Error {
2229
0
                        error: Error::Utf8Error {
2230
0
                            function: host_fn.name(),
2231
0
                            param_num: 1,
2232
0
                            error,
2233
0
                        },
2234
0
                        prototype: self.inner.into_prototype(),
2235
0
                    };
2236
0
                }
2237
2238
0
                let (msg_str_ptr, msg_str_size) = expect_pointer_size_raw!(2);
2239
0
                let msg_utf8_check = str::from_utf8(
2240
0
                    self.inner
2241
0
                        .vm
2242
0
                        .read_memory(msg_str_ptr, msg_str_size)
2243
0
                        .unwrap_or_else(|_| unreachable!())
2244
0
                        .as_ref(),
2245
0
                )
2246
0
                .map(|_| ());
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesi_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesi_0Bb_
2247
0
                if let Err(error) = msg_utf8_check {
2248
0
                    return HostVm::Error {
2249
0
                        error: Error::Utf8Error {
2250
0
                            function: host_fn.name(),
2251
0
                            param_num: 2,
2252
0
                            error,
2253
0
                        },
2254
0
                        prototype: self.inner.into_prototype(),
2255
0
                    };
2256
0
                }
2257
0
2258
0
                HostVm::LogEmit(LogEmit {
2259
0
                    inner: self.inner,
2260
0
                    log_entry: LogEmitInner::Log {
2261
0
                        log_level,
2262
0
                        target_str_ptr,
2263
0
                        target_str_size,
2264
0
                        msg_str_ptr,
2265
0
                        msg_str_size,
2266
0
                    },
2267
0
                })
2268
            }
2269
            HostFunction::ext_logging_max_level_version_1 => {
2270
136
                HostVm::GetMaxLogLevel(GetMaxLogLevel { inner: self.inner })
2271
            }
2272
            HostFunction::ext_panic_handler_abort_on_panic_version_1 => {
2273
0
                let message = {
2274
0
                    let message_bytes = expect_pointer_size!(0);
2275
0
                    str::from_utf8(message_bytes.as_ref()).map(|msg| msg.to_owned())
Unexecuted instantiation: _RNCNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesj_0Bb_
Unexecuted instantiation: _RNCNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_10ReadyToRun8run_oncesj_0Bb_
2276
0
                };
2277
0
2278
0
                match message {
2279
0
                    Ok(message) => HostVm::Error {
2280
0
                        error: Error::AbortOnPanic { message },
2281
0
                        prototype: self.inner.into_prototype(),
2282
0
                    },
2283
0
                    Err(error) => HostVm::Error {
2284
0
                        error: Error::Utf8Error {
2285
0
                            function: host_fn.name(),
2286
0
                            param_num: 0,
2287
0
                            error,
2288
0
                        },
2289
0
                        prototype: self.inner.into_prototype(),
2290
0
                    },
2291
                }
2292
            }
2293
        }
2294
34.4k
    }
_RNvMs2_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_10ReadyToRun8run_once
Line
Count
Source
749
29.2k
    fn run_once(mut self) -> HostVm {
750
        // `vm::ExecOutcome::Interrupted` is by far the variant that requires the most
751
        // handling code. As such, special-case all other variants before.
752
29.2k
        let (
id, params29.1k
) = match self.inner.vm.run(self.resume_value) {
753
29.1k
            Ok(vm::ExecOutcome::Interrupted { id, params }) => (id, params),
754
755
            Ok(vm::ExecOutcome::Finished {
756
42
                return_value: Ok(Some(vm::WasmValue::I64(ret))),
757
42
            }) => {
758
42
                // Wasm virtual machine has successfully returned.
759
42
760
42
                if self.inner.storage_transaction_depth > 0 {
761
0
                    return HostVm::Error {
762
0
                        prototype: self.inner.into_prototype(),
763
0
                        error: Error::FinishedWithPendingTransaction,
764
0
                    };
765
42
                }
766
42
767
42
                // Turn the `i64` into a `u64`, not changing any bit.
768
42
                let ret = u64::from_ne_bytes(ret.to_ne_bytes());
769
42
770
42
                // According to the runtime environment specification, the return value is two
771
42
                // consecutive I32s representing the length and size of the SCALE-encoded
772
42
                // return value.
773
42
                let value_size = u32::try_from(ret >> 32).unwrap_or_else(|_| unreachable!());
774
42
                let value_ptr = u32::try_from(ret & 0xffff_ffff).unwrap_or_else(|_| unreachable!());
775
42
776
42
                if value_size.saturating_add(value_ptr)
777
42
                    <= u32::from(self.inner.vm.memory_size()) * 64 * 1024
778
                {
779
38
                    return HostVm::Finished(Finished {
780
38
                        inner: self.inner,
781
38
                        value_ptr,
782
38
                        value_size,
783
38
                    });
784
4
                }
785
4
                let error = Error::ReturnedPtrOutOfRange {
786
4
                    pointer: value_ptr,
787
4
                    size: value_size,
788
4
                    memory_size: u32::from(self.inner.vm.memory_size()) * 64 * 1024,
789
4
                };
790
4
791
4
                return HostVm::Error {
792
4
                    prototype: self.inner.into_prototype(),
793
4
                    error,
794
4
                };
795
            }
796
797
            Ok(vm::ExecOutcome::Finished {
798
2
                return_value: Ok(return_value),
799
2
            }) => {
800
2
                // The Wasm function has successfully returned, but the specs require that it
801
2
                // returns a `i64`.
802
2
                return HostVm::Error {
803
2
                    prototype: self.inner.into_prototype(),
804
2
                    error: Error::BadReturnValue {
805
2
                        actual: return_value.map(|v| v.ty()),
806
2
                    },
807
2
                };
808
            }
809
810
            Ok(vm::ExecOutcome::Finished {
811
2
                return_value: Err(err),
812
2
            }) => {
813
2
                return HostVm::Error {
814
2
                    error: Error::Trap(err),
815
2
                    prototype: self.inner.into_prototype(),
816
2
                };
817
            }
818
819
            Err(vm::RunErr::BadValueTy { .. }) => {
820
                // Tried to inject back the value returned by a host function, but it doesn't
821
                // match what the Wasm code expects. Given that we check the host function
822
                // signatures at initialization, this indicates a bug in this implementation.
823
0
                unreachable!()
824
            }
825
826
            Err(vm::RunErr::Poisoned) => {
827
                // Can only happen if there's a bug somewhere.
828
0
                unreachable!()
829
            }
830
        };
831
832
        // The Wasm code has called an host_fn. The `id` is a value that we passed
833
        // at initialization, and corresponds to an index in `registered_functions`.
834
29.1k
        let 
host_fn29.1k
= match self.inner.common.registered_functions.get(id) {
835
29.1k
            Some(FunctionImport::Resolved(f)) => *f,
836
2
            Some(FunctionImport::Unresolved { name, module }) => {
837
2
                return HostVm::Error {
838
2
                    error: Error::UnresolvedFunctionCalled {
839
2
                        function: name.clone(),
840
2
                        module_name: module.clone(),
841
2
                    },
842
2
                    prototype: self.inner.into_prototype(),
843
2
                };
844
            }
845
0
            None => unreachable!(),
846
        };
847
848
        // Passed a parameter index. Produces an `impl AsRef<[u8]>`.
849
        macro_rules! expect_pointer_size {
850
            ($num:expr) => {{
851
                let val = match &params[$num] {
852
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
853
                    // The signatures are checked at initialization and the Wasm VM ensures that
854
                    // the proper parameter types are provided.
855
                    _ => unreachable!(),
856
                };
857
858
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
859
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
860
861
                let result = self.inner.vm.read_memory(ptr, len);
862
                match result {
863
                    Ok(v) => v,
864
                    Err(vm::OutOfBoundsError) => {
865
                        drop(result);
866
                        return HostVm::Error {
867
                            error: Error::ParamOutOfRange {
868
                                function: host_fn.name(),
869
                                param_num: $num,
870
                                pointer: ptr,
871
                                length: len,
872
                            },
873
                            prototype: self.inner.into_prototype(),
874
                        };
875
                    }
876
                }
877
            }};
878
        }
879
880
        macro_rules! expect_pointer_size_raw {
881
            ($num:expr) => {{
882
                let val = match &params[$num] {
883
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
884
                    // The signatures are checked at initialization and the Wasm VM ensures that
885
                    // the proper parameter types are provided.
886
                    _ => unreachable!(),
887
                };
888
889
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
890
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
891
892
                if len.saturating_add(ptr) > u32::from(self.inner.vm.memory_size()) * 64 * 1024 {
893
                    return HostVm::Error {
894
                        error: Error::ParamOutOfRange {
895
                            function: host_fn.name(),
896
                            param_num: $num,
897
                            pointer: ptr,
898
                            length: len,
899
                        },
900
                        prototype: self.inner.into_prototype(),
901
                    };
902
                }
903
904
                (ptr, len)
905
            }};
906
        }
907
908
        macro_rules! expect_pointer_constant_size {
909
            ($num:expr, $size:expr) => {{
910
                let ptr = match params[$num] {
911
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
912
                    // The signatures are checked at initialization and the Wasm VM ensures that
913
                    // the proper parameter types are provided.
914
                    _ => unreachable!(),
915
                };
916
917
                let result = self.inner.vm.read_memory(ptr, $size);
918
                match result {
919
                    Ok(v) => {
920
                        *<&[u8; $size]>::try_from(v.as_ref()).unwrap_or_else(|_| unreachable!())
921
                    }
922
                    Err(vm::OutOfBoundsError) => {
923
                        drop(result);
924
                        return HostVm::Error {
925
                            error: Error::ParamOutOfRange {
926
                                function: host_fn.name(),
927
                                param_num: $num,
928
                                pointer: ptr,
929
                                length: $size,
930
                            },
931
                            prototype: self.inner.into_prototype(),
932
                        };
933
                    }
934
                }
935
            }};
936
        }
937
938
        macro_rules! expect_pointer_constant_size_raw {
939
            ($num:expr, $size:expr) => {{
940
                let ptr = match params[$num] {
941
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
942
                    // The signatures are checked at initialization and the Wasm VM ensures that
943
                    // the proper parameter types are provided.
944
                    _ => unreachable!(),
945
                };
946
947
                if u32::saturating_add($size, ptr)
948
                    > u32::from(self.inner.vm.memory_size()) * 64 * 1024
949
                {
950
                    return HostVm::Error {
951
                        error: Error::ParamOutOfRange {
952
                            function: host_fn.name(),
953
                            param_num: $num,
954
                            pointer: ptr,
955
                            length: $size,
956
                        },
957
                        prototype: self.inner.into_prototype(),
958
                    };
959
                }
960
961
                ptr
962
            }};
963
        }
964
965
        macro_rules! expect_u32 {
966
            ($num:expr) => {{
967
                match &params[$num] {
968
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
969
                    // The signatures are checked at initialization and the Wasm VM ensures that
970
                    // the proper parameter types are provided.
971
                    _ => unreachable!(),
972
                }
973
            }};
974
        }
975
976
        macro_rules! expect_offchain_storage_kind {
977
            ($num:expr) => {{
978
                match &params[$num] {
979
                    // `0` indicates `StorageKind::PERSISTENT`, the only kind of offchain
980
                    // storage that is available.
981
                    vm::WasmValue::I32(0) => true,
982
                    // `1` indicates `StorageKind::LOCAL`, which is valid but has never been
983
                    // implemented in Substrate.
984
                    vm::WasmValue::I32(1) => false,
985
                    vm::WasmValue::I32(_) => {
986
                        return HostVm::Error {
987
                            error: Error::ParamDecodeError,
988
                            prototype: self.inner.into_prototype(),
989
                        };
990
                    }
991
                    // The signatures are checked at initialization and the Wasm VM ensures that
992
                    // the proper parameter types are provided.
993
                    _ => unreachable!(),
994
                }
995
            }};
996
        }
997
998
        macro_rules! expect_state_version {
999
            ($num:expr) => {{
1000
                match &params[$num] {
1001
                    vm::WasmValue::I32(0) => TrieEntryVersion::V0,
1002
                    vm::WasmValue::I32(1) => TrieEntryVersion::V1,
1003
                    vm::WasmValue::I32(_) => {
1004
                        return HostVm::Error {
1005
                            error: Error::ParamDecodeError,
1006
                            prototype: self.inner.into_prototype(),
1007
                        };
1008
                    }
1009
                    // The signatures are checked at initialization and the Wasm VM ensures that
1010
                    // the proper parameter types are provided.
1011
                    _ => unreachable!(),
1012
                }
1013
            }};
1014
        }
1015
1016
        // TODO: implement all functions and remove this macro
1017
        macro_rules! host_fn_not_implemented {
1018
            () => {{
1019
                return HostVm::Error {
1020
                    error: Error::HostFunctionNotImplemented {
1021
                        function: host_fn.name(),
1022
                    },
1023
                    prototype: self.inner.into_prototype(),
1024
                };
1025
            }};
1026
        }
1027
1028
        // Handle the function calls.
1029
        // Some of these enum variants simply change the state of `self`, while most of them
1030
        // instead return an `ExternalVm` to the user.
1031
29.1k
        match host_fn {
1032
            HostFunction::ext_storage_set_version_1 => {
1033
300
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1034
300
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1035
300
                HostVm::ExternalStorageSet(ExternalStorageSet {
1036
300
                    key_ptr,
1037
300
                    key_size,
1038
300
                    child_trie_ptr_size: None,
1039
300
                    value: Some((value_ptr, value_size)),
1040
300
                    inner: self.inner,
1041
300
                })
1042
            }
1043
            HostFunction::ext_storage_get_version_1 => {
1044
571
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1045
571
                HostVm::ExternalStorageGet(ExternalStorageGet {
1046
571
                    key_ptr,
1047
571
                    key_size,
1048
571
                    child_trie_ptr_size: None,
1049
571
                    calling: id,
1050
571
                    value_out_ptr: None,
1051
571
                    offset: 0,
1052
571
                    max_size: u32::MAX,
1053
571
                    inner: self.inner,
1054
571
                })
1055
            }
1056
            HostFunction::ext_storage_read_version_1 => {
1057
10
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1058
10
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(1);
1059
10
                let offset = expect_u32!(2);
1060
10
                HostVm::ExternalStorageGet(ExternalStorageGet {
1061
10
                    key_ptr,
1062
10
                    key_size,
1063
10
                    child_trie_ptr_size: None,
1064
10
                    calling: id,
1065
10
                    value_out_ptr: Some(value_out_ptr),
1066
10
                    offset,
1067
10
                    max_size: value_out_size,
1068
10
                    inner: self.inner,
1069
10
                })
1070
            }
1071
            HostFunction::ext_storage_clear_version_1 => {
1072
71
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1073
71
                HostVm::ExternalStorageSet(ExternalStorageSet {
1074
71
                    key_ptr,
1075
71
                    key_size,
1076
71
                    child_trie_ptr_size: None,
1077
71
                    value: None,
1078
71
                    inner: self.inner,
1079
71
                })
1080
            }
1081
            HostFunction::ext_storage_exists_version_1 => {
1082
16
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1083
16
                HostVm::ExternalStorageGet(ExternalStorageGet {
1084
16
                    key_ptr,
1085
16
                    key_size,
1086
16
                    child_trie_ptr_size: None,
1087
16
                    calling: id,
1088
16
                    value_out_ptr: None,
1089
16
                    offset: 0,
1090
16
                    max_size: 0,
1091
16
                    inner: self.inner,
1092
16
                })
1093
            }
1094
            HostFunction::ext_storage_clear_prefix_version_1 => {
1095
1
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1096
1
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1097
1
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1098
1
                    child_trie_ptr_size: None,
1099
1
                    inner: self.inner,
1100
1
                    max_keys_to_remove: None,
1101
1
                    calling: id,
1102
1
                })
1103
            }
1104
            HostFunction::ext_storage_clear_prefix_version_2 => {
1105
4
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1106
1107
4
                let max_keys_to_remove = {
1108
4
                    let input = expect_pointer_size!(1);
1109
4
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1110
4
                        nom::Parser::parse(
1111
4
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1112
4
                                nom::number::streaming::le_u32,
1113
4
                            )),
1114
4
                            input.as_ref(),
1115
4
                        )
1116
4
                        .map(|(_, parse_result)| parse_result);
1117
4
1118
4
                    match parsing_result {
1119
4
                        Ok(val) => Ok(val),
1120
0
                        Err(_) => Err(()),
1121
                    }
1122
                };
1123
1124
4
                let max_keys_to_remove = match max_keys_to_remove {
1125
4
                    Ok(l) => l,
1126
                    Err(()) => {
1127
0
                        return HostVm::Error {
1128
0
                            error: Error::ParamDecodeError,
1129
0
                            prototype: self.inner.into_prototype(),
1130
0
                        };
1131
                    }
1132
                };
1133
1134
4
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1135
4
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1136
4
                    child_trie_ptr_size: None,
1137
4
                    inner: self.inner,
1138
4
                    max_keys_to_remove,
1139
4
                    calling: id,
1140
4
                })
1141
            }
1142
            HostFunction::ext_storage_root_version_1 => {
1143
1
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1144
1
                    inner: self.inner,
1145
1
                    calling: id,
1146
1
                    child_trie_ptr_size: None,
1147
1
                })
1148
            }
1149
            HostFunction::ext_storage_root_version_2 => {
1150
                // The `ext_storage_root_version_2` host function gets passed as parameter the
1151
                // state version of the runtime. This is in fact completely unnecessary as the
1152
                // same information is found in the runtime specification, and this parameter
1153
                // should be considered as a historical accident. We verify that the version
1154
                // provided as parameter is the same as the one in the specification.
1155
4
                let version_param = expect_state_version!(0);
1156
4
                let version_spec = self
1157
4
                    .inner
1158
4
                    .common
1159
4
                    .runtime_version
1160
4
                    .as_ref()
1161
4
                    .unwrap_or_else(|| unreachable!())
1162
4
                    .decode()
1163
4
                    .state_version
1164
4
                    .unwrap_or(TrieEntryVersion::V0);
1165
4
1166
4
                if version_param != version_spec {
1167
0
                    return HostVm::Error {
1168
0
                        error: Error::StateVersionMismatch {
1169
0
                            parameter: version_param,
1170
0
                            specification: version_spec,
1171
0
                        },
1172
0
                        prototype: self.inner.into_prototype(),
1173
0
                    };
1174
4
                }
1175
4
1176
4
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1177
4
                    inner: self.inner,
1178
4
                    calling: id,
1179
4
                    child_trie_ptr_size: None,
1180
4
                })
1181
            }
1182
            HostFunction::ext_storage_changes_root_version_1 => {
1183
                // The changes trie is an obsolete attempt at having a second trie containing, for
1184
                // each storage item, the latest block height where this item has been modified.
1185
                // When this function returns `None`, it indicates that the changes trie is
1186
                // disabled. While this function used to be called by the runtimes of
1187
                // Westend/Polkadot/Kusama (and maybe others), it has never returned anything else
1188
                // but `None`. The entire changes trie mechanism was ultimately removed in
1189
                // October 2021.
1190
                // This function is no longer called by recent runtimes, but must be preserved for
1191
                // backwards compatibility.
1192
1
                self.inner.alloc_write_and_return_pointer_size(
1193
1
                    HostFunction::ext_storage_changes_root_version_1.name(),
1194
1
                    iter::once(&[0][..]),
1195
1
                )
1196
            }
1197
            HostFunction::ext_storage_next_key_version_1 => {
1198
1
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1199
1
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1200
1
                    key_ptr,
1201
1
                    key_size,
1202
1
                    child_trie_ptr_size: None,
1203
1
                    inner: self.inner,
1204
1
                })
1205
            }
1206
            HostFunction::ext_storage_append_version_1 => {
1207
71
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1208
71
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1209
71
                HostVm::ExternalStorageAppend(ExternalStorageAppend {
1210
71
                    key_ptr,
1211
71
                    key_size,
1212
71
                    value_ptr,
1213
71
                    value_size,
1214
71
                    inner: self.inner,
1215
71
                })
1216
            }
1217
            HostFunction::ext_storage_start_transaction_version_1 => {
1218
                // TODO: a maximum depth is important in order to prevent a malicious runtime from crashing the client, but the depth needs to be the same as in Substrate; figure out
1219
14
                self.inner.storage_transaction_depth += 1;
1220
14
                HostVm::StartStorageTransaction(StartStorageTransaction { inner: self.inner })
1221
            }
1222
            HostFunction::ext_storage_rollback_transaction_version_1 => {
1223
0
                if self.inner.storage_transaction_depth == 0 {
1224
0
                    return HostVm::Error {
1225
0
                        error: Error::NoActiveTransaction,
1226
0
                        prototype: self.inner.into_prototype(),
1227
0
                    };
1228
0
                }
1229
0
1230
0
                self.inner.storage_transaction_depth -= 1;
1231
0
                HostVm::EndStorageTransaction {
1232
0
                    resume: EndStorageTransaction { inner: self.inner },
1233
0
                    rollback: true,
1234
0
                }
1235
            }
1236
            HostFunction::ext_storage_commit_transaction_version_1 => {
1237
14
                if self.inner.storage_transaction_depth == 0 {
1238
0
                    return HostVm::Error {
1239
0
                        error: Error::NoActiveTransaction,
1240
0
                        prototype: self.inner.into_prototype(),
1241
0
                    };
1242
14
                }
1243
14
1244
14
                self.inner.storage_transaction_depth -= 1;
1245
14
                HostVm::EndStorageTransaction {
1246
14
                    resume: EndStorageTransaction { inner: self.inner },
1247
14
                    rollback: false,
1248
14
                }
1249
            }
1250
            HostFunction::ext_storage_proof_size_storage_proof_size_version_1 => {
1251
0
                match self.inner.storage_proof_size_behavior {
1252
0
                    StorageProofSizeBehavior::ConstantReturnValue(value) => {
1253
0
                        HostVm::ReadyToRun(ReadyToRun {
1254
0
                            inner: self.inner,
1255
0
                            resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(
1256
0
                                value.to_ne_bytes(),
1257
0
                            ))),
1258
0
                        })
1259
                    }
1260
0
                    StorageProofSizeBehavior::Unimplemented => HostVm::Error {
1261
0
                        error: Error::HostFunctionNotImplemented {
1262
0
                            function: host_fn.name(),
1263
0
                        },
1264
0
                        prototype: self.inner.into_prototype(),
1265
0
                    },
1266
                }
1267
            }
1268
            HostFunction::ext_default_child_storage_get_version_1 => {
1269
2
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1270
2
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1271
2
                HostVm::ExternalStorageGet(ExternalStorageGet {
1272
2
                    key_ptr,
1273
2
                    key_size,
1274
2
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1275
2
                    calling: id,
1276
2
                    value_out_ptr: None,
1277
2
                    offset: 0,
1278
2
                    max_size: u32::MAX,
1279
2
                    inner: self.inner,
1280
2
                })
1281
            }
1282
            HostFunction::ext_default_child_storage_read_version_1 => {
1283
4
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1284
4
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1285
4
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(2);
1286
4
                let offset = expect_u32!(3);
1287
4
                HostVm::ExternalStorageGet(ExternalStorageGet {
1288
4
                    key_ptr,
1289
4
                    key_size,
1290
4
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1291
4
                    calling: id,
1292
4
                    value_out_ptr: Some(value_out_ptr),
1293
4
                    offset,
1294
4
                    max_size: value_out_size,
1295
4
                    inner: self.inner,
1296
4
                })
1297
            }
1298
            HostFunction::ext_default_child_storage_storage_kill_version_1 => {
1299
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1300
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1301
0
                    prefix_ptr_size: None,
1302
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1303
0
                    inner: self.inner,
1304
0
                    max_keys_to_remove: None,
1305
0
                    calling: id,
1306
0
                })
1307
            }
1308
            HostFunction::ext_default_child_storage_storage_kill_version_2
1309
            | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
1310
1
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1311
1312
1
                let max_keys_to_remove = {
1313
1
                    let input = expect_pointer_size!(1);
1314
1
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1315
1
                        nom::Parser::parse(
1316
1
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1317
1
                                nom::number::streaming::le_u32,
1318
1
                            )),
1319
1
                            input.as_ref(),
1320
1
                        )
1321
1
                        .map(|(_, parse_result)| parse_result);
1322
1
1323
1
                    match parsing_result {
1324
1
                        Ok(val) => Ok(val),
1325
0
                        Err(_) => Err(()),
1326
                    }
1327
                };
1328
1329
1
                let max_keys_to_remove = match max_keys_to_remove {
1330
1
                    Ok(l) => l,
1331
                    Err(()) => {
1332
0
                        return HostVm::Error {
1333
0
                            error: Error::ParamDecodeError,
1334
0
                            prototype: self.inner.into_prototype(),
1335
0
                        };
1336
                    }
1337
                };
1338
1339
1
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1340
1
                    prefix_ptr_size: None,
1341
1
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1342
1
                    inner: self.inner,
1343
1
                    max_keys_to_remove,
1344
1
                    calling: id,
1345
1
                })
1346
            }
1347
            HostFunction::ext_default_child_storage_clear_prefix_version_1 => {
1348
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1349
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1350
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1351
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1352
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1353
0
                    inner: self.inner,
1354
0
                    max_keys_to_remove: None,
1355
0
                    calling: id,
1356
0
                })
1357
            }
1358
            HostFunction::ext_default_child_storage_clear_prefix_version_2 => {
1359
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1360
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1361
1362
0
                let max_keys_to_remove = {
1363
0
                    let input = expect_pointer_size!(2);
1364
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1365
0
                        nom::Parser::parse(
1366
0
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1367
0
                                nom::number::streaming::le_u32,
1368
0
                            )),
1369
0
                            input.as_ref(),
1370
0
                        )
1371
0
                        .map(|(_, parse_result)| parse_result);
1372
0
1373
0
                    match parsing_result {
1374
0
                        Ok(val) => Ok(val),
1375
0
                        Err(_) => Err(()),
1376
                    }
1377
                };
1378
1379
0
                let max_keys_to_remove = match max_keys_to_remove {
1380
0
                    Ok(l) => l,
1381
                    Err(()) => {
1382
0
                        return HostVm::Error {
1383
0
                            error: Error::ParamDecodeError,
1384
0
                            prototype: self.inner.into_prototype(),
1385
0
                        };
1386
                    }
1387
                };
1388
1389
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1390
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1391
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1392
0
                    inner: self.inner,
1393
0
                    max_keys_to_remove,
1394
0
                    calling: id,
1395
0
                })
1396
            }
1397
            HostFunction::ext_default_child_storage_set_version_1 => {
1398
4
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1399
4
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1400
4
                let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1401
4
                HostVm::ExternalStorageSet(ExternalStorageSet {
1402
4
                    key_ptr,
1403
4
                    key_size,
1404
4
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1405
4
                    value: Some((value_ptr, value_size)),
1406
4
                    inner: self.inner,
1407
4
                })
1408
            }
1409
            HostFunction::ext_default_child_storage_clear_version_1 => {
1410
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1411
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1412
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1413
0
                    key_ptr,
1414
0
                    key_size,
1415
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1416
0
                    value: None,
1417
0
                    inner: self.inner,
1418
0
                })
1419
            }
1420
            HostFunction::ext_default_child_storage_exists_version_1 => {
1421
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1422
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1423
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1424
0
                    key_ptr,
1425
0
                    key_size,
1426
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1427
0
                    calling: id,
1428
0
                    value_out_ptr: None,
1429
0
                    offset: 0,
1430
0
                    max_size: 0,
1431
0
                    inner: self.inner,
1432
0
                })
1433
            }
1434
            HostFunction::ext_default_child_storage_next_key_version_1 => {
1435
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1436
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1437
0
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1438
0
                    key_ptr,
1439
0
                    key_size,
1440
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1441
0
                    inner: self.inner,
1442
0
                })
1443
            }
1444
            HostFunction::ext_default_child_storage_root_version_1 => {
1445
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1446
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1447
0
                    inner: self.inner,
1448
0
                    calling: id,
1449
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1450
0
                })
1451
            }
1452
            HostFunction::ext_default_child_storage_root_version_2 => {
1453
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1454
1455
                // The `ext_default_child_storage_root_version_2` host function gets passed as
1456
                // parameter the state version of the runtime. This is in fact completely
1457
                // unnecessary as the same information is found in the runtime specification, and
1458
                // this parameter should be considered as a historical accident. We verify that the
1459
                // version provided as parameter is the same as the one in the specification.
1460
0
                let version_param = expect_state_version!(1);
1461
0
                let version_spec = self
1462
0
                    .inner
1463
0
                    .common
1464
0
                    .runtime_version
1465
0
                    .as_ref()
1466
0
                    .unwrap_or_else(|| unreachable!())
1467
0
                    .decode()
1468
0
                    .state_version
1469
0
                    .unwrap_or(TrieEntryVersion::V0);
1470
0
1471
0
                if version_param != version_spec {
1472
0
                    return HostVm::Error {
1473
0
                        error: Error::StateVersionMismatch {
1474
0
                            parameter: version_param,
1475
0
                            specification: version_spec,
1476
0
                        },
1477
0
                        prototype: self.inner.into_prototype(),
1478
0
                    };
1479
0
                }
1480
0
1481
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1482
0
                    inner: self.inner,
1483
0
                    calling: id,
1484
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1485
0
                })
1486
            }
1487
0
            HostFunction::ext_crypto_ed25519_public_keys_version_1 => host_fn_not_implemented!(),
1488
0
            HostFunction::ext_crypto_ed25519_generate_version_1 => host_fn_not_implemented!(),
1489
0
            HostFunction::ext_crypto_ed25519_sign_version_1 => host_fn_not_implemented!(),
1490
            HostFunction::ext_crypto_ed25519_verify_version_1
1491
            | HostFunction::ext_crypto_ed25519_batch_verify_version_1 => {
1492
0
                let is_batch_verification = matches!(
1493
0
                    host_fn,
1494
                    HostFunction::ext_crypto_ed25519_batch_verify_version_1
1495
                );
1496
1497
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1498
0
                    return HostVm::Error {
1499
0
                        error: Error::BatchVerifyWithoutStarting,
1500
0
                        prototype: self.inner.into_prototype(),
1501
0
                    };
1502
0
                }
1503
1504
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1505
                HostVm::SignatureVerification(SignatureVerification {
1506
0
                    algorithm: SignatureVerificationAlgorithm::Ed25519,
1507
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1508
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1509
0
                    message_ptr,
1510
0
                    message_size,
1511
0
                    inner: self.inner,
1512
0
                    is_batch_verification,
1513
                })
1514
            }
1515
0
            HostFunction::ext_crypto_sr25519_public_keys_version_1 => host_fn_not_implemented!(),
1516
0
            HostFunction::ext_crypto_sr25519_generate_version_1 => host_fn_not_implemented!(),
1517
0
            HostFunction::ext_crypto_sr25519_sign_version_1 => host_fn_not_implemented!(),
1518
            HostFunction::ext_crypto_sr25519_verify_version_1
1519
            | HostFunction::ext_crypto_sr25519_batch_verify_version_1 => {
1520
0
                let is_batch_verification = matches!(
1521
0
                    host_fn,
1522
                    HostFunction::ext_crypto_sr25519_batch_verify_version_1
1523
                );
1524
1525
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1526
0
                    return HostVm::Error {
1527
0
                        error: Error::BatchVerifyWithoutStarting,
1528
0
                        prototype: self.inner.into_prototype(),
1529
0
                    };
1530
0
                }
1531
1532
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1533
                HostVm::SignatureVerification(SignatureVerification {
1534
0
                    algorithm: SignatureVerificationAlgorithm::Sr25519V1,
1535
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1536
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1537
0
                    message_ptr,
1538
0
                    message_size,
1539
0
                    inner: self.inner,
1540
0
                    is_batch_verification,
1541
                })
1542
            }
1543
            HostFunction::ext_crypto_sr25519_verify_version_2 => {
1544
6
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1545
                HostVm::SignatureVerification(SignatureVerification {
1546
6
                    algorithm: SignatureVerificationAlgorithm::Sr25519V2,
1547
6
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1548
6
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1549
6
                    message_ptr,
1550
6
                    message_size,
1551
6
                    inner: self.inner,
1552
                    is_batch_verification: false,
1553
                })
1554
            }
1555
0
            HostFunction::ext_crypto_ecdsa_generate_version_1 => host_fn_not_implemented!(),
1556
            HostFunction::ext_crypto_ecdsa_sign_version_1 => {
1557
                // NOTE: safe to unwrap here because we supply the nn to blake2b fn
1558
0
                let data = <[u8; 32]>::try_from(
1559
0
                    blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
1560
0
                        .as_bytes(),
1561
0
                )
1562
0
                .unwrap_or_else(|_| unreachable!());
1563
0
                let message = libsecp256k1::Message::parse(&data);
1564
1565
0
                if let Ok(sc) =
1566
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1567
                {
1568
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1569
0
1570
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1571
0
                    self.inner.alloc_write_and_return_pointer(
1572
0
                        host_fn.name(),
1573
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1574
0
                    )
1575
                } else {
1576
0
                    HostVm::Error {
1577
0
                        error: Error::ParamDecodeError,
1578
0
                        prototype: self.inner.into_prototype(),
1579
0
                    }
1580
                }
1581
            }
1582
0
            HostFunction::ext_crypto_ecdsa_public_keys_version_1 => host_fn_not_implemented!(),
1583
            HostFunction::ext_crypto_ecdsa_verify_version_1
1584
            | HostFunction::ext_crypto_ecdsa_batch_verify_version_1 => {
1585
0
                let is_batch_verification = matches!(
1586
0
                    host_fn,
1587
                    HostFunction::ext_crypto_ecdsa_batch_verify_version_1
1588
                );
1589
1590
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1591
0
                    return HostVm::Error {
1592
0
                        error: Error::BatchVerifyWithoutStarting,
1593
0
                        prototype: self.inner.into_prototype(),
1594
0
                    };
1595
0
                }
1596
1597
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1598
                HostVm::SignatureVerification(SignatureVerification {
1599
0
                    algorithm: SignatureVerificationAlgorithm::Ecdsa,
1600
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1601
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1602
0
                    message_ptr,
1603
0
                    message_size,
1604
0
                    inner: self.inner,
1605
0
                    is_batch_verification,
1606
                })
1607
            }
1608
0
            HostFunction::ext_crypto_ecdsa_verify_version_2 => host_fn_not_implemented!(),
1609
            HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => {
1610
                // TODO: seems misimplemented, see https://spec.polkadot.network/#id-ext_crypto_ecdsa_sign_prehashed
1611
0
                let message = libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));
1612
1613
0
                if let Ok(sc) =
1614
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1615
                {
1616
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1617
0
1618
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1619
0
                    self.inner.alloc_write_and_return_pointer(
1620
0
                        host_fn.name(),
1621
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1622
0
                    )
1623
                } else {
1624
0
                    HostVm::Error {
1625
0
                        error: Error::ParamDecodeError,
1626
0
                        prototype: self.inner.into_prototype(),
1627
0
                    }
1628
                }
1629
            }
1630
            HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => {
1631
                HostVm::SignatureVerification(SignatureVerification {
1632
0
                    algorithm: SignatureVerificationAlgorithm::EcdsaPrehashed,
1633
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1634
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1635
0
                    message_ptr: expect_pointer_constant_size_raw!(1, 32),
1636
                    message_size: 32,
1637
0
                    inner: self.inner,
1638
                    is_batch_verification: false,
1639
                })
1640
            }
1641
1642
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1
1643
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => {
1644
0
                let sig = expect_pointer_constant_size!(0, 65);
1645
0
                let msg = expect_pointer_constant_size!(1, 32);
1646
0
                let is_v2 = matches!(
1647
0
                    host_fn,
1648
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2
1649
                );
1650
1651
0
                let result = {
1652
0
                    let rs = if is_v2 {
1653
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1654
                    } else {
1655
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1656
                    };
1657
1658
0
                    if let Ok(rs) = rs {
1659
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1660
0
                            sig[64] - 27
1661
                        } else {
1662
0
                            sig[64]
1663
                        });
1664
1665
0
                        if let Ok(v) = v {
1666
0
                            let pubkey = libsecp256k1::recover(
1667
0
                                &libsecp256k1::Message::parse_slice(&msg)
1668
0
                                    .unwrap_or_else(|_| unreachable!()),
1669
0
                                &rs,
1670
0
                                &v,
1671
0
                            );
1672
1673
0
                            if let Ok(pubkey) = pubkey {
1674
0
                                let mut res = Vec::with_capacity(65);
1675
0
                                res.push(0);
1676
0
                                res.extend_from_slice(&pubkey.serialize()[1..65]);
1677
0
                                res
1678
                            } else {
1679
0
                                vec![1, 2]
1680
                            }
1681
                        } else {
1682
0
                            vec![1, 1]
1683
                        }
1684
                    } else {
1685
0
                        vec![1, 0]
1686
                    }
1687
                };
1688
1689
0
                self.inner
1690
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1691
            }
1692
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_1
1693
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2 => {
1694
0
                let sig = expect_pointer_constant_size!(0, 65);
1695
0
                let msg = expect_pointer_constant_size!(1, 32);
1696
0
                let is_v2 = matches!(
1697
0
                    host_fn,
1698
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2
1699
                );
1700
1701
0
                let result = {
1702
0
                    let rs = if is_v2 {
1703
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1704
                    } else {
1705
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1706
                    };
1707
1708
0
                    if let Ok(rs) = rs {
1709
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1710
0
                            sig[64] - 27
1711
                        } else {
1712
0
                            sig[64]
1713
                        });
1714
1715
0
                        if let Ok(v) = v {
1716
0
                            let pubkey = libsecp256k1::recover(
1717
0
                                &libsecp256k1::Message::parse_slice(&msg)
1718
0
                                    .unwrap_or_else(|_| unreachable!()),
1719
0
                                &rs,
1720
0
                                &v,
1721
0
                            );
1722
1723
0
                            if let Ok(pubkey) = pubkey {
1724
0
                                let mut res = Vec::with_capacity(34);
1725
0
                                res.push(0);
1726
0
                                res.extend_from_slice(&pubkey.serialize_compressed());
1727
0
                                res
1728
                            } else {
1729
0
                                vec![1, 2]
1730
                            }
1731
                        } else {
1732
0
                            vec![1, 1]
1733
                        }
1734
                    } else {
1735
0
                        vec![1, 0]
1736
                    }
1737
                };
1738
1739
0
                self.inner
1740
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1741
            }
1742
            HostFunction::ext_crypto_start_batch_verify_version_1 => {
1743
4
                if self.inner.signatures_batch_verification.is_some() {
1744
0
                    return HostVm::Error {
1745
0
                        error: Error::AlreadyBatchVerify,
1746
0
                        prototype: self.inner.into_prototype(),
1747
0
                    };
1748
4
                }
1749
4
1750
4
                self.inner.signatures_batch_verification = Some(true);
1751
4
1752
4
                HostVm::ReadyToRun(ReadyToRun {
1753
4
                    resume_value: None,
1754
4
                    inner: self.inner,
1755
4
                })
1756
            }
1757
            HostFunction::ext_crypto_finish_batch_verify_version_1 => {
1758
4
                let Some(outcome) = self.inner.signatures_batch_verification.take() else {
1759
0
                    return HostVm::Error {
1760
0
                        error: Error::NoBatchVerify,
1761
0
                        prototype: self.inner.into_prototype(),
1762
0
                    };
1763
                };
1764
1765
                HostVm::ReadyToRun(ReadyToRun {
1766
4
                    resume_value: Some(vm::WasmValue::I32(if outcome { 1 } else { 
00
})),
1767
4
                    inner: self.inner,
1768
                })
1769
            }
1770
            HostFunction::ext_hashing_keccak_256_version_1 => {
1771
2
                let hash =
1772
2
                    <sha3::Keccak256 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1773
2
                self.inner
1774
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1775
            }
1776
            HostFunction::ext_hashing_keccak_512_version_1 => {
1777
2
                let hash =
1778
2
                    <sha3::Keccak512 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1779
2
                self.inner
1780
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1781
            }
1782
            HostFunction::ext_hashing_sha2_256_version_1 => {
1783
2
                let hash = <sha2::Sha256 as sha2::Digest>::digest(expect_pointer_size!(0).as_ref());
1784
2
                self.inner
1785
2
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1786
            }
1787
            HostFunction::ext_hashing_blake2_128_version_1 => {
1788
148
                let out = {
1789
148
                    let data = expect_pointer_size!(0);
1790
148
                    blake2_rfc::blake2b::blake2b(16, &[], data.as_ref())
1791
148
                };
1792
148
1793
148
                self.inner
1794
148
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1795
            }
1796
            HostFunction::ext_hashing_blake2_256_version_1 => {
1797
30
                let out = {
1798
30
                    let data = expect_pointer_size!(0);
1799
30
                    blake2_rfc::blake2b::blake2b(32, &[], data.as_ref())
1800
30
                };
1801
30
1802
30
                self.inner
1803
30
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1804
            }
1805
            HostFunction::ext_hashing_twox_64_version_1 => {
1806
67
                let r0 = {
1807
67
                    let data = expect_pointer_size!(0);
1808
67
                    twox_hash::XxHash64::oneshot(0, data.as_ref())
1809
67
                };
1810
67
1811
67
                self.inner
1812
67
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&r0.to_le_bytes()))
1813
            }
1814
            HostFunction::ext_hashing_twox_128_version_1 => {
1815
1.73k
                let [r0, r1] = {
1816
1.73k
                    let data = expect_pointer_size!(0);
1817
1.73k
                    let data = data.as_ref();
1818
1.73k
                    [
1819
1.73k
                        twox_hash::XxHash64::oneshot(0, data),
1820
1.73k
                        twox_hash::XxHash64::oneshot(1, data),
1821
1.73k
                    ]
1822
1.73k
                };
1823
1.73k
1824
1.73k
                self.inner.alloc_write_and_return_pointer(
1825
1.73k
                    host_fn.name(),
1826
1.73k
                    iter::once(&r0.to_le_bytes()).chain(iter::once(&r1.to_le_bytes())),
1827
1.73k
                )
1828
            }
1829
            HostFunction::ext_hashing_twox_256_version_1 => {
1830
2
                let [r0, r1, r2, r3] = {
1831
2
                    let data = expect_pointer_size!(0);
1832
2
                    let data = data.as_ref();
1833
2
                    [
1834
2
                        twox_hash::XxHash64::oneshot(0, data),
1835
2
                        twox_hash::XxHash64::oneshot(1, data),
1836
2
                        twox_hash::XxHash64::oneshot(2, data),
1837
2
                        twox_hash::XxHash64::oneshot(3, data),
1838
2
                    ]
1839
2
                };
1840
2
1841
2
                self.inner.alloc_write_and_return_pointer(
1842
2
                    host_fn.name(),
1843
2
                    iter::once(&r0.to_le_bytes())
1844
2
                        .chain(iter::once(&r1.to_le_bytes()))
1845
2
                        .chain(iter::once(&r2.to_le_bytes()))
1846
2
                        .chain(iter::once(&r3.to_le_bytes())),
1847
2
                )
1848
            }
1849
            HostFunction::ext_offchain_index_set_version_1 => {
1850
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1851
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1852
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1853
0
                    key_ptr,
1854
0
                    key_size,
1855
0
                    value: Some((value_ptr, value_size)),
1856
0
                    inner: self.inner,
1857
0
                })
1858
            }
1859
            HostFunction::ext_offchain_index_clear_version_1 => {
1860
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1861
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1862
0
                    key_ptr,
1863
0
                    key_size,
1864
0
                    value: None,
1865
0
                    inner: self.inner,
1866
0
                })
1867
            }
1868
0
            HostFunction::ext_offchain_is_validator_version_1 => HostVm::ReadyToRun(ReadyToRun {
1869
0
                inner: self.inner,
1870
0
                resume_value: Some(vm::WasmValue::I32(1)), // TODO: ask the API user
1871
0
            }),
1872
            HostFunction::ext_offchain_submit_transaction_version_1 => {
1873
0
                let (tx_ptr, tx_size) = expect_pointer_size_raw!(0);
1874
0
                HostVm::OffchainSubmitTransaction(OffchainSubmitTransaction {
1875
0
                    inner: self.inner,
1876
0
                    calling: id,
1877
0
                    tx_ptr,
1878
0
                    tx_size,
1879
0
                })
1880
            }
1881
            HostFunction::ext_offchain_network_state_version_1 => {
1882
0
                host_fn_not_implemented!()
1883
            }
1884
            HostFunction::ext_offchain_timestamp_version_1 => {
1885
0
                HostVm::OffchainTimestamp(OffchainTimestamp { inner: self.inner })
1886
            }
1887
            HostFunction::ext_offchain_sleep_until_version_1 => {
1888
0
                host_fn_not_implemented!()
1889
            }
1890
            HostFunction::ext_offchain_random_seed_version_1 => {
1891
0
                HostVm::OffchainRandomSeed(OffchainRandomSeed {
1892
0
                    inner: self.inner,
1893
0
                    calling: id,
1894
0
                })
1895
            }
1896
            HostFunction::ext_offchain_local_storage_set_version_1 => {
1897
0
                if expect_offchain_storage_kind!(0) {
1898
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1899
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1900
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1901
0
                        key_ptr,
1902
0
                        key_size,
1903
0
                        value: Some((value_ptr, value_size)),
1904
0
                        old_value: None,
1905
0
                        inner: self.inner,
1906
0
                    })
1907
                } else {
1908
0
                    HostVm::ReadyToRun(ReadyToRun {
1909
0
                        inner: self.inner,
1910
0
                        resume_value: None,
1911
0
                    })
1912
                }
1913
            }
1914
            HostFunction::ext_offchain_local_storage_compare_and_set_version_1 => {
1915
0
                if expect_offchain_storage_kind!(0) {
1916
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1917
0
                    let (old_value_ptr, old_value_size) = expect_pointer_size_raw!(2);
1918
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(3);
1919
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1920
0
                        key_ptr,
1921
0
                        key_size,
1922
0
                        value: Some((value_ptr, value_size)),
1923
0
                        old_value: Some((old_value_ptr, old_value_size)),
1924
0
                        inner: self.inner,
1925
0
                    })
1926
                } else {
1927
0
                    HostVm::ReadyToRun(ReadyToRun {
1928
0
                        inner: self.inner,
1929
0
                        resume_value: Some(vm::WasmValue::I32(0)),
1930
0
                    })
1931
                }
1932
            }
1933
            HostFunction::ext_offchain_local_storage_get_version_1 => {
1934
0
                if expect_offchain_storage_kind!(0) {
1935
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1936
0
                    HostVm::ExternalOffchainStorageGet(ExternalOffchainStorageGet {
1937
0
                        key_ptr,
1938
0
                        key_size,
1939
0
                        calling: id,
1940
0
                        inner: self.inner,
1941
0
                    })
1942
                } else {
1943
                    // Write a SCALE-encoded `None`.
1944
0
                    self.inner
1945
0
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
1946
                }
1947
            }
1948
            HostFunction::ext_offchain_local_storage_clear_version_1 => {
1949
0
                if expect_offchain_storage_kind!(0) {
1950
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1951
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1952
0
                        key_ptr,
1953
0
                        key_size,
1954
0
                        value: None,
1955
0
                        old_value: None,
1956
0
                        inner: self.inner,
1957
0
                    })
1958
                } else {
1959
0
                    HostVm::ReadyToRun(ReadyToRun {
1960
0
                        inner: self.inner,
1961
0
                        resume_value: None,
1962
0
                    })
1963
                }
1964
            }
1965
0
            HostFunction::ext_offchain_http_request_start_version_1 => host_fn_not_implemented!(),
1966
            HostFunction::ext_offchain_http_request_add_header_version_1 => {
1967
0
                host_fn_not_implemented!()
1968
            }
1969
            HostFunction::ext_offchain_http_request_write_body_version_1 => {
1970
0
                host_fn_not_implemented!()
1971
            }
1972
0
            HostFunction::ext_offchain_http_response_wait_version_1 => host_fn_not_implemented!(),
1973
            HostFunction::ext_offchain_http_response_headers_version_1 => {
1974
0
                host_fn_not_implemented!()
1975
            }
1976
            HostFunction::ext_offchain_http_response_read_body_version_1 => {
1977
0
                host_fn_not_implemented!()
1978
            }
1979
            HostFunction::ext_trie_blake2_256_root_version_1
1980
            | HostFunction::ext_trie_blake2_256_root_version_2
1981
            | HostFunction::ext_trie_keccak_256_root_version_1
1982
            | HostFunction::ext_trie_keccak_256_root_version_2 => {
1983
0
                let state_version = if matches!(
1984
0
                    host_fn,
1985
                    HostFunction::ext_trie_blake2_256_root_version_2
1986
                        | HostFunction::ext_trie_keccak_256_root_version_2
1987
                ) {
1988
0
                    expect_state_version!(1)
1989
                } else {
1990
0
                    TrieEntryVersion::V0
1991
                };
1992
1993
0
                let result = {
1994
0
                    let input = expect_pointer_size!(0);
1995
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1996
0
                        nom::Parser::parse(
1997
0
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
1998
0
                                crate::util::nom_scale_compact_usize,
1999
0
                                |num_elems| {
2000
                                    nom::multi::many_m_n(
2001
                                        num_elems,
2002
                                        num_elems,
2003
                                        (
2004
                                            nom::combinator::flat_map(
2005
                                                crate::util::nom_scale_compact_usize,
2006
                                                nom::bytes::streaming::take,
2007
                                            ),
2008
                                            nom::combinator::flat_map(
2009
                                                crate::util::nom_scale_compact_usize,
2010
                                                nom::bytes::streaming::take,
2011
                                            ),
2012
                                        ),
2013
                                    )
2014
0
                                },
2015
0
                            )),
2016
0
                            input.as_ref(),
2017
0
                        )
2018
0
                        .map(|(_, parse_result)| parse_result);
2019
0
2020
0
                    match parsing_result {
2021
0
                        Ok(elements) => Ok(trie::trie_root(
2022
0
                            state_version,
2023
0
                            if matches!(
2024
0
                                host_fn,
2025
                                HostFunction::ext_trie_blake2_256_root_version_1
2026
                                    | HostFunction::ext_trie_blake2_256_root_version_2
2027
                            ) {
2028
0
                                trie::HashFunction::Blake2
2029
                            } else {
2030
0
                                trie::HashFunction::Keccak256
2031
                            },
2032
0
                            &elements[..],
2033
                        )),
2034
0
                        Err(_) => Err(()),
2035
                    }
2036
                };
2037
2038
0
                match result {
2039
0
                    Ok(out) => self
2040
0
                        .inner
2041
0
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2042
0
                    Err(()) => HostVm::Error {
2043
0
                        error: Error::ParamDecodeError,
2044
0
                        prototype: self.inner.into_prototype(),
2045
0
                    },
2046
                }
2047
            }
2048
            HostFunction::ext_trie_blake2_256_ordered_root_version_1
2049
            | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2050
            | HostFunction::ext_trie_keccak_256_ordered_root_version_1
2051
            | HostFunction::ext_trie_keccak_256_ordered_root_version_2 => {
2052
5
                let state_version = if 
matches!1
(
2053
5
                    host_fn,
2054
                    HostFunction::ext_trie_blake2_256_ordered_root_version_2
2055
                        | HostFunction::ext_trie_keccak_256_ordered_root_version_2
2056
                ) {
2057
4
                    expect_state_version!(1)
2058
                } else {
2059
1
                    TrieEntryVersion::V0
2060
                };
2061
2062
5
                let result = {
2063
5
                    let input = expect_pointer_size!(0);
2064
5
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
2065
5
                        nom::Parser::parse(
2066
5
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
2067
5
                                crate::util::nom_scale_compact_usize,
2068
5
                                |num_elems| {
2069
                                    nom::multi::many_m_n(
2070
                                        num_elems,
2071
                                        num_elems,
2072
                                        nom::combinator::flat_map(
2073
                                            crate::util::nom_scale_compact_usize,
2074
                                            nom::bytes::streaming::take,
2075
                                        ),
2076
                                    )
2077
5
                                },
2078
5
                            )),
2079
5
                            input.as_ref(),
2080
5
                        )
2081
5
                        .map(|(_, parse_result)| parse_result);
2082
5
2083
5
                    match parsing_result {
2084
5
                        Ok(elements) => Ok(trie::ordered_root(
2085
5
                            state_version,
2086
0
                            if matches!(
2087
5
                                host_fn,
2088
                                HostFunction::ext_trie_blake2_256_ordered_root_version_1
2089
                                    | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2090
                            ) {
2091
5
                                trie::HashFunction::Blake2
2092
                            } else {
2093
0
                                trie::HashFunction::Keccak256
2094
                            },
2095
5
                            &elements[..],
2096
                        )),
2097
0
                        Err(_) => Err(()),
2098
                    }
2099
                };
2100
2101
5
                match result {
2102
5
                    Ok(out) => self
2103
5
                        .inner
2104
5
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2105
0
                    Err(()) => HostVm::Error {
2106
0
                        error: Error::ParamDecodeError,
2107
0
                        prototype: self.inner.into_prototype(),
2108
0
                    },
2109
                }
2110
            }
2111
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_1 => host_fn_not_implemented!(),
2112
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_2 => host_fn_not_implemented!(),
2113
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_1 => host_fn_not_implemented!(),
2114
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_2 => host_fn_not_implemented!(),
2115
            HostFunction::ext_misc_print_num_version_1 => {
2116
0
                let num = match params[0] {
2117
0
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
2118
                    // The signatures are checked at initialization and the Wasm VM ensures that
2119
                    // the proper parameter types are provided.
2120
0
                    _ => unreachable!(),
2121
                };
2122
2123
0
                HostVm::LogEmit(LogEmit {
2124
0
                    inner: self.inner,
2125
0
                    log_entry: LogEmitInner::Num(num),
2126
0
                })
2127
            }
2128
            HostFunction::ext_misc_print_utf8_version_1 => {
2129
0
                let (str_ptr, str_size) = expect_pointer_size_raw!(0);
2130
2131
0
                let utf8_check = str::from_utf8(
2132
0
                    self.inner
2133
0
                        .vm
2134
0
                        .read_memory(str_ptr, str_size)
2135
0
                        .unwrap_or_else(|_| unreachable!())
2136
0
                        .as_ref(),
2137
0
                )
2138
0
                .map(|_| ());
2139
0
                if let Err(error) = utf8_check {
2140
0
                    return HostVm::Error {
2141
0
                        error: Error::Utf8Error {
2142
0
                            function: host_fn.name(),
2143
0
                            param_num: 2,
2144
0
                            error,
2145
0
                        },
2146
0
                        prototype: self.inner.into_prototype(),
2147
0
                    };
2148
0
                }
2149
0
2150
0
                HostVm::LogEmit(LogEmit {
2151
0
                    inner: self.inner,
2152
0
                    log_entry: LogEmitInner::Utf8 { str_ptr, str_size },
2153
0
                })
2154
            }
2155
            HostFunction::ext_misc_print_hex_version_1 => {
2156
0
                let (data_ptr, data_size) = expect_pointer_size_raw!(0);
2157
0
                HostVm::LogEmit(LogEmit {
2158
0
                    inner: self.inner,
2159
0
                    log_entry: LogEmitInner::Hex {
2160
0
                        data_ptr,
2161
0
                        data_size,
2162
0
                    },
2163
0
                })
2164
            }
2165
            HostFunction::ext_misc_runtime_version_version_1 => {
2166
0
                let (wasm_blob_ptr, wasm_blob_size) = expect_pointer_size_raw!(0);
2167
0
                HostVm::CallRuntimeVersion(CallRuntimeVersion {
2168
0
                    inner: self.inner,
2169
0
                    wasm_blob_ptr,
2170
0
                    wasm_blob_size,
2171
0
                })
2172
            }
2173
            HostFunction::ext_allocator_malloc_version_1 => {
2174
11.7k
                let size = expect_u32!(0);
2175
2176
11.7k
                let ptr = match self.inner.alloc(host_fn.name(), size) {
2177
11.7k
                    Ok(p) => p,
2178
0
                    Err(error) => {
2179
0
                        return HostVm::Error {
2180
0
                            error,
2181
0
                            prototype: self.inner.into_prototype(),
2182
0
                        };
2183
                    }
2184
                };
2185
2186
11.7k
                let ptr_i32 = i32::from_ne_bytes(ptr.to_ne_bytes());
2187
11.7k
                HostVm::ReadyToRun(ReadyToRun {
2188
11.7k
                    resume_value: Some(vm::WasmValue::I32(ptr_i32)),
2189
11.7k
                    inner: self.inner,
2190
11.7k
                })
2191
            }
2192
            HostFunction::ext_allocator_free_version_1 => {
2193
14.3k
                let pointer = expect_u32!(0);
2194
14.3k
                match self.inner.allocator.deallocate(
2195
14.3k
                    &mut MemAccess {
2196
14.3k
                        vm: MemAccessVm::Running(&mut self.inner.vm),
2197
14.3k
                        memory_total_pages: self.inner.common.memory_total_pages,
2198
14.3k
                    },
2199
14.3k
                    pointer,
2200
14.3k
                ) {
2201
14.3k
                    Ok(()) => {}
2202
                    Err(_) => {
2203
0
                        return HostVm::Error {
2204
0
                            error: Error::FreeError { pointer },
2205
0
                            prototype: self.inner.into_prototype(),
2206
0
                        };
2207
                    }
2208
                };
2209
2210
14.3k
                HostVm::ReadyToRun(ReadyToRun {
2211
14.3k
                    resume_value: None,
2212
14.3k
                    inner: self.inner,
2213
14.3k
                })
2214
            }
2215
            HostFunction::ext_logging_log_version_1 => {
2216
0
                let log_level = expect_u32!(0);
2217
2218
0
                let (target_str_ptr, target_str_size) = expect_pointer_size_raw!(1);
2219
0
                let target_utf8_check = str::from_utf8(
2220
0
                    self.inner
2221
0
                        .vm
2222
0
                        .read_memory(target_str_ptr, target_str_size)
2223
0
                        .unwrap_or_else(|_| unreachable!())
2224
0
                        .as_ref(),
2225
0
                )
2226
0
                .map(|_| ());
2227
0
                if let Err(error) = target_utf8_check {
2228
0
                    return HostVm::Error {
2229
0
                        error: Error::Utf8Error {
2230
0
                            function: host_fn.name(),
2231
0
                            param_num: 1,
2232
0
                            error,
2233
0
                        },
2234
0
                        prototype: self.inner.into_prototype(),
2235
0
                    };
2236
0
                }
2237
2238
0
                let (msg_str_ptr, msg_str_size) = expect_pointer_size_raw!(2);
2239
0
                let msg_utf8_check = str::from_utf8(
2240
0
                    self.inner
2241
0
                        .vm
2242
0
                        .read_memory(msg_str_ptr, msg_str_size)
2243
0
                        .unwrap_or_else(|_| unreachable!())
2244
0
                        .as_ref(),
2245
0
                )
2246
0
                .map(|_| ());
2247
0
                if let Err(error) = msg_utf8_check {
2248
0
                    return HostVm::Error {
2249
0
                        error: Error::Utf8Error {
2250
0
                            function: host_fn.name(),
2251
0
                            param_num: 2,
2252
0
                            error,
2253
0
                        },
2254
0
                        prototype: self.inner.into_prototype(),
2255
0
                    };
2256
0
                }
2257
0
2258
0
                HostVm::LogEmit(LogEmit {
2259
0
                    inner: self.inner,
2260
0
                    log_entry: LogEmitInner::Log {
2261
0
                        log_level,
2262
0
                        target_str_ptr,
2263
0
                        target_str_size,
2264
0
                        msg_str_ptr,
2265
0
                        msg_str_size,
2266
0
                    },
2267
0
                })
2268
            }
2269
            HostFunction::ext_logging_max_level_version_1 => {
2270
9
                HostVm::GetMaxLogLevel(GetMaxLogLevel { inner: self.inner })
2271
            }
2272
            HostFunction::ext_panic_handler_abort_on_panic_version_1 => {
2273
0
                let message = {
2274
0
                    let message_bytes = expect_pointer_size!(0);
2275
0
                    str::from_utf8(message_bytes.as_ref()).map(|msg| msg.to_owned())
2276
0
                };
2277
0
2278
0
                match message {
2279
0
                    Ok(message) => HostVm::Error {
2280
0
                        error: Error::AbortOnPanic { message },
2281
0
                        prototype: self.inner.into_prototype(),
2282
0
                    },
2283
0
                    Err(error) => HostVm::Error {
2284
0
                        error: Error::Utf8Error {
2285
0
                            function: host_fn.name(),
2286
0
                            param_num: 0,
2287
0
                            error,
2288
0
                        },
2289
0
                        prototype: self.inner.into_prototype(),
2290
0
                    },
2291
                }
2292
            }
2293
        }
2294
29.2k
    }
_RNvMs2_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_10ReadyToRun8run_once
Line
Count
Source
749
5.20k
    fn run_once(mut self) -> HostVm {
750
        // `vm::ExecOutcome::Interrupted` is by far the variant that requires the most
751
        // handling code. As such, special-case all other variants before.
752
5.20k
        let (
id, params5.07k
) = match self.inner.vm.run(self.resume_value) {
753
5.07k
            Ok(vm::ExecOutcome::Interrupted { id, params }) => (id, params),
754
755
            Ok(vm::ExecOutcome::Finished {
756
127
                return_value: Ok(Some(vm::WasmValue::I64(ret))),
757
127
            }) => {
758
127
                // Wasm virtual machine has successfully returned.
759
127
760
127
                if self.inner.storage_transaction_depth > 0 {
761
0
                    return HostVm::Error {
762
0
                        prototype: self.inner.into_prototype(),
763
0
                        error: Error::FinishedWithPendingTransaction,
764
0
                    };
765
127
                }
766
127
767
127
                // Turn the `i64` into a `u64`, not changing any bit.
768
127
                let ret = u64::from_ne_bytes(ret.to_ne_bytes());
769
127
770
127
                // According to the runtime environment specification, the return value is two
771
127
                // consecutive I32s representing the length and size of the SCALE-encoded
772
127
                // return value.
773
127
                let value_size = u32::try_from(ret >> 32).unwrap_or_else(|_| unreachable!());
774
127
                let value_ptr = u32::try_from(ret & 0xffff_ffff).unwrap_or_else(|_| unreachable!());
775
127
776
127
                if value_size.saturating_add(value_ptr)
777
127
                    <= u32::from(self.inner.vm.memory_size()) * 64 * 1024
778
                {
779
127
                    return HostVm::Finished(Finished {
780
127
                        inner: self.inner,
781
127
                        value_ptr,
782
127
                        value_size,
783
127
                    });
784
0
                }
785
0
                let error = Error::ReturnedPtrOutOfRange {
786
0
                    pointer: value_ptr,
787
0
                    size: value_size,
788
0
                    memory_size: u32::from(self.inner.vm.memory_size()) * 64 * 1024,
789
0
                };
790
0
791
0
                return HostVm::Error {
792
0
                    prototype: self.inner.into_prototype(),
793
0
                    error,
794
0
                };
795
            }
796
797
            Ok(vm::ExecOutcome::Finished {
798
0
                return_value: Ok(return_value),
799
0
            }) => {
800
0
                // The Wasm function has successfully returned, but the specs require that it
801
0
                // returns a `i64`.
802
0
                return HostVm::Error {
803
0
                    prototype: self.inner.into_prototype(),
804
0
                    error: Error::BadReturnValue {
805
0
                        actual: return_value.map(|v| v.ty()),
806
0
                    },
807
0
                };
808
            }
809
810
            Ok(vm::ExecOutcome::Finished {
811
0
                return_value: Err(err),
812
0
            }) => {
813
0
                return HostVm::Error {
814
0
                    error: Error::Trap(err),
815
0
                    prototype: self.inner.into_prototype(),
816
0
                };
817
            }
818
819
            Err(vm::RunErr::BadValueTy { .. }) => {
820
                // Tried to inject back the value returned by a host function, but it doesn't
821
                // match what the Wasm code expects. Given that we check the host function
822
                // signatures at initialization, this indicates a bug in this implementation.
823
0
                unreachable!()
824
            }
825
826
            Err(vm::RunErr::Poisoned) => {
827
                // Can only happen if there's a bug somewhere.
828
0
                unreachable!()
829
            }
830
        };
831
832
        // The Wasm code has called an host_fn. The `id` is a value that we passed
833
        // at initialization, and corresponds to an index in `registered_functions`.
834
5.07k
        let host_fn = match self.inner.common.registered_functions.get(id) {
835
5.07k
            Some(FunctionImport::Resolved(f)) => *f,
836
0
            Some(FunctionImport::Unresolved { name, module }) => {
837
0
                return HostVm::Error {
838
0
                    error: Error::UnresolvedFunctionCalled {
839
0
                        function: name.clone(),
840
0
                        module_name: module.clone(),
841
0
                    },
842
0
                    prototype: self.inner.into_prototype(),
843
0
                };
844
            }
845
0
            None => unreachable!(),
846
        };
847
848
        // Passed a parameter index. Produces an `impl AsRef<[u8]>`.
849
        macro_rules! expect_pointer_size {
850
            ($num:expr) => {{
851
                let val = match &params[$num] {
852
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
853
                    // The signatures are checked at initialization and the Wasm VM ensures that
854
                    // the proper parameter types are provided.
855
                    _ => unreachable!(),
856
                };
857
858
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
859
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
860
861
                let result = self.inner.vm.read_memory(ptr, len);
862
                match result {
863
                    Ok(v) => v,
864
                    Err(vm::OutOfBoundsError) => {
865
                        drop(result);
866
                        return HostVm::Error {
867
                            error: Error::ParamOutOfRange {
868
                                function: host_fn.name(),
869
                                param_num: $num,
870
                                pointer: ptr,
871
                                length: len,
872
                            },
873
                            prototype: self.inner.into_prototype(),
874
                        };
875
                    }
876
                }
877
            }};
878
        }
879
880
        macro_rules! expect_pointer_size_raw {
881
            ($num:expr) => {{
882
                let val = match &params[$num] {
883
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
884
                    // The signatures are checked at initialization and the Wasm VM ensures that
885
                    // the proper parameter types are provided.
886
                    _ => unreachable!(),
887
                };
888
889
                let len = u32::try_from(val >> 32).unwrap_or_else(|_| unreachable!());
890
                let ptr = u32::try_from(val & 0xffffffff).unwrap_or_else(|_| unreachable!());
891
892
                if len.saturating_add(ptr) > u32::from(self.inner.vm.memory_size()) * 64 * 1024 {
893
                    return HostVm::Error {
894
                        error: Error::ParamOutOfRange {
895
                            function: host_fn.name(),
896
                            param_num: $num,
897
                            pointer: ptr,
898
                            length: len,
899
                        },
900
                        prototype: self.inner.into_prototype(),
901
                    };
902
                }
903
904
                (ptr, len)
905
            }};
906
        }
907
908
        macro_rules! expect_pointer_constant_size {
909
            ($num:expr, $size:expr) => {{
910
                let ptr = match params[$num] {
911
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
912
                    // The signatures are checked at initialization and the Wasm VM ensures that
913
                    // the proper parameter types are provided.
914
                    _ => unreachable!(),
915
                };
916
917
                let result = self.inner.vm.read_memory(ptr, $size);
918
                match result {
919
                    Ok(v) => {
920
                        *<&[u8; $size]>::try_from(v.as_ref()).unwrap_or_else(|_| unreachable!())
921
                    }
922
                    Err(vm::OutOfBoundsError) => {
923
                        drop(result);
924
                        return HostVm::Error {
925
                            error: Error::ParamOutOfRange {
926
                                function: host_fn.name(),
927
                                param_num: $num,
928
                                pointer: ptr,
929
                                length: $size,
930
                            },
931
                            prototype: self.inner.into_prototype(),
932
                        };
933
                    }
934
                }
935
            }};
936
        }
937
938
        macro_rules! expect_pointer_constant_size_raw {
939
            ($num:expr, $size:expr) => {{
940
                let ptr = match params[$num] {
941
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
942
                    // The signatures are checked at initialization and the Wasm VM ensures that
943
                    // the proper parameter types are provided.
944
                    _ => unreachable!(),
945
                };
946
947
                if u32::saturating_add($size, ptr)
948
                    > u32::from(self.inner.vm.memory_size()) * 64 * 1024
949
                {
950
                    return HostVm::Error {
951
                        error: Error::ParamOutOfRange {
952
                            function: host_fn.name(),
953
                            param_num: $num,
954
                            pointer: ptr,
955
                            length: $size,
956
                        },
957
                        prototype: self.inner.into_prototype(),
958
                    };
959
                }
960
961
                ptr
962
            }};
963
        }
964
965
        macro_rules! expect_u32 {
966
            ($num:expr) => {{
967
                match &params[$num] {
968
                    vm::WasmValue::I32(v) => u32::from_ne_bytes(v.to_ne_bytes()),
969
                    // The signatures are checked at initialization and the Wasm VM ensures that
970
                    // the proper parameter types are provided.
971
                    _ => unreachable!(),
972
                }
973
            }};
974
        }
975
976
        macro_rules! expect_offchain_storage_kind {
977
            ($num:expr) => {{
978
                match &params[$num] {
979
                    // `0` indicates `StorageKind::PERSISTENT`, the only kind of offchain
980
                    // storage that is available.
981
                    vm::WasmValue::I32(0) => true,
982
                    // `1` indicates `StorageKind::LOCAL`, which is valid but has never been
983
                    // implemented in Substrate.
984
                    vm::WasmValue::I32(1) => false,
985
                    vm::WasmValue::I32(_) => {
986
                        return HostVm::Error {
987
                            error: Error::ParamDecodeError,
988
                            prototype: self.inner.into_prototype(),
989
                        };
990
                    }
991
                    // The signatures are checked at initialization and the Wasm VM ensures that
992
                    // the proper parameter types are provided.
993
                    _ => unreachable!(),
994
                }
995
            }};
996
        }
997
998
        macro_rules! expect_state_version {
999
            ($num:expr) => {{
1000
                match &params[$num] {
1001
                    vm::WasmValue::I32(0) => TrieEntryVersion::V0,
1002
                    vm::WasmValue::I32(1) => TrieEntryVersion::V1,
1003
                    vm::WasmValue::I32(_) => {
1004
                        return HostVm::Error {
1005
                            error: Error::ParamDecodeError,
1006
                            prototype: self.inner.into_prototype(),
1007
                        };
1008
                    }
1009
                    // The signatures are checked at initialization and the Wasm VM ensures that
1010
                    // the proper parameter types are provided.
1011
                    _ => unreachable!(),
1012
                }
1013
            }};
1014
        }
1015
1016
        // TODO: implement all functions and remove this macro
1017
        macro_rules! host_fn_not_implemented {
1018
            () => {{
1019
                return HostVm::Error {
1020
                    error: Error::HostFunctionNotImplemented {
1021
                        function: host_fn.name(),
1022
                    },
1023
                    prototype: self.inner.into_prototype(),
1024
                };
1025
            }};
1026
        }
1027
1028
        // Handle the function calls.
1029
        // Some of these enum variants simply change the state of `self`, while most of them
1030
        // instead return an `ExternalVm` to the user.
1031
5.07k
        match host_fn {
1032
            HostFunction::ext_storage_set_version_1 => {
1033
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1034
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1035
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1036
0
                    key_ptr,
1037
0
                    key_size,
1038
0
                    child_trie_ptr_size: None,
1039
0
                    value: Some((value_ptr, value_size)),
1040
0
                    inner: self.inner,
1041
0
                })
1042
            }
1043
            HostFunction::ext_storage_get_version_1 => {
1044
84
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1045
84
                HostVm::ExternalStorageGet(ExternalStorageGet {
1046
84
                    key_ptr,
1047
84
                    key_size,
1048
84
                    child_trie_ptr_size: None,
1049
84
                    calling: id,
1050
84
                    value_out_ptr: None,
1051
84
                    offset: 0,
1052
84
                    max_size: u32::MAX,
1053
84
                    inner: self.inner,
1054
84
                })
1055
            }
1056
            HostFunction::ext_storage_read_version_1 => {
1057
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1058
0
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(1);
1059
0
                let offset = expect_u32!(2);
1060
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1061
0
                    key_ptr,
1062
0
                    key_size,
1063
0
                    child_trie_ptr_size: None,
1064
0
                    calling: id,
1065
0
                    value_out_ptr: Some(value_out_ptr),
1066
0
                    offset,
1067
0
                    max_size: value_out_size,
1068
0
                    inner: self.inner,
1069
0
                })
1070
            }
1071
            HostFunction::ext_storage_clear_version_1 => {
1072
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1073
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1074
0
                    key_ptr,
1075
0
                    key_size,
1076
0
                    child_trie_ptr_size: None,
1077
0
                    value: None,
1078
0
                    inner: self.inner,
1079
0
                })
1080
            }
1081
            HostFunction::ext_storage_exists_version_1 => {
1082
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1083
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1084
0
                    key_ptr,
1085
0
                    key_size,
1086
0
                    child_trie_ptr_size: None,
1087
0
                    calling: id,
1088
0
                    value_out_ptr: None,
1089
0
                    offset: 0,
1090
0
                    max_size: 0,
1091
0
                    inner: self.inner,
1092
0
                })
1093
            }
1094
            HostFunction::ext_storage_clear_prefix_version_1 => {
1095
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1096
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1097
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1098
0
                    child_trie_ptr_size: None,
1099
0
                    inner: self.inner,
1100
0
                    max_keys_to_remove: None,
1101
0
                    calling: id,
1102
0
                })
1103
            }
1104
            HostFunction::ext_storage_clear_prefix_version_2 => {
1105
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(0);
1106
1107
0
                let max_keys_to_remove = {
1108
0
                    let input = expect_pointer_size!(1);
1109
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1110
0
                        nom::Parser::parse(
1111
0
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1112
0
                                nom::number::streaming::le_u32,
1113
0
                            )),
1114
0
                            input.as_ref(),
1115
0
                        )
1116
0
                        .map(|(_, parse_result)| parse_result);
1117
0
1118
0
                    match parsing_result {
1119
0
                        Ok(val) => Ok(val),
1120
0
                        Err(_) => Err(()),
1121
                    }
1122
                };
1123
1124
0
                let max_keys_to_remove = match max_keys_to_remove {
1125
0
                    Ok(l) => l,
1126
                    Err(()) => {
1127
0
                        return HostVm::Error {
1128
0
                            error: Error::ParamDecodeError,
1129
0
                            prototype: self.inner.into_prototype(),
1130
0
                        };
1131
                    }
1132
                };
1133
1134
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1135
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1136
0
                    child_trie_ptr_size: None,
1137
0
                    inner: self.inner,
1138
0
                    max_keys_to_remove,
1139
0
                    calling: id,
1140
0
                })
1141
            }
1142
            HostFunction::ext_storage_root_version_1 => {
1143
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1144
0
                    inner: self.inner,
1145
0
                    calling: id,
1146
0
                    child_trie_ptr_size: None,
1147
0
                })
1148
            }
1149
            HostFunction::ext_storage_root_version_2 => {
1150
                // The `ext_storage_root_version_2` host function gets passed as parameter the
1151
                // state version of the runtime. This is in fact completely unnecessary as the
1152
                // same information is found in the runtime specification, and this parameter
1153
                // should be considered as a historical accident. We verify that the version
1154
                // provided as parameter is the same as the one in the specification.
1155
0
                let version_param = expect_state_version!(0);
1156
0
                let version_spec = self
1157
0
                    .inner
1158
0
                    .common
1159
0
                    .runtime_version
1160
0
                    .as_ref()
1161
0
                    .unwrap_or_else(|| unreachable!())
1162
0
                    .decode()
1163
0
                    .state_version
1164
0
                    .unwrap_or(TrieEntryVersion::V0);
1165
0
1166
0
                if version_param != version_spec {
1167
0
                    return HostVm::Error {
1168
0
                        error: Error::StateVersionMismatch {
1169
0
                            parameter: version_param,
1170
0
                            specification: version_spec,
1171
0
                        },
1172
0
                        prototype: self.inner.into_prototype(),
1173
0
                    };
1174
0
                }
1175
0
1176
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1177
0
                    inner: self.inner,
1178
0
                    calling: id,
1179
0
                    child_trie_ptr_size: None,
1180
0
                })
1181
            }
1182
            HostFunction::ext_storage_changes_root_version_1 => {
1183
                // The changes trie is an obsolete attempt at having a second trie containing, for
1184
                // each storage item, the latest block height where this item has been modified.
1185
                // When this function returns `None`, it indicates that the changes trie is
1186
                // disabled. While this function used to be called by the runtimes of
1187
                // Westend/Polkadot/Kusama (and maybe others), it has never returned anything else
1188
                // but `None`. The entire changes trie mechanism was ultimately removed in
1189
                // October 2021.
1190
                // This function is no longer called by recent runtimes, but must be preserved for
1191
                // backwards compatibility.
1192
0
                self.inner.alloc_write_and_return_pointer_size(
1193
0
                    HostFunction::ext_storage_changes_root_version_1.name(),
1194
0
                    iter::once(&[0][..]),
1195
0
                )
1196
            }
1197
            HostFunction::ext_storage_next_key_version_1 => {
1198
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1199
0
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1200
0
                    key_ptr,
1201
0
                    key_size,
1202
0
                    child_trie_ptr_size: None,
1203
0
                    inner: self.inner,
1204
0
                })
1205
            }
1206
            HostFunction::ext_storage_append_version_1 => {
1207
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1208
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1209
0
                HostVm::ExternalStorageAppend(ExternalStorageAppend {
1210
0
                    key_ptr,
1211
0
                    key_size,
1212
0
                    value_ptr,
1213
0
                    value_size,
1214
0
                    inner: self.inner,
1215
0
                })
1216
            }
1217
            HostFunction::ext_storage_start_transaction_version_1 => {
1218
                // TODO: a maximum depth is important in order to prevent a malicious runtime from crashing the client, but the depth needs to be the same as in Substrate; figure out
1219
0
                self.inner.storage_transaction_depth += 1;
1220
0
                HostVm::StartStorageTransaction(StartStorageTransaction { inner: self.inner })
1221
            }
1222
            HostFunction::ext_storage_rollback_transaction_version_1 => {
1223
0
                if self.inner.storage_transaction_depth == 0 {
1224
0
                    return HostVm::Error {
1225
0
                        error: Error::NoActiveTransaction,
1226
0
                        prototype: self.inner.into_prototype(),
1227
0
                    };
1228
0
                }
1229
0
1230
0
                self.inner.storage_transaction_depth -= 1;
1231
0
                HostVm::EndStorageTransaction {
1232
0
                    resume: EndStorageTransaction { inner: self.inner },
1233
0
                    rollback: true,
1234
0
                }
1235
            }
1236
            HostFunction::ext_storage_commit_transaction_version_1 => {
1237
0
                if self.inner.storage_transaction_depth == 0 {
1238
0
                    return HostVm::Error {
1239
0
                        error: Error::NoActiveTransaction,
1240
0
                        prototype: self.inner.into_prototype(),
1241
0
                    };
1242
0
                }
1243
0
1244
0
                self.inner.storage_transaction_depth -= 1;
1245
0
                HostVm::EndStorageTransaction {
1246
0
                    resume: EndStorageTransaction { inner: self.inner },
1247
0
                    rollback: false,
1248
0
                }
1249
            }
1250
            HostFunction::ext_storage_proof_size_storage_proof_size_version_1 => {
1251
0
                match self.inner.storage_proof_size_behavior {
1252
0
                    StorageProofSizeBehavior::ConstantReturnValue(value) => {
1253
0
                        HostVm::ReadyToRun(ReadyToRun {
1254
0
                            inner: self.inner,
1255
0
                            resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(
1256
0
                                value.to_ne_bytes(),
1257
0
                            ))),
1258
0
                        })
1259
                    }
1260
0
                    StorageProofSizeBehavior::Unimplemented => HostVm::Error {
1261
0
                        error: Error::HostFunctionNotImplemented {
1262
0
                            function: host_fn.name(),
1263
0
                        },
1264
0
                        prototype: self.inner.into_prototype(),
1265
0
                    },
1266
                }
1267
            }
1268
            HostFunction::ext_default_child_storage_get_version_1 => {
1269
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1270
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1271
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1272
0
                    key_ptr,
1273
0
                    key_size,
1274
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1275
0
                    calling: id,
1276
0
                    value_out_ptr: None,
1277
0
                    offset: 0,
1278
0
                    max_size: u32::MAX,
1279
0
                    inner: self.inner,
1280
0
                })
1281
            }
1282
            HostFunction::ext_default_child_storage_read_version_1 => {
1283
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1284
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1285
0
                let (value_out_ptr, value_out_size) = expect_pointer_size_raw!(2);
1286
0
                let offset = expect_u32!(3);
1287
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1288
0
                    key_ptr,
1289
0
                    key_size,
1290
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1291
0
                    calling: id,
1292
0
                    value_out_ptr: Some(value_out_ptr),
1293
0
                    offset,
1294
0
                    max_size: value_out_size,
1295
0
                    inner: self.inner,
1296
0
                })
1297
            }
1298
            HostFunction::ext_default_child_storage_storage_kill_version_1 => {
1299
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1300
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1301
0
                    prefix_ptr_size: None,
1302
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1303
0
                    inner: self.inner,
1304
0
                    max_keys_to_remove: None,
1305
0
                    calling: id,
1306
0
                })
1307
            }
1308
            HostFunction::ext_default_child_storage_storage_kill_version_2
1309
            | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
1310
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1311
1312
0
                let max_keys_to_remove = {
1313
0
                    let input = expect_pointer_size!(1);
1314
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1315
0
                        nom::Parser::parse(
1316
0
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1317
0
                                nom::number::streaming::le_u32,
1318
0
                            )),
1319
0
                            input.as_ref(),
1320
0
                        )
1321
0
                        .map(|(_, parse_result)| parse_result);
1322
0
1323
0
                    match parsing_result {
1324
0
                        Ok(val) => Ok(val),
1325
0
                        Err(_) => Err(()),
1326
                    }
1327
                };
1328
1329
0
                let max_keys_to_remove = match max_keys_to_remove {
1330
0
                    Ok(l) => l,
1331
                    Err(()) => {
1332
0
                        return HostVm::Error {
1333
0
                            error: Error::ParamDecodeError,
1334
0
                            prototype: self.inner.into_prototype(),
1335
0
                        };
1336
                    }
1337
                };
1338
1339
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1340
0
                    prefix_ptr_size: None,
1341
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1342
0
                    inner: self.inner,
1343
0
                    max_keys_to_remove,
1344
0
                    calling: id,
1345
0
                })
1346
            }
1347
            HostFunction::ext_default_child_storage_clear_prefix_version_1 => {
1348
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1349
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1350
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1351
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1352
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1353
0
                    inner: self.inner,
1354
0
                    max_keys_to_remove: None,
1355
0
                    calling: id,
1356
0
                })
1357
            }
1358
            HostFunction::ext_default_child_storage_clear_prefix_version_2 => {
1359
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1360
0
                let (prefix_ptr, prefix_size) = expect_pointer_size_raw!(1);
1361
1362
0
                let max_keys_to_remove = {
1363
0
                    let input = expect_pointer_size!(2);
1364
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1365
0
                        nom::Parser::parse(
1366
0
                            &mut nom::combinator::all_consuming(util::nom_option_decode(
1367
0
                                nom::number::streaming::le_u32,
1368
0
                            )),
1369
0
                            input.as_ref(),
1370
0
                        )
1371
0
                        .map(|(_, parse_result)| parse_result);
1372
0
1373
0
                    match parsing_result {
1374
0
                        Ok(val) => Ok(val),
1375
0
                        Err(_) => Err(()),
1376
                    }
1377
                };
1378
1379
0
                let max_keys_to_remove = match max_keys_to_remove {
1380
0
                    Ok(l) => l,
1381
                    Err(()) => {
1382
0
                        return HostVm::Error {
1383
0
                            error: Error::ParamDecodeError,
1384
0
                            prototype: self.inner.into_prototype(),
1385
0
                        };
1386
                    }
1387
                };
1388
1389
0
                HostVm::ExternalStorageClearPrefix(ExternalStorageClearPrefix {
1390
0
                    prefix_ptr_size: Some((prefix_ptr, prefix_size)),
1391
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1392
0
                    inner: self.inner,
1393
0
                    max_keys_to_remove,
1394
0
                    calling: id,
1395
0
                })
1396
            }
1397
            HostFunction::ext_default_child_storage_set_version_1 => {
1398
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1399
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1400
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1401
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1402
0
                    key_ptr,
1403
0
                    key_size,
1404
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1405
0
                    value: Some((value_ptr, value_size)),
1406
0
                    inner: self.inner,
1407
0
                })
1408
            }
1409
            HostFunction::ext_default_child_storage_clear_version_1 => {
1410
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1411
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1412
0
                HostVm::ExternalStorageSet(ExternalStorageSet {
1413
0
                    key_ptr,
1414
0
                    key_size,
1415
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1416
0
                    value: None,
1417
0
                    inner: self.inner,
1418
0
                })
1419
            }
1420
            HostFunction::ext_default_child_storage_exists_version_1 => {
1421
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1422
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1423
0
                HostVm::ExternalStorageGet(ExternalStorageGet {
1424
0
                    key_ptr,
1425
0
                    key_size,
1426
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1427
0
                    calling: id,
1428
0
                    value_out_ptr: None,
1429
0
                    offset: 0,
1430
0
                    max_size: 0,
1431
0
                    inner: self.inner,
1432
0
                })
1433
            }
1434
            HostFunction::ext_default_child_storage_next_key_version_1 => {
1435
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1436
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1437
0
                HostVm::ExternalStorageNextKey(ExternalStorageNextKey {
1438
0
                    key_ptr,
1439
0
                    key_size,
1440
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1441
0
                    inner: self.inner,
1442
0
                })
1443
            }
1444
            HostFunction::ext_default_child_storage_root_version_1 => {
1445
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1446
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1447
0
                    inner: self.inner,
1448
0
                    calling: id,
1449
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1450
0
                })
1451
            }
1452
            HostFunction::ext_default_child_storage_root_version_2 => {
1453
0
                let (child_trie_ptr, child_trie_size) = expect_pointer_size_raw!(0);
1454
1455
                // The `ext_default_child_storage_root_version_2` host function gets passed as
1456
                // parameter the state version of the runtime. This is in fact completely
1457
                // unnecessary as the same information is found in the runtime specification, and
1458
                // this parameter should be considered as a historical accident. We verify that the
1459
                // version provided as parameter is the same as the one in the specification.
1460
0
                let version_param = expect_state_version!(1);
1461
0
                let version_spec = self
1462
0
                    .inner
1463
0
                    .common
1464
0
                    .runtime_version
1465
0
                    .as_ref()
1466
0
                    .unwrap_or_else(|| unreachable!())
1467
0
                    .decode()
1468
0
                    .state_version
1469
0
                    .unwrap_or(TrieEntryVersion::V0);
1470
0
1471
0
                if version_param != version_spec {
1472
0
                    return HostVm::Error {
1473
0
                        error: Error::StateVersionMismatch {
1474
0
                            parameter: version_param,
1475
0
                            specification: version_spec,
1476
0
                        },
1477
0
                        prototype: self.inner.into_prototype(),
1478
0
                    };
1479
0
                }
1480
0
1481
0
                HostVm::ExternalStorageRoot(ExternalStorageRoot {
1482
0
                    inner: self.inner,
1483
0
                    calling: id,
1484
0
                    child_trie_ptr_size: Some((child_trie_ptr, child_trie_size)),
1485
0
                })
1486
            }
1487
0
            HostFunction::ext_crypto_ed25519_public_keys_version_1 => host_fn_not_implemented!(),
1488
0
            HostFunction::ext_crypto_ed25519_generate_version_1 => host_fn_not_implemented!(),
1489
0
            HostFunction::ext_crypto_ed25519_sign_version_1 => host_fn_not_implemented!(),
1490
            HostFunction::ext_crypto_ed25519_verify_version_1
1491
            | HostFunction::ext_crypto_ed25519_batch_verify_version_1 => {
1492
0
                let is_batch_verification = matches!(
1493
0
                    host_fn,
1494
                    HostFunction::ext_crypto_ed25519_batch_verify_version_1
1495
                );
1496
1497
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1498
0
                    return HostVm::Error {
1499
0
                        error: Error::BatchVerifyWithoutStarting,
1500
0
                        prototype: self.inner.into_prototype(),
1501
0
                    };
1502
0
                }
1503
1504
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1505
                HostVm::SignatureVerification(SignatureVerification {
1506
0
                    algorithm: SignatureVerificationAlgorithm::Ed25519,
1507
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1508
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1509
0
                    message_ptr,
1510
0
                    message_size,
1511
0
                    inner: self.inner,
1512
0
                    is_batch_verification,
1513
                })
1514
            }
1515
0
            HostFunction::ext_crypto_sr25519_public_keys_version_1 => host_fn_not_implemented!(),
1516
0
            HostFunction::ext_crypto_sr25519_generate_version_1 => host_fn_not_implemented!(),
1517
0
            HostFunction::ext_crypto_sr25519_sign_version_1 => host_fn_not_implemented!(),
1518
            HostFunction::ext_crypto_sr25519_verify_version_1
1519
            | HostFunction::ext_crypto_sr25519_batch_verify_version_1 => {
1520
0
                let is_batch_verification = matches!(
1521
0
                    host_fn,
1522
                    HostFunction::ext_crypto_sr25519_batch_verify_version_1
1523
                );
1524
1525
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1526
0
                    return HostVm::Error {
1527
0
                        error: Error::BatchVerifyWithoutStarting,
1528
0
                        prototype: self.inner.into_prototype(),
1529
0
                    };
1530
0
                }
1531
1532
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1533
                HostVm::SignatureVerification(SignatureVerification {
1534
0
                    algorithm: SignatureVerificationAlgorithm::Sr25519V1,
1535
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1536
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1537
0
                    message_ptr,
1538
0
                    message_size,
1539
0
                    inner: self.inner,
1540
0
                    is_batch_verification,
1541
                })
1542
            }
1543
            HostFunction::ext_crypto_sr25519_verify_version_2 => {
1544
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1545
                HostVm::SignatureVerification(SignatureVerification {
1546
0
                    algorithm: SignatureVerificationAlgorithm::Sr25519V2,
1547
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 64),
1548
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 32),
1549
0
                    message_ptr,
1550
0
                    message_size,
1551
0
                    inner: self.inner,
1552
                    is_batch_verification: false,
1553
                })
1554
            }
1555
0
            HostFunction::ext_crypto_ecdsa_generate_version_1 => host_fn_not_implemented!(),
1556
            HostFunction::ext_crypto_ecdsa_sign_version_1 => {
1557
                // NOTE: safe to unwrap here because we supply the nn to blake2b fn
1558
0
                let data = <[u8; 32]>::try_from(
1559
0
                    blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
1560
0
                        .as_bytes(),
1561
0
                )
1562
0
                .unwrap_or_else(|_| unreachable!());
1563
0
                let message = libsecp256k1::Message::parse(&data);
1564
1565
0
                if let Ok(sc) =
1566
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1567
                {
1568
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1569
0
1570
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1571
0
                    self.inner.alloc_write_and_return_pointer(
1572
0
                        host_fn.name(),
1573
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1574
0
                    )
1575
                } else {
1576
0
                    HostVm::Error {
1577
0
                        error: Error::ParamDecodeError,
1578
0
                        prototype: self.inner.into_prototype(),
1579
0
                    }
1580
                }
1581
            }
1582
0
            HostFunction::ext_crypto_ecdsa_public_keys_version_1 => host_fn_not_implemented!(),
1583
            HostFunction::ext_crypto_ecdsa_verify_version_1
1584
            | HostFunction::ext_crypto_ecdsa_batch_verify_version_1 => {
1585
0
                let is_batch_verification = matches!(
1586
0
                    host_fn,
1587
                    HostFunction::ext_crypto_ecdsa_batch_verify_version_1
1588
                );
1589
1590
0
                if is_batch_verification && self.inner.signatures_batch_verification.is_none() {
1591
0
                    return HostVm::Error {
1592
0
                        error: Error::BatchVerifyWithoutStarting,
1593
0
                        prototype: self.inner.into_prototype(),
1594
0
                    };
1595
0
                }
1596
1597
0
                let (message_ptr, message_size) = expect_pointer_size_raw!(1);
1598
                HostVm::SignatureVerification(SignatureVerification {
1599
0
                    algorithm: SignatureVerificationAlgorithm::Ecdsa,
1600
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1601
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1602
0
                    message_ptr,
1603
0
                    message_size,
1604
0
                    inner: self.inner,
1605
0
                    is_batch_verification,
1606
                })
1607
            }
1608
0
            HostFunction::ext_crypto_ecdsa_verify_version_2 => host_fn_not_implemented!(),
1609
            HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => {
1610
                // TODO: seems misimplemented, see https://spec.polkadot.network/#id-ext_crypto_ecdsa_sign_prehashed
1611
0
                let message = libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));
1612
1613
0
                if let Ok(sc) =
1614
0
                    libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
1615
                {
1616
0
                    let (sig, ri) = libsecp256k1::sign(&message, &sc);
1617
0
1618
0
                    // NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
1619
0
                    self.inner.alloc_write_and_return_pointer(
1620
0
                        host_fn.name(),
1621
0
                        [&sig.serialize()[..], &[ri.serialize()]].into_iter(),
1622
0
                    )
1623
                } else {
1624
0
                    HostVm::Error {
1625
0
                        error: Error::ParamDecodeError,
1626
0
                        prototype: self.inner.into_prototype(),
1627
0
                    }
1628
                }
1629
            }
1630
            HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => {
1631
                HostVm::SignatureVerification(SignatureVerification {
1632
0
                    algorithm: SignatureVerificationAlgorithm::EcdsaPrehashed,
1633
0
                    signature_ptr: expect_pointer_constant_size_raw!(0, 65),
1634
0
                    public_key_ptr: expect_pointer_constant_size_raw!(2, 33),
1635
0
                    message_ptr: expect_pointer_constant_size_raw!(1, 32),
1636
                    message_size: 32,
1637
0
                    inner: self.inner,
1638
                    is_batch_verification: false,
1639
                })
1640
            }
1641
1642
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1
1643
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => {
1644
0
                let sig = expect_pointer_constant_size!(0, 65);
1645
0
                let msg = expect_pointer_constant_size!(1, 32);
1646
0
                let is_v2 = matches!(
1647
0
                    host_fn,
1648
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2
1649
                );
1650
1651
0
                let result = {
1652
0
                    let rs = if is_v2 {
1653
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1654
                    } else {
1655
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1656
                    };
1657
1658
0
                    if let Ok(rs) = rs {
1659
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1660
0
                            sig[64] - 27
1661
                        } else {
1662
0
                            sig[64]
1663
                        });
1664
1665
0
                        if let Ok(v) = v {
1666
0
                            let pubkey = libsecp256k1::recover(
1667
0
                                &libsecp256k1::Message::parse_slice(&msg)
1668
0
                                    .unwrap_or_else(|_| unreachable!()),
1669
0
                                &rs,
1670
0
                                &v,
1671
0
                            );
1672
1673
0
                            if let Ok(pubkey) = pubkey {
1674
0
                                let mut res = Vec::with_capacity(65);
1675
0
                                res.push(0);
1676
0
                                res.extend_from_slice(&pubkey.serialize()[1..65]);
1677
0
                                res
1678
                            } else {
1679
0
                                vec![1, 2]
1680
                            }
1681
                        } else {
1682
0
                            vec![1, 1]
1683
                        }
1684
                    } else {
1685
0
                        vec![1, 0]
1686
                    }
1687
                };
1688
1689
0
                self.inner
1690
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1691
            }
1692
            HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_1
1693
            | HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2 => {
1694
0
                let sig = expect_pointer_constant_size!(0, 65);
1695
0
                let msg = expect_pointer_constant_size!(1, 32);
1696
0
                let is_v2 = matches!(
1697
0
                    host_fn,
1698
                    HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_2
1699
                );
1700
1701
0
                let result = {
1702
0
                    let rs = if is_v2 {
1703
0
                        libsecp256k1::Signature::parse_standard_slice(&sig[0..64])
1704
                    } else {
1705
0
                        libsecp256k1::Signature::parse_overflowing_slice(&sig[0..64])
1706
                    };
1707
1708
0
                    if let Ok(rs) = rs {
1709
0
                        let v = libsecp256k1::RecoveryId::parse(if sig[64] > 26 {
1710
0
                            sig[64] - 27
1711
                        } else {
1712
0
                            sig[64]
1713
                        });
1714
1715
0
                        if let Ok(v) = v {
1716
0
                            let pubkey = libsecp256k1::recover(
1717
0
                                &libsecp256k1::Message::parse_slice(&msg)
1718
0
                                    .unwrap_or_else(|_| unreachable!()),
1719
0
                                &rs,
1720
0
                                &v,
1721
0
                            );
1722
1723
0
                            if let Ok(pubkey) = pubkey {
1724
0
                                let mut res = Vec::with_capacity(34);
1725
0
                                res.push(0);
1726
0
                                res.extend_from_slice(&pubkey.serialize_compressed());
1727
0
                                res
1728
                            } else {
1729
0
                                vec![1, 2]
1730
                            }
1731
                        } else {
1732
0
                            vec![1, 1]
1733
                        }
1734
                    } else {
1735
0
                        vec![1, 0]
1736
                    }
1737
                };
1738
1739
0
                self.inner
1740
0
                    .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&result))
1741
            }
1742
            HostFunction::ext_crypto_start_batch_verify_version_1 => {
1743
0
                if self.inner.signatures_batch_verification.is_some() {
1744
0
                    return HostVm::Error {
1745
0
                        error: Error::AlreadyBatchVerify,
1746
0
                        prototype: self.inner.into_prototype(),
1747
0
                    };
1748
0
                }
1749
0
1750
0
                self.inner.signatures_batch_verification = Some(true);
1751
0
1752
0
                HostVm::ReadyToRun(ReadyToRun {
1753
0
                    resume_value: None,
1754
0
                    inner: self.inner,
1755
0
                })
1756
            }
1757
            HostFunction::ext_crypto_finish_batch_verify_version_1 => {
1758
0
                let Some(outcome) = self.inner.signatures_batch_verification.take() else {
1759
0
                    return HostVm::Error {
1760
0
                        error: Error::NoBatchVerify,
1761
0
                        prototype: self.inner.into_prototype(),
1762
0
                    };
1763
                };
1764
1765
                HostVm::ReadyToRun(ReadyToRun {
1766
0
                    resume_value: Some(vm::WasmValue::I32(if outcome { 1 } else { 0 })),
1767
0
                    inner: self.inner,
1768
                })
1769
            }
1770
            HostFunction::ext_hashing_keccak_256_version_1 => {
1771
0
                let hash =
1772
0
                    <sha3::Keccak256 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1773
0
                self.inner
1774
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1775
            }
1776
            HostFunction::ext_hashing_keccak_512_version_1 => {
1777
0
                let hash =
1778
0
                    <sha3::Keccak512 as sha3::Digest>::digest(expect_pointer_size!(0).as_ref());
1779
0
                self.inner
1780
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1781
            }
1782
            HostFunction::ext_hashing_sha2_256_version_1 => {
1783
0
                let hash = <sha2::Sha256 as sha2::Digest>::digest(expect_pointer_size!(0).as_ref());
1784
0
                self.inner
1785
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&hash))
1786
            }
1787
            HostFunction::ext_hashing_blake2_128_version_1 => {
1788
0
                let out = {
1789
0
                    let data = expect_pointer_size!(0);
1790
0
                    blake2_rfc::blake2b::blake2b(16, &[], data.as_ref())
1791
0
                };
1792
0
1793
0
                self.inner
1794
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1795
            }
1796
            HostFunction::ext_hashing_blake2_256_version_1 => {
1797
0
                let out = {
1798
0
                    let data = expect_pointer_size!(0);
1799
0
                    blake2_rfc::blake2b::blake2b(32, &[], data.as_ref())
1800
0
                };
1801
0
1802
0
                self.inner
1803
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(out.as_bytes()))
1804
            }
1805
            HostFunction::ext_hashing_twox_64_version_1 => {
1806
0
                let r0 = {
1807
0
                    let data = expect_pointer_size!(0);
1808
0
                    twox_hash::XxHash64::oneshot(0, data.as_ref())
1809
0
                };
1810
0
1811
0
                self.inner
1812
0
                    .alloc_write_and_return_pointer(host_fn.name(), iter::once(&r0.to_le_bytes()))
1813
            }
1814
            HostFunction::ext_hashing_twox_128_version_1 => {
1815
84
                let [r0, r1] = {
1816
84
                    let data = expect_pointer_size!(0);
1817
84
                    let data = data.as_ref();
1818
84
                    [
1819
84
                        twox_hash::XxHash64::oneshot(0, data),
1820
84
                        twox_hash::XxHash64::oneshot(1, data),
1821
84
                    ]
1822
84
                };
1823
84
1824
84
                self.inner.alloc_write_and_return_pointer(
1825
84
                    host_fn.name(),
1826
84
                    iter::once(&r0.to_le_bytes()).chain(iter::once(&r1.to_le_bytes())),
1827
84
                )
1828
            }
1829
            HostFunction::ext_hashing_twox_256_version_1 => {
1830
0
                let [r0, r1, r2, r3] = {
1831
0
                    let data = expect_pointer_size!(0);
1832
0
                    let data = data.as_ref();
1833
0
                    [
1834
0
                        twox_hash::XxHash64::oneshot(0, data),
1835
0
                        twox_hash::XxHash64::oneshot(1, data),
1836
0
                        twox_hash::XxHash64::oneshot(2, data),
1837
0
                        twox_hash::XxHash64::oneshot(3, data),
1838
0
                    ]
1839
0
                };
1840
0
1841
0
                self.inner.alloc_write_and_return_pointer(
1842
0
                    host_fn.name(),
1843
0
                    iter::once(&r0.to_le_bytes())
1844
0
                        .chain(iter::once(&r1.to_le_bytes()))
1845
0
                        .chain(iter::once(&r2.to_le_bytes()))
1846
0
                        .chain(iter::once(&r3.to_le_bytes())),
1847
0
                )
1848
            }
1849
            HostFunction::ext_offchain_index_set_version_1 => {
1850
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1851
0
                let (value_ptr, value_size) = expect_pointer_size_raw!(1);
1852
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1853
0
                    key_ptr,
1854
0
                    key_size,
1855
0
                    value: Some((value_ptr, value_size)),
1856
0
                    inner: self.inner,
1857
0
                })
1858
            }
1859
            HostFunction::ext_offchain_index_clear_version_1 => {
1860
0
                let (key_ptr, key_size) = expect_pointer_size_raw!(0);
1861
0
                HostVm::ExternalOffchainIndexSet(ExternalOffchainIndexSet {
1862
0
                    key_ptr,
1863
0
                    key_size,
1864
0
                    value: None,
1865
0
                    inner: self.inner,
1866
0
                })
1867
            }
1868
0
            HostFunction::ext_offchain_is_validator_version_1 => HostVm::ReadyToRun(ReadyToRun {
1869
0
                inner: self.inner,
1870
0
                resume_value: Some(vm::WasmValue::I32(1)), // TODO: ask the API user
1871
0
            }),
1872
            HostFunction::ext_offchain_submit_transaction_version_1 => {
1873
0
                let (tx_ptr, tx_size) = expect_pointer_size_raw!(0);
1874
0
                HostVm::OffchainSubmitTransaction(OffchainSubmitTransaction {
1875
0
                    inner: self.inner,
1876
0
                    calling: id,
1877
0
                    tx_ptr,
1878
0
                    tx_size,
1879
0
                })
1880
            }
1881
            HostFunction::ext_offchain_network_state_version_1 => {
1882
0
                host_fn_not_implemented!()
1883
            }
1884
            HostFunction::ext_offchain_timestamp_version_1 => {
1885
0
                HostVm::OffchainTimestamp(OffchainTimestamp { inner: self.inner })
1886
            }
1887
            HostFunction::ext_offchain_sleep_until_version_1 => {
1888
0
                host_fn_not_implemented!()
1889
            }
1890
            HostFunction::ext_offchain_random_seed_version_1 => {
1891
0
                HostVm::OffchainRandomSeed(OffchainRandomSeed {
1892
0
                    inner: self.inner,
1893
0
                    calling: id,
1894
0
                })
1895
            }
1896
            HostFunction::ext_offchain_local_storage_set_version_1 => {
1897
0
                if expect_offchain_storage_kind!(0) {
1898
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1899
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(2);
1900
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1901
0
                        key_ptr,
1902
0
                        key_size,
1903
0
                        value: Some((value_ptr, value_size)),
1904
0
                        old_value: None,
1905
0
                        inner: self.inner,
1906
0
                    })
1907
                } else {
1908
0
                    HostVm::ReadyToRun(ReadyToRun {
1909
0
                        inner: self.inner,
1910
0
                        resume_value: None,
1911
0
                    })
1912
                }
1913
            }
1914
            HostFunction::ext_offchain_local_storage_compare_and_set_version_1 => {
1915
0
                if expect_offchain_storage_kind!(0) {
1916
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1917
0
                    let (old_value_ptr, old_value_size) = expect_pointer_size_raw!(2);
1918
0
                    let (value_ptr, value_size) = expect_pointer_size_raw!(3);
1919
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1920
0
                        key_ptr,
1921
0
                        key_size,
1922
0
                        value: Some((value_ptr, value_size)),
1923
0
                        old_value: Some((old_value_ptr, old_value_size)),
1924
0
                        inner: self.inner,
1925
0
                    })
1926
                } else {
1927
0
                    HostVm::ReadyToRun(ReadyToRun {
1928
0
                        inner: self.inner,
1929
0
                        resume_value: Some(vm::WasmValue::I32(0)),
1930
0
                    })
1931
                }
1932
            }
1933
            HostFunction::ext_offchain_local_storage_get_version_1 => {
1934
0
                if expect_offchain_storage_kind!(0) {
1935
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1936
0
                    HostVm::ExternalOffchainStorageGet(ExternalOffchainStorageGet {
1937
0
                        key_ptr,
1938
0
                        key_size,
1939
0
                        calling: id,
1940
0
                        inner: self.inner,
1941
0
                    })
1942
                } else {
1943
                    // Write a SCALE-encoded `None`.
1944
0
                    self.inner
1945
0
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
1946
                }
1947
            }
1948
            HostFunction::ext_offchain_local_storage_clear_version_1 => {
1949
0
                if expect_offchain_storage_kind!(0) {
1950
0
                    let (key_ptr, key_size) = expect_pointer_size_raw!(1);
1951
0
                    HostVm::ExternalOffchainStorageSet(ExternalOffchainStorageSet {
1952
0
                        key_ptr,
1953
0
                        key_size,
1954
0
                        value: None,
1955
0
                        old_value: None,
1956
0
                        inner: self.inner,
1957
0
                    })
1958
                } else {
1959
0
                    HostVm::ReadyToRun(ReadyToRun {
1960
0
                        inner: self.inner,
1961
0
                        resume_value: None,
1962
0
                    })
1963
                }
1964
            }
1965
0
            HostFunction::ext_offchain_http_request_start_version_1 => host_fn_not_implemented!(),
1966
            HostFunction::ext_offchain_http_request_add_header_version_1 => {
1967
0
                host_fn_not_implemented!()
1968
            }
1969
            HostFunction::ext_offchain_http_request_write_body_version_1 => {
1970
0
                host_fn_not_implemented!()
1971
            }
1972
0
            HostFunction::ext_offchain_http_response_wait_version_1 => host_fn_not_implemented!(),
1973
            HostFunction::ext_offchain_http_response_headers_version_1 => {
1974
0
                host_fn_not_implemented!()
1975
            }
1976
            HostFunction::ext_offchain_http_response_read_body_version_1 => {
1977
0
                host_fn_not_implemented!()
1978
            }
1979
            HostFunction::ext_trie_blake2_256_root_version_1
1980
            | HostFunction::ext_trie_blake2_256_root_version_2
1981
            | HostFunction::ext_trie_keccak_256_root_version_1
1982
            | HostFunction::ext_trie_keccak_256_root_version_2 => {
1983
0
                let state_version = if matches!(
1984
0
                    host_fn,
1985
                    HostFunction::ext_trie_blake2_256_root_version_2
1986
                        | HostFunction::ext_trie_keccak_256_root_version_2
1987
                ) {
1988
0
                    expect_state_version!(1)
1989
                } else {
1990
0
                    TrieEntryVersion::V0
1991
                };
1992
1993
0
                let result = {
1994
0
                    let input = expect_pointer_size!(0);
1995
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
1996
0
                        nom::Parser::parse(
1997
0
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
1998
0
                                crate::util::nom_scale_compact_usize,
1999
0
                                |num_elems| {
2000
                                    nom::multi::many_m_n(
2001
                                        num_elems,
2002
                                        num_elems,
2003
                                        (
2004
                                            nom::combinator::flat_map(
2005
                                                crate::util::nom_scale_compact_usize,
2006
                                                nom::bytes::streaming::take,
2007
                                            ),
2008
                                            nom::combinator::flat_map(
2009
                                                crate::util::nom_scale_compact_usize,
2010
                                                nom::bytes::streaming::take,
2011
                                            ),
2012
                                        ),
2013
                                    )
2014
0
                                },
2015
0
                            )),
2016
0
                            input.as_ref(),
2017
0
                        )
2018
0
                        .map(|(_, parse_result)| parse_result);
2019
0
2020
0
                    match parsing_result {
2021
0
                        Ok(elements) => Ok(trie::trie_root(
2022
0
                            state_version,
2023
0
                            if matches!(
2024
0
                                host_fn,
2025
                                HostFunction::ext_trie_blake2_256_root_version_1
2026
                                    | HostFunction::ext_trie_blake2_256_root_version_2
2027
                            ) {
2028
0
                                trie::HashFunction::Blake2
2029
                            } else {
2030
0
                                trie::HashFunction::Keccak256
2031
                            },
2032
0
                            &elements[..],
2033
                        )),
2034
0
                        Err(_) => Err(()),
2035
                    }
2036
                };
2037
2038
0
                match result {
2039
0
                    Ok(out) => self
2040
0
                        .inner
2041
0
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2042
0
                    Err(()) => HostVm::Error {
2043
0
                        error: Error::ParamDecodeError,
2044
0
                        prototype: self.inner.into_prototype(),
2045
0
                    },
2046
                }
2047
            }
2048
            HostFunction::ext_trie_blake2_256_ordered_root_version_1
2049
            | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2050
            | HostFunction::ext_trie_keccak_256_ordered_root_version_1
2051
            | HostFunction::ext_trie_keccak_256_ordered_root_version_2 => {
2052
0
                let state_version = if matches!(
2053
0
                    host_fn,
2054
                    HostFunction::ext_trie_blake2_256_ordered_root_version_2
2055
                        | HostFunction::ext_trie_keccak_256_ordered_root_version_2
2056
                ) {
2057
0
                    expect_state_version!(1)
2058
                } else {
2059
0
                    TrieEntryVersion::V0
2060
                };
2061
2062
0
                let result = {
2063
0
                    let input = expect_pointer_size!(0);
2064
0
                    let parsing_result: Result<_, nom::Err<(&[u8], nom::error::ErrorKind)>> =
2065
0
                        nom::Parser::parse(
2066
0
                            &mut nom::combinator::all_consuming(nom::combinator::flat_map(
2067
0
                                crate::util::nom_scale_compact_usize,
2068
0
                                |num_elems| {
2069
                                    nom::multi::many_m_n(
2070
                                        num_elems,
2071
                                        num_elems,
2072
                                        nom::combinator::flat_map(
2073
                                            crate::util::nom_scale_compact_usize,
2074
                                            nom::bytes::streaming::take,
2075
                                        ),
2076
                                    )
2077
0
                                },
2078
0
                            )),
2079
0
                            input.as_ref(),
2080
0
                        )
2081
0
                        .map(|(_, parse_result)| parse_result);
2082
0
2083
0
                    match parsing_result {
2084
0
                        Ok(elements) => Ok(trie::ordered_root(
2085
0
                            state_version,
2086
0
                            if matches!(
2087
0
                                host_fn,
2088
                                HostFunction::ext_trie_blake2_256_ordered_root_version_1
2089
                                    | HostFunction::ext_trie_blake2_256_ordered_root_version_2
2090
                            ) {
2091
0
                                trie::HashFunction::Blake2
2092
                            } else {
2093
0
                                trie::HashFunction::Keccak256
2094
                            },
2095
0
                            &elements[..],
2096
                        )),
2097
0
                        Err(_) => Err(()),
2098
                    }
2099
                };
2100
2101
0
                match result {
2102
0
                    Ok(out) => self
2103
0
                        .inner
2104
0
                        .alloc_write_and_return_pointer(host_fn.name(), iter::once(&out)),
2105
0
                    Err(()) => HostVm::Error {
2106
0
                        error: Error::ParamDecodeError,
2107
0
                        prototype: self.inner.into_prototype(),
2108
0
                    },
2109
                }
2110
            }
2111
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_1 => host_fn_not_implemented!(),
2112
0
            HostFunction::ext_trie_blake2_256_verify_proof_version_2 => host_fn_not_implemented!(),
2113
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_1 => host_fn_not_implemented!(),
2114
0
            HostFunction::ext_trie_keccak_256_verify_proof_version_2 => host_fn_not_implemented!(),
2115
            HostFunction::ext_misc_print_num_version_1 => {
2116
0
                let num = match params[0] {
2117
0
                    vm::WasmValue::I64(v) => u64::from_ne_bytes(v.to_ne_bytes()),
2118
                    // The signatures are checked at initialization and the Wasm VM ensures that
2119
                    // the proper parameter types are provided.
2120
0
                    _ => unreachable!(),
2121
                };
2122
2123
0
                HostVm::LogEmit(LogEmit {
2124
0
                    inner: self.inner,
2125
0
                    log_entry: LogEmitInner::Num(num),
2126
0
                })
2127
            }
2128
            HostFunction::ext_misc_print_utf8_version_1 => {
2129
0
                let (str_ptr, str_size) = expect_pointer_size_raw!(0);
2130
2131
0
                let utf8_check = str::from_utf8(
2132
0
                    self.inner
2133
0
                        .vm
2134
0
                        .read_memory(str_ptr, str_size)
2135
0
                        .unwrap_or_else(|_| unreachable!())
2136
0
                        .as_ref(),
2137
0
                )
2138
0
                .map(|_| ());
2139
0
                if let Err(error) = utf8_check {
2140
0
                    return HostVm::Error {
2141
0
                        error: Error::Utf8Error {
2142
0
                            function: host_fn.name(),
2143
0
                            param_num: 2,
2144
0
                            error,
2145
0
                        },
2146
0
                        prototype: self.inner.into_prototype(),
2147
0
                    };
2148
0
                }
2149
0
2150
0
                HostVm::LogEmit(LogEmit {
2151
0
                    inner: self.inner,
2152
0
                    log_entry: LogEmitInner::Utf8 { str_ptr, str_size },
2153
0
                })
2154
            }
2155
            HostFunction::ext_misc_print_hex_version_1 => {
2156
0
                let (data_ptr, data_size) = expect_pointer_size_raw!(0);
2157
0
                HostVm::LogEmit(LogEmit {
2158
0
                    inner: self.inner,
2159
0
                    log_entry: LogEmitInner::Hex {
2160
0
                        data_ptr,
2161
0
                        data_size,
2162
0
                    },
2163
0
                })
2164
            }
2165
            HostFunction::ext_misc_runtime_version_version_1 => {
2166
0
                let (wasm_blob_ptr, wasm_blob_size) = expect_pointer_size_raw!(0);
2167
0
                HostVm::CallRuntimeVersion(CallRuntimeVersion {
2168
0
                    inner: self.inner,
2169
0
                    wasm_blob_ptr,
2170
0
                    wasm_blob_size,
2171
0
                })
2172
            }
2173
            HostFunction::ext_allocator_malloc_version_1 => {
2174
2.37k
                let size = expect_u32!(0);
2175
2176
2.37k
                let ptr = match self.inner.alloc(host_fn.name(), size) {
2177
2.37k
                    Ok(p) => p,
2178
0
                    Err(error) => {
2179
0
                        return HostVm::Error {
2180
0
                            error,
2181
0
                            prototype: self.inner.into_prototype(),
2182
0
                        };
2183
                    }
2184
                };
2185
2186
2.37k
                let ptr_i32 = i32::from_ne_bytes(ptr.to_ne_bytes());
2187
2.37k
                HostVm::ReadyToRun(ReadyToRun {
2188
2.37k
                    resume_value: Some(vm::WasmValue::I32(ptr_i32)),
2189
2.37k
                    inner: self.inner,
2190
2.37k
                })
2191
            }
2192
            HostFunction::ext_allocator_free_version_1 => {
2193
2.41k
                let pointer = expect_u32!(0);
2194
2.41k
                match self.inner.allocator.deallocate(
2195
2.41k
                    &mut MemAccess {
2196
2.41k
                        vm: MemAccessVm::Running(&mut self.inner.vm),
2197
2.41k
                        memory_total_pages: self.inner.common.memory_total_pages,
2198
2.41k
                    },
2199
2.41k
                    pointer,
2200
2.41k
                ) {
2201
2.41k
                    Ok(()) => {}
2202
                    Err(_) => {
2203
0
                        return HostVm::Error {
2204
0
                            error: Error::FreeError { pointer },
2205
0
                            prototype: self.inner.into_prototype(),
2206
0
                        };
2207
                    }
2208
                };
2209
2210
2.41k
                HostVm::ReadyToRun(ReadyToRun {
2211
2.41k
                    resume_value: None,
2212
2.41k
                    inner: self.inner,
2213
2.41k
                })
2214
            }
2215
            HostFunction::ext_logging_log_version_1 => {
2216
0
                let log_level = expect_u32!(0);
2217
2218
0
                let (target_str_ptr, target_str_size) = expect_pointer_size_raw!(1);
2219
0
                let target_utf8_check = str::from_utf8(
2220
0
                    self.inner
2221
0
                        .vm
2222
0
                        .read_memory(target_str_ptr, target_str_size)
2223
0
                        .unwrap_or_else(|_| unreachable!())
2224
0
                        .as_ref(),
2225
0
                )
2226
0
                .map(|_| ());
2227
0
                if let Err(error) = target_utf8_check {
2228
0
                    return HostVm::Error {
2229
0
                        error: Error::Utf8Error {
2230
0
                            function: host_fn.name(),
2231
0
                            param_num: 1,
2232
0
                            error,
2233
0
                        },
2234
0
                        prototype: self.inner.into_prototype(),
2235
0
                    };
2236
0
                }
2237
2238
0
                let (msg_str_ptr, msg_str_size) = expect_pointer_size_raw!(2);
2239
0
                let msg_utf8_check = str::from_utf8(
2240
0
                    self.inner
2241
0
                        .vm
2242
0
                        .read_memory(msg_str_ptr, msg_str_size)
2243
0
                        .unwrap_or_else(|_| unreachable!())
2244
0
                        .as_ref(),
2245
0
                )
2246
0
                .map(|_| ());
2247
0
                if let Err(error) = msg_utf8_check {
2248
0
                    return HostVm::Error {
2249
0
                        error: Error::Utf8Error {
2250
0
                            function: host_fn.name(),
2251
0
                            param_num: 2,
2252
0
                            error,
2253
0
                        },
2254
0
                        prototype: self.inner.into_prototype(),
2255
0
                    };
2256
0
                }
2257
0
2258
0
                HostVm::LogEmit(LogEmit {
2259
0
                    inner: self.inner,
2260
0
                    log_entry: LogEmitInner::Log {
2261
0
                        log_level,
2262
0
                        target_str_ptr,
2263
0
                        target_str_size,
2264
0
                        msg_str_ptr,
2265
0
                        msg_str_size,
2266
0
                    },
2267
0
                })
2268
            }
2269
            HostFunction::ext_logging_max_level_version_1 => {
2270
127
                HostVm::GetMaxLogLevel(GetMaxLogLevel { inner: self.inner })
2271
            }
2272
            HostFunction::ext_panic_handler_abort_on_panic_version_1 => {
2273
0
                let message = {
2274
0
                    let message_bytes = expect_pointer_size!(0);
2275
0
                    str::from_utf8(message_bytes.as_ref()).map(|msg| msg.to_owned())
2276
0
                };
2277
0
2278
0
                match message {
2279
0
                    Ok(message) => HostVm::Error {
2280
0
                        error: Error::AbortOnPanic { message },
2281
0
                        prototype: self.inner.into_prototype(),
2282
0
                    },
2283
0
                    Err(error) => HostVm::Error {
2284
0
                        error: Error::Utf8Error {
2285
0
                            function: host_fn.name(),
2286
0
                            param_num: 0,
2287
0
                            error,
2288
0
                        },
2289
0
                        prototype: self.inner.into_prototype(),
2290
0
                    },
2291
                }
2292
            }
2293
        }
2294
5.20k
    }
2295
}
2296
2297
impl fmt::Debug for ReadyToRun {
2298
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2299
0
        f.debug_tuple("ReadyToRun").finish()
2300
0
    }
Unexecuted instantiation: _RNvXs3_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_10ReadyToRunNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs3_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_10ReadyToRunNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2301
}
2302
2303
/// Function execution has succeeded. Contains the return value of the call.
2304
///
2305
/// The trie root hash of all the child tries must be recalculated and written to the main trie
2306
/// similar to when a [`ExternalStorageRoot`] with a `child_trie` of `None` is generated. See the
2307
/// documentation of [`ExternalStorageRoot`].
2308
pub struct Finished {
2309
    inner: Box<Inner>,
2310
2311
    /// Pointer to the value returned by the VM. Guaranteed to be in range.
2312
    value_ptr: u32,
2313
    /// Size of the value returned by the VM. Guaranteed to be in range.
2314
    value_size: u32,
2315
}
2316
2317
impl Finished {
2318
    /// Returns the value the called function has returned.
2319
158
    pub fn value(&self) -> impl AsRef<[u8]> {
2320
158
        self.inner
2321
158
            .vm
2322
158
            .read_memory(self.value_ptr, self.value_size)
2323
158
            .unwrap_or_else(|_| unreachable!())
2324
158
    }
_RNvMs4_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_8Finished5value
Line
Count
Source
2319
31
    pub fn value(&self) -> impl AsRef<[u8]> {
2320
31
        self.inner
2321
31
            .vm
2322
31
            .read_memory(self.value_ptr, self.value_size)
2323
31
            .unwrap_or_else(|_| unreachable!())
2324
31
    }
_RNvMs4_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_8Finished5value
Line
Count
Source
2319
127
    pub fn value(&self) -> impl AsRef<[u8]> {
2320
127
        self.inner
2321
127
            .vm
2322
127
            .read_memory(self.value_ptr, self.value_size)
2323
127
            .unwrap_or_else(|_| unreachable!())
2324
127
    }
2325
2326
    /// Turns the virtual machine back into a prototype.
2327
135
    pub fn into_prototype(self) -> HostVmPrototype {
2328
135
        self.inner.into_prototype()
2329
135
    }
_RNvMs4_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_8Finished14into_prototype
Line
Count
Source
2327
9
    pub fn into_prototype(self) -> HostVmPrototype {
2328
9
        self.inner.into_prototype()
2329
9
    }
_RNvMs4_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_8Finished14into_prototype
Line
Count
Source
2327
126
    pub fn into_prototype(self) -> HostVmPrototype {
2328
126
        self.inner.into_prototype()
2329
126
    }
2330
}
2331
2332
impl fmt::Debug for Finished {
2333
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2334
0
        f.debug_tuple("Finished").finish()
2335
0
    }
Unexecuted instantiation: _RNvXs5_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_8FinishedNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs5_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_8FinishedNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2336
}
2337
2338
/// Must provide the value of a storage entry.
2339
pub struct ExternalStorageGet {
2340
    inner: Box<Inner>,
2341
2342
    /// Function currently being called by the Wasm code. Refers to an index within
2343
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
2344
    calling: usize,
2345
2346
    /// Used only for the `ext_storage_read_version_1` function. Stores the pointer where the
2347
    /// output should be stored.
2348
    value_out_ptr: Option<u32>,
2349
2350
    /// Pointer to the key whose value must be loaded. Guaranteed to be in range.
2351
    key_ptr: u32,
2352
    /// Size of the key whose value must be loaded. Guaranteed to be in range.
2353
    key_size: u32,
2354
    /// Pointer and size to the default child trie. `None` if main trie. Guaranteed to be in range.
2355
    child_trie_ptr_size: Option<(u32, u32)>,
2356
    /// Offset within the value that the Wasm VM requires.
2357
    offset: u32,
2358
    /// Maximum size that the Wasm VM would accept.
2359
    max_size: u32,
2360
}
2361
2362
impl ExternalStorageGet {
2363
    /// Returns the key whose value must be provided back with [`ExternalStorageGet::resume`].
2364
2.90k
    pub fn key(&self) -> impl AsRef<[u8]> {
2365
2.90k
        self.inner
2366
2.90k
            .vm
2367
2.90k
            .read_memory(self.key_ptr, self.key_size)
2368
2.90k
            .unwrap_or_else(|_| unreachable!())
2369
2.90k
    }
_RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet3key
Line
Count
Source
2364
2.73k
    pub fn key(&self) -> impl AsRef<[u8]> {
2365
2.73k
        self.inner
2366
2.73k
            .vm
2367
2.73k
            .read_memory(self.key_ptr, self.key_size)
2368
2.73k
            .unwrap_or_else(|_| unreachable!())
2369
2.73k
    }
_RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet3key
Line
Count
Source
2364
168
    pub fn key(&self) -> impl AsRef<[u8]> {
2365
168
        self.inner
2366
168
            .vm
2367
168
            .read_memory(self.key_ptr, self.key_size)
2368
168
            .unwrap_or_else(|_| unreachable!())
2369
168
    }
2370
2371
    /// If `Some`, read from the given child trie. If `None`, read from the main trie.
2372
811
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2373
811
        if let Some((
child_trie_ptr, child_trie_size12
)) = self.child_trie_ptr_size {
2374
12
            let child_trie = self
2375
12
                .inner
2376
12
                .vm
2377
12
                .read_memory(child_trie_ptr, child_trie_size)
2378
12
                .unwrap_or_else(|_| unreachable!());
2379
12
            Some(child_trie)
2380
        } else {
2381
799
            None
2382
        }
2383
811
    }
_RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet10child_trie
Line
Count
Source
2372
727
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2373
727
        if let Some((
child_trie_ptr, child_trie_size12
)) = self.child_trie_ptr_size {
2374
12
            let child_trie = self
2375
12
                .inner
2376
12
                .vm
2377
12
                .read_memory(child_trie_ptr, child_trie_size)
2378
12
                .unwrap_or_else(|_| unreachable!());
2379
12
            Some(child_trie)
2380
        } else {
2381
715
            None
2382
        }
2383
727
    }
_RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet10child_trie
Line
Count
Source
2372
84
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2373
84
        if let Some((
child_trie_ptr, child_trie_size0
)) = self.child_trie_ptr_size {
2374
0
            let child_trie = self
2375
0
                .inner
2376
0
                .vm
2377
0
                .read_memory(child_trie_ptr, child_trie_size)
2378
0
                .unwrap_or_else(|_| unreachable!());
2379
0
            Some(child_trie)
2380
        } else {
2381
84
            None
2382
        }
2383
84
    }
2384
2385
    /// Offset within the value that is requested.
2386
0
    pub fn offset(&self) -> u32 {
2387
0
        self.offset
2388
0
    }
Unexecuted instantiation: _RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet6offset
Unexecuted instantiation: _RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet6offset
2389
2390
    /// Maximum size of the value to pass back.
2391
    ///
2392
    /// > **Note**: This can be 0 if we only want to know whether a value exists.
2393
0
    pub fn max_size(&self) -> u32 {
2394
0
        self.max_size
2395
0
    }
Unexecuted instantiation: _RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet8max_size
Unexecuted instantiation: _RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet8max_size
2396
2397
    /// Same as [`ExternalStorageGet::resume`], but passes the full value, without taking the
2398
    /// offset and maximum size into account.
2399
    ///
2400
    /// This is a convenient function that automatically applies the offset and maximum size, to
2401
    /// use when the full storage value is already present in memory.
2402
687
    pub fn resume_full_value(self, value: Option<&[u8]>) -> HostVm {
2403
687
        if let Some(
value598
) = value {
2404
598
            if usize::try_from(self.offset).unwrap_or_else(|_| unreachable!()) < value.len() {
2405
598
                let value_slice =
2406
598
                    &value[usize::try_from(self.offset).unwrap_or_else(|_| unreachable!())..];
2407
598
                if usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())
2408
598
                    < value_slice.len()
2409
                {
2410
10
                    let value_slice = &value_slice
2411
10
                        [..usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())];
2412
10
                    self.resume(Some((value_slice, value.len())))
2413
                } else {
2414
588
                    self.resume(Some((value_slice, value.len())))
2415
                }
2416
            } else {
2417
0
                self.resume(Some((&[], value.len())))
2418
            }
2419
        } else {
2420
89
            self.resume(None)
2421
        }
2422
687
    }
_RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet17resume_full_value
Line
Count
Source
2402
603
    pub fn resume_full_value(self, value: Option<&[u8]>) -> HostVm {
2403
603
        if let Some(
value514
) = value {
2404
514
            if usize::try_from(self.offset).unwrap_or_else(|_| unreachable!()) < value.len() {
2405
514
                let value_slice =
2406
514
                    &value[usize::try_from(self.offset).unwrap_or_else(|_| unreachable!())..];
2407
514
                if usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())
2408
514
                    < value_slice.len()
2409
                {
2410
10
                    let value_slice = &value_slice
2411
10
                        [..usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())];
2412
10
                    self.resume(Some((value_slice, value.len())))
2413
                } else {
2414
504
                    self.resume(Some((value_slice, value.len())))
2415
                }
2416
            } else {
2417
0
                self.resume(Some((&[], value.len())))
2418
            }
2419
        } else {
2420
89
            self.resume(None)
2421
        }
2422
603
    }
_RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet17resume_full_value
Line
Count
Source
2402
84
    pub fn resume_full_value(self, value: Option<&[u8]>) -> HostVm {
2403
84
        if let Some(value) = value {
2404
84
            if usize::try_from(self.offset).unwrap_or_else(|_| unreachable!()) < value.len() {
2405
84
                let value_slice =
2406
84
                    &value[usize::try_from(self.offset).unwrap_or_else(|_| unreachable!())..];
2407
84
                if usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())
2408
84
                    < value_slice.len()
2409
                {
2410
0
                    let value_slice = &value_slice
2411
0
                        [..usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!())];
2412
0
                    self.resume(Some((value_slice, value.len())))
2413
                } else {
2414
84
                    self.resume(Some((value_slice, value.len())))
2415
                }
2416
            } else {
2417
0
                self.resume(Some((&[], value.len())))
2418
            }
2419
        } else {
2420
0
            self.resume(None)
2421
        }
2422
84
    }
2423
2424
    /// Writes the storage value in the Wasm VM's memory and prepares the virtual machine to
2425
    /// resume execution.
2426
    ///
2427
    /// The value to provide must be the value of that key starting at the offset returned by
2428
    /// [`ExternalStorageGet::offset`]. If the offset is out of range, an empty slice must be
2429
    /// passed.
2430
    ///
2431
    /// If `Some`, the total size of the value, without taking [`ExternalStorageGet::offset`] or
2432
    /// [`ExternalStorageGet::max_size`] into account, must additionally be provided.
2433
    ///
2434
    /// If [`ExternalStorageGet::child_trie`] returns `Some` but the child trie doesn't exist,
2435
    /// then `None` must be provided.
2436
    ///
2437
    /// The value must not be longer than what [`ExternalStorageGet::max_size`] returns.
2438
    ///
2439
    /// # Panic
2440
    ///
2441
    /// Panics if the value is longer than what [`ExternalStorageGet::max_size`] returns.
2442
    ///
2443
687
    pub fn resume(self, value: Option<(&[u8], usize)>) -> HostVm {
2444
687
        self.resume_vectored(
2445
687
            value
2446
687
                .as_ref()
2447
687
                .map(|(value, size)| 
(iter::once(&value[..]), *size)598
),
_RNCNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_18ExternalStorageGet6resume0Bb_
Line
Count
Source
2447
514
                .map(|(value, size)| (iter::once(&value[..]), *size)),
_RNCNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_18ExternalStorageGet6resume0Bb_
Line
Count
Source
2447
84
                .map(|(value, size)| (iter::once(&value[..]), *size)),
2448
687
        )
2449
687
    }
_RNvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGet6resume
Line
Count
Source
2443
603
    pub fn resume(self, value: Option<(&[u8], usize)>) -> HostVm {
2444
603
        self.resume_vectored(
2445
603
            value
2446
603
                .as_ref()
2447
603
                .map(|(value, size)| (iter::once(&value[..]), *size)),
2448
603
        )
2449
603
    }
_RNvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGet6resume
Line
Count
Source
2443
84
    pub fn resume(self, value: Option<(&[u8], usize)>) -> HostVm {
2444
84
        self.resume_vectored(
2445
84
            value
2446
84
                .as_ref()
2447
84
                .map(|(value, size)| (iter::once(&value[..]), *size)),
2448
84
        )
2449
84
    }
2450
2451
    /// Similar to [`ExternalStorageGet::resume`], but allows passing the value as a list of
2452
    /// buffers whose concatenation forms the actual value.
2453
    ///
2454
    /// If `Some`, the total size of the value, without taking [`ExternalStorageGet::offset`] or
2455
    /// [`ExternalStorageGet::max_size`] into account, must additionally be provided.
2456
    ///
2457
    /// # Panic
2458
    ///
2459
    /// See [`ExternalStorageGet::resume`].
2460
    ///
2461
687
    pub fn resume_vectored(
2462
687
        mut self,
2463
687
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>> + Clone, usize)>,
2464
687
    ) -> HostVm {
2465
687
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2466
687
            FunctionImport::Resolved(f) => f,
2467
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2468
        };
2469
2470
687
        match host_fn {
2471
            HostFunction::ext_storage_get_version_1
2472
            | HostFunction::ext_default_child_storage_get_version_1 => {
2473
657
                if let Some((
value, value_total_len588
)) = value {
2474
                    // Writing `Some(value)`.
2475
588
                    debug_assert_eq!(
2476
588
                        value.clone().fold(0, |a, b| a + b.as_ref().len()),
_RNCINvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB8_18ExternalStorageGet15resume_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1s_EEs3_0Bc_
Line
Count
Source
2476
504
                        value.clone().fold(0, |a, b| a + b.as_ref().len()),
_RNCINvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB8_18ExternalStorageGet15resume_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1s_EEs3_0Bc_
Line
Count
Source
2476
84
                        value.clone().fold(0, |a, b| a + b.as_ref().len()),
2477
                        value_total_len
2478
                    );
2479
588
                    let value_len_enc = util::encode_scale_compact_usize(value_total_len);
2480
588
                    self.inner.alloc_write_and_return_pointer_size(
2481
588
                        host_fn.name(),
2482
588
                        iter::once(&[1][..])
2483
588
                            .chain(iter::once(value_len_enc.as_ref()))
2484
588
                            .map(either::Left)
2485
588
                            .chain(value.map(either::Right)),
2486
588
                    )
2487
                } else {
2488
                    // Write a SCALE-encoded `None`.
2489
69
                    self.inner
2490
69
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
2491
                }
2492
            }
2493
            HostFunction::ext_storage_read_version_1
2494
            | HostFunction::ext_default_child_storage_read_version_1 => {
2495
14
                let outcome = if let Some((
value, value_total_len2
)) = value {
2496
2
                    let mut remaining_max_allowed =
2497
2
                        usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!());
2498
2
                    let mut offset = self.value_out_ptr.unwrap_or_else(|| unreachable!());
2499
4
                    for 
value2
in value {
2500
2
                        let value = value.as_ref();
2501
2
                        assert!(value.len() <= remaining_max_allowed);
2502
2
                        remaining_max_allowed -= value.len();
2503
2
                        self.inner
2504
2
                            .vm
2505
2
                            .write_memory(offset, value)
2506
2
                            .unwrap_or_else(|_| unreachable!());
2507
2
                        offset += u32::try_from(value.len()).unwrap_or_else(|_| unreachable!());
2508
2
                    }
2509
2510
                    // Note: the https://github.com/paritytech/substrate/pull/7084 PR has changed
2511
                    // the meaning of this return value.
2512
2
                    Some(
2513
2
                        u32::try_from(value_total_len).unwrap_or_else(|_| unreachable!())
2514
2
                            - self.offset,
2515
2
                    )
2516
                } else {
2517
12
                    None
2518
                };
2519
2520
14
                return self.inner.alloc_write_and_return_pointer_size(
2521
14
                    host_fn.name(),
2522
14
                    if let Some(
outcome2
) = outcome {
2523
2
                        either::Left(
2524
2
                            iter::once(either::Left([1u8]))
2525
2
                                .chain(iter::once(either::Right(outcome.to_le_bytes()))),
2526
2
                        )
2527
                    } else {
2528
12
                        either::Right(iter::once(either::Left([0u8])))
2529
                    },
2530
                );
2531
            }
2532
            HostFunction::ext_storage_exists_version_1
2533
            | HostFunction::ext_default_child_storage_exists_version_1 => {
2534
                HostVm::ReadyToRun(ReadyToRun {
2535
16
                    inner: self.inner,
2536
16
                    resume_value: Some(if value.is_some() {
2537
8
                        vm::WasmValue::I32(1)
2538
                    } else {
2539
8
                        vm::WasmValue::I32(0)
2540
                    }),
2541
                })
2542
            }
2543
0
            _ => unreachable!(),
2544
        }
2545
687
    }
_RINvMs6_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_18ExternalStorageGet15resume_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1q_EEBa_
Line
Count
Source
2461
603
    pub fn resume_vectored(
2462
603
        mut self,
2463
603
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>> + Clone, usize)>,
2464
603
    ) -> HostVm {
2465
603
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2466
603
            FunctionImport::Resolved(f) => f,
2467
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2468
        };
2469
2470
603
        match host_fn {
2471
            HostFunction::ext_storage_get_version_1
2472
            | HostFunction::ext_default_child_storage_get_version_1 => {
2473
573
                if let Some((
value, value_total_len504
)) = value {
2474
                    // Writing `Some(value)`.
2475
504
                    debug_assert_eq!(
2476
504
                        value.clone().fold(0, |a, b| a + b.as_ref().len()),
2477
                        value_total_len
2478
                    );
2479
504
                    let value_len_enc = util::encode_scale_compact_usize(value_total_len);
2480
504
                    self.inner.alloc_write_and_return_pointer_size(
2481
504
                        host_fn.name(),
2482
504
                        iter::once(&[1][..])
2483
504
                            .chain(iter::once(value_len_enc.as_ref()))
2484
504
                            .map(either::Left)
2485
504
                            .chain(value.map(either::Right)),
2486
504
                    )
2487
                } else {
2488
                    // Write a SCALE-encoded `None`.
2489
69
                    self.inner
2490
69
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
2491
                }
2492
            }
2493
            HostFunction::ext_storage_read_version_1
2494
            | HostFunction::ext_default_child_storage_read_version_1 => {
2495
14
                let outcome = if let Some((
value, value_total_len2
)) = value {
2496
2
                    let mut remaining_max_allowed =
2497
2
                        usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!());
2498
2
                    let mut offset = self.value_out_ptr.unwrap_or_else(|| unreachable!());
2499
4
                    for 
value2
in value {
2500
2
                        let value = value.as_ref();
2501
2
                        assert!(value.len() <= remaining_max_allowed);
2502
2
                        remaining_max_allowed -= value.len();
2503
2
                        self.inner
2504
2
                            .vm
2505
2
                            .write_memory(offset, value)
2506
2
                            .unwrap_or_else(|_| unreachable!());
2507
2
                        offset += u32::try_from(value.len()).unwrap_or_else(|_| unreachable!());
2508
2
                    }
2509
2510
                    // Note: the https://github.com/paritytech/substrate/pull/7084 PR has changed
2511
                    // the meaning of this return value.
2512
2
                    Some(
2513
2
                        u32::try_from(value_total_len).unwrap_or_else(|_| unreachable!())
2514
2
                            - self.offset,
2515
2
                    )
2516
                } else {
2517
12
                    None
2518
                };
2519
2520
14
                return self.inner.alloc_write_and_return_pointer_size(
2521
14
                    host_fn.name(),
2522
14
                    if let Some(
outcome2
) = outcome {
2523
2
                        either::Left(
2524
2
                            iter::once(either::Left([1u8]))
2525
2
                                .chain(iter::once(either::Right(outcome.to_le_bytes()))),
2526
2
                        )
2527
                    } else {
2528
12
                        either::Right(iter::once(either::Left([0u8])))
2529
                    },
2530
                );
2531
            }
2532
            HostFunction::ext_storage_exists_version_1
2533
            | HostFunction::ext_default_child_storage_exists_version_1 => {
2534
                HostVm::ReadyToRun(ReadyToRun {
2535
16
                    inner: self.inner,
2536
16
                    resume_value: Some(if value.is_some() {
2537
8
                        vm::WasmValue::I32(1)
2538
                    } else {
2539
8
                        vm::WasmValue::I32(0)
2540
                    }),
2541
                })
2542
            }
2543
0
            _ => unreachable!(),
2544
        }
2545
603
    }
_RINvMs6_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_18ExternalStorageGet15resume_vectoredRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1q_EEBa_
Line
Count
Source
2461
84
    pub fn resume_vectored(
2462
84
        mut self,
2463
84
        value: Option<(impl Iterator<Item = impl AsRef<[u8]>> + Clone, usize)>,
2464
84
    ) -> HostVm {
2465
84
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2466
84
            FunctionImport::Resolved(f) => f,
2467
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2468
        };
2469
2470
84
        match host_fn {
2471
            HostFunction::ext_storage_get_version_1
2472
            | HostFunction::ext_default_child_storage_get_version_1 => {
2473
84
                if let Some((value, value_total_len)) = value {
2474
                    // Writing `Some(value)`.
2475
84
                    debug_assert_eq!(
2476
84
                        value.clone().fold(0, |a, b| a + b.as_ref().len()),
2477
                        value_total_len
2478
                    );
2479
84
                    let value_len_enc = util::encode_scale_compact_usize(value_total_len);
2480
84
                    self.inner.alloc_write_and_return_pointer_size(
2481
84
                        host_fn.name(),
2482
84
                        iter::once(&[1][..])
2483
84
                            .chain(iter::once(value_len_enc.as_ref()))
2484
84
                            .map(either::Left)
2485
84
                            .chain(value.map(either::Right)),
2486
84
                    )
2487
                } else {
2488
                    // Write a SCALE-encoded `None`.
2489
0
                    self.inner
2490
0
                        .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
2491
                }
2492
            }
2493
            HostFunction::ext_storage_read_version_1
2494
            | HostFunction::ext_default_child_storage_read_version_1 => {
2495
0
                let outcome = if let Some((value, value_total_len)) = value {
2496
0
                    let mut remaining_max_allowed =
2497
0
                        usize::try_from(self.max_size).unwrap_or_else(|_| unreachable!());
2498
0
                    let mut offset = self.value_out_ptr.unwrap_or_else(|| unreachable!());
2499
0
                    for value in value {
2500
0
                        let value = value.as_ref();
2501
0
                        assert!(value.len() <= remaining_max_allowed);
2502
0
                        remaining_max_allowed -= value.len();
2503
0
                        self.inner
2504
0
                            .vm
2505
0
                            .write_memory(offset, value)
2506
0
                            .unwrap_or_else(|_| unreachable!());
2507
0
                        offset += u32::try_from(value.len()).unwrap_or_else(|_| unreachable!());
2508
0
                    }
2509
2510
                    // Note: the https://github.com/paritytech/substrate/pull/7084 PR has changed
2511
                    // the meaning of this return value.
2512
0
                    Some(
2513
0
                        u32::try_from(value_total_len).unwrap_or_else(|_| unreachable!())
2514
0
                            - self.offset,
2515
0
                    )
2516
                } else {
2517
0
                    None
2518
                };
2519
2520
0
                return self.inner.alloc_write_and_return_pointer_size(
2521
0
                    host_fn.name(),
2522
0
                    if let Some(outcome) = outcome {
2523
0
                        either::Left(
2524
0
                            iter::once(either::Left([1u8]))
2525
0
                                .chain(iter::once(either::Right(outcome.to_le_bytes()))),
2526
0
                        )
2527
                    } else {
2528
0
                        either::Right(iter::once(either::Left([0u8])))
2529
                    },
2530
                );
2531
            }
2532
            HostFunction::ext_storage_exists_version_1
2533
            | HostFunction::ext_default_child_storage_exists_version_1 => {
2534
                HostVm::ReadyToRun(ReadyToRun {
2535
0
                    inner: self.inner,
2536
0
                    resume_value: Some(if value.is_some() {
2537
0
                        vm::WasmValue::I32(1)
2538
                    } else {
2539
0
                        vm::WasmValue::I32(0)
2540
                    }),
2541
                })
2542
            }
2543
0
            _ => unreachable!(),
2544
        }
2545
84
    }
2546
}
2547
2548
impl fmt::Debug for ExternalStorageGet {
2549
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2550
0
        f.debug_tuple("ExternalStorageGet").finish()
2551
0
    }
Unexecuted instantiation: _RNvXs7_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageGetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs7_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageGetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2552
}
2553
2554
/// Must set the value of a storage entry.
2555
///
2556
/// If [`ExternalStorageSet::child_trie`] return `None` and [`ExternalStorageSet::key`]
2557
/// returns a key that starts with `:child_storage:`, then the write must be silently ignored.
2558
///
2559
/// If [`ExternalStorageSet::child_trie`] and [`ExternalStorageSet::value`] return `Some` and the
2560
/// child trie doesn't exist, it must implicitly be created.
2561
/// If [`ExternalStorageSet::child_trie`] returns `Some` and [`ExternalStorageSet::value`]
2562
/// returns `None` and this is the last entry in the child trie, it must implicitly be destroyed.
2563
pub struct ExternalStorageSet {
2564
    inner: Box<Inner>,
2565
2566
    /// Pointer to the key whose value must be set. Guaranteed to be in range.
2567
    key_ptr: u32,
2568
    /// Size of the key whose value must be set. Guaranteed to be in range.
2569
    key_size: u32,
2570
    /// Pointer and size to the default child trie key. `None` if main trie. Guaranteed to be
2571
    /// in range.
2572
    child_trie_ptr_size: Option<(u32, u32)>,
2573
2574
    /// Pointer and size of the value to set. `None` for clearing. Guaranteed to be in range.
2575
    value: Option<(u32, u32)>,
2576
}
2577
2578
impl ExternalStorageSet {
2579
    /// Returns the key whose value must be set.
2580
746
    pub fn key(&self) -> impl AsRef<[u8]> {
2581
746
        self.inner
2582
746
            .vm
2583
746
            .read_memory(self.key_ptr, self.key_size)
2584
746
            .unwrap_or_else(|_| unreachable!())
2585
746
    }
_RNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSet3key
Line
Count
Source
2580
746
    pub fn key(&self) -> impl AsRef<[u8]> {
2581
746
        self.inner
2582
746
            .vm
2583
746
            .read_memory(self.key_ptr, self.key_size)
2584
746
            .unwrap_or_else(|_| unreachable!())
2585
746
    }
Unexecuted instantiation: _RNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSet3key
2586
2587
    /// If `Some`, write to the given child trie. If `None`, write to the main trie.
2588
    ///
2589
    /// If [`ExternalStorageSet::value`] returns `Some` and the child trie doesn't exist, it must
2590
    /// implicitly be created.
2591
    /// If [`ExternalStorageSet::value`] returns `None` and this is the last entry in the child
2592
    /// trie, it must implicitly be destroyed.
2593
1.12k
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2594
1.12k
        match &self.child_trie_ptr_size {
2595
12
            Some((ptr, size)) => {
2596
12
                let child_trie = self
2597
12
                    .inner
2598
12
                    .vm
2599
12
                    .read_memory(*ptr, *size)
2600
12
                    .unwrap_or_else(|_| unreachable!());
2601
12
                Some(child_trie)
2602
            }
2603
1.11k
            None => None,
2604
        }
2605
1.12k
    }
_RNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSet10child_trie
Line
Count
Source
2593
1.12k
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2594
1.12k
        match &self.child_trie_ptr_size {
2595
12
            Some((ptr, size)) => {
2596
12
                let child_trie = self
2597
12
                    .inner
2598
12
                    .vm
2599
12
                    .read_memory(*ptr, *size)
2600
12
                    .unwrap_or_else(|_| unreachable!());
2601
12
                Some(child_trie)
2602
            }
2603
1.11k
            None => None,
2604
        }
2605
1.12k
    }
Unexecuted instantiation: _RNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSet10child_trie
2606
2607
    /// Returns the value to set.
2608
    ///
2609
    /// If `None` is returned, the key should be removed from the storage entirely.
2610
375
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
2611
375
        self.value.map(|(ptr, size)| {
2612
304
            self.inner
2613
304
                .vm
2614
304
                .read_memory(ptr, size)
2615
304
                .unwrap_or_else(|_| unreachable!())
2616
375
        })
_RNCNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_18ExternalStorageSet5value0Bb_
Line
Count
Source
2611
304
        self.value.map(|(ptr, size)| {
2612
304
            self.inner
2613
304
                .vm
2614
304
                .read_memory(ptr, size)
2615
304
                .unwrap_or_else(|_| unreachable!())
2616
304
        })
Unexecuted instantiation: _RNCNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_18ExternalStorageSet5value0Bb_
2617
375
    }
_RNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSet5value
Line
Count
Source
2610
375
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
2611
375
        self.value.map(|(ptr, size)| {
2612
            self.inner
2613
                .vm
2614
                .read_memory(ptr, size)
2615
                .unwrap_or_else(|_| unreachable!())
2616
375
        })
2617
375
    }
Unexecuted instantiation: _RNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSet5value
2618
2619
    /// Returns the state trie version indicated by the runtime.
2620
    ///
2621
    /// This information should be stored alongside with the storage value and is necessary in
2622
    /// order to properly build the trie and thus the trie root node hash.
2623
0
    pub fn state_trie_version(&self) -> TrieEntryVersion {
2624
0
        self.inner
2625
0
            .common
2626
0
            .runtime_version
2627
0
            .as_ref()
2628
0
            .unwrap_or_else(|| unreachable!())
2629
0
            .decode()
2630
0
            .state_version
2631
0
            .unwrap_or(TrieEntryVersion::V0)
2632
0
    }
Unexecuted instantiation: _RNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSet18state_trie_version
Unexecuted instantiation: _RNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSet18state_trie_version
2633
2634
    /// Resumes execution after having set the value.
2635
375
    pub fn resume(self) -> HostVm {
2636
375
        HostVm::ReadyToRun(ReadyToRun {
2637
375
            inner: self.inner,
2638
375
            resume_value: None,
2639
375
        })
2640
375
    }
_RNvMs8_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSet6resume
Line
Count
Source
2635
375
    pub fn resume(self) -> HostVm {
2636
375
        HostVm::ReadyToRun(ReadyToRun {
2637
375
            inner: self.inner,
2638
375
            resume_value: None,
2639
375
        })
2640
375
    }
Unexecuted instantiation: _RNvMs8_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSet6resume
2641
}
2642
2643
impl fmt::Debug for ExternalStorageSet {
2644
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2645
0
        f.debug_tuple("ExternalStorageSet").finish()
2646
0
    }
Unexecuted instantiation: _RNvXs9_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18ExternalStorageSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs9_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18ExternalStorageSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2647
}
2648
2649
/// Must load a storage value, treat it as if it was a SCALE-encoded container, and put `value`
2650
/// at the end of the container, increasing the number of elements.
2651
///
2652
/// If [`ExternalStorageAppend::child_trie`] return `Some` and the child trie doesn't exist, it
2653
/// must implicitly be created.
2654
///
2655
/// If [`ExternalStorageAppend::child_trie`] return `None` and [`ExternalStorageAppend::key`]
2656
/// returns a key that starts with `:child_storage:`, then the write must be silently ignored.
2657
///
2658
/// If there isn't any existing value of if the existing value isn't actually a SCALE-encoded
2659
/// container, store a 1-size container with the `value`.
2660
///
2661
/// # Details
2662
///
2663
/// The SCALE encoding encodes containers as a SCALE-compact-encoded length followed with the
2664
/// SCALE-encoded items one after the other. For example, a container of two elements is stored
2665
/// as the number `2` followed with the two items.
2666
///
2667
/// This change consists in taking an existing value and assuming that it is a SCALE-encoded
2668
/// container. This can be done as decoding a SCALE-compact-encoded number at the start of
2669
/// the existing encoded value. One most then increments that number and puts `value` at the
2670
/// end of the encoded value.
2671
///
2672
/// It is not necessary to decode `value` as is assumed that is already encoded in the same
2673
/// way as the other items in the container.
2674
pub struct ExternalStorageAppend {
2675
    inner: Box<Inner>,
2676
2677
    /// Pointer to the key whose value must be set. Guaranteed to be in range.
2678
    key_ptr: u32,
2679
    /// Size of the key whose value must be set. Guaranteed to be in range.
2680
    key_size: u32,
2681
2682
    /// Pointer to the value to append. Guaranteed to be in range.
2683
    value_ptr: u32,
2684
    /// Size of the value to append. Guaranteed to be in range.
2685
    value_size: u32,
2686
}
2687
2688
impl ExternalStorageAppend {
2689
    /// Returns the key whose value must be set.
2690
221
    pub fn key(&self) -> impl AsRef<[u8]> {
2691
221
        self.inner
2692
221
            .vm
2693
221
            .read_memory(self.key_ptr, self.key_size)
2694
221
            .unwrap_or_else(|_| unreachable!())
2695
221
    }
_RNvMsa_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21ExternalStorageAppend3key
Line
Count
Source
2690
221
    pub fn key(&self) -> impl AsRef<[u8]> {
2691
221
        self.inner
2692
221
            .vm
2693
221
            .read_memory(self.key_ptr, self.key_size)
2694
221
            .unwrap_or_else(|_| unreachable!())
2695
221
    }
Unexecuted instantiation: _RNvMsa_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21ExternalStorageAppend3key
2696
2697
    /// If `Some`, write to the given child trie. If `None`, write to the main trie.
2698
    ///
2699
    /// If this returns `Some` and the child trie doesn't exist, it must implicitly be created.
2700
    ///
2701
    /// > **Note**: At the moment, this function always returns None, as there is no host function
2702
    /// >           that appends to a child trie storage.
2703
228
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2704
228
        // Note that there is no equivalent of this host function for child tries.
2705
228
        None::<&'static [u8]>
2706
228
    }
_RNvMsa_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21ExternalStorageAppend10child_trie
Line
Count
Source
2703
228
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2704
228
        // Note that there is no equivalent of this host function for child tries.
2705
228
        None::<&'static [u8]>
2706
228
    }
Unexecuted instantiation: _RNvMsa_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21ExternalStorageAppend10child_trie
2707
2708
    /// Returns the value to append.
2709
71
    pub fn value(&self) -> impl AsRef<[u8]> {
2710
71
        self.inner
2711
71
            .vm
2712
71
            .read_memory(self.value_ptr, self.value_size)
2713
71
            .unwrap_or_else(|_| unreachable!())
2714
71
    }
_RNvMsa_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21ExternalStorageAppend5value
Line
Count
Source
2709
71
    pub fn value(&self) -> impl AsRef<[u8]> {
2710
71
        self.inner
2711
71
            .vm
2712
71
            .read_memory(self.value_ptr, self.value_size)
2713
71
            .unwrap_or_else(|_| unreachable!())
2714
71
    }
Unexecuted instantiation: _RNvMsa_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21ExternalStorageAppend5value
2715
2716
    /// Resumes execution after having set the value.
2717
71
    pub fn resume(self) -> HostVm {
2718
71
        HostVm::ReadyToRun(ReadyToRun {
2719
71
            inner: self.inner,
2720
71
            resume_value: None,
2721
71
        })
2722
71
    }
_RNvMsa_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21ExternalStorageAppend6resume
Line
Count
Source
2717
71
    pub fn resume(self) -> HostVm {
2718
71
        HostVm::ReadyToRun(ReadyToRun {
2719
71
            inner: self.inner,
2720
71
            resume_value: None,
2721
71
        })
2722
71
    }
Unexecuted instantiation: _RNvMsa_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21ExternalStorageAppend6resume
2723
}
2724
2725
impl fmt::Debug for ExternalStorageAppend {
2726
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2727
0
        f.debug_tuple("ExternalStorageAppend").finish()
2728
0
    }
Unexecuted instantiation: _RNvXsb_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21ExternalStorageAppendNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsb_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21ExternalStorageAppendNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2729
}
2730
2731
/// Must remove from the storage keys which start with a certain prefix. Use
2732
/// [`ExternalStorageClearPrefix::max_keys_to_remove`] to determine the maximum number of keys
2733
/// to remove.
2734
///
2735
/// If [`ExternalStorageClearPrefix::child_trie`] returns `Some` and all the entries of the child
2736
/// trie are removed, the child trie must implicitly be destroyed.
2737
///
2738
/// If [`ExternalStorageClearPrefix::child_trie`] return `None` and the prefix returned by
2739
/// [`ExternalStorageClearPrefix::prefix`] intersects with `:child_storage:`, then the clearing
2740
/// must be silently ignored.
2741
pub struct ExternalStorageClearPrefix {
2742
    inner: Box<Inner>,
2743
    /// Function currently being called by the Wasm code. Refers to an index within
2744
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
2745
    calling: usize,
2746
2747
    /// Pointer and size to the prefix. `None` if `&[]`. Guaranteed to be in range.
2748
    prefix_ptr_size: Option<(u32, u32)>,
2749
    /// Pointer and size to the default child trie. `None` if main trie. Guaranteed to be in range.
2750
    child_trie_ptr_size: Option<(u32, u32)>,
2751
2752
    /// Maximum number of keys to remove.
2753
    max_keys_to_remove: Option<u32>,
2754
}
2755
2756
impl ExternalStorageClearPrefix {
2757
    /// Returns the prefix whose keys must be removed.
2758
35
    pub fn prefix(&self) -> impl AsRef<[u8]> {
2759
35
        if let Some((
prefix_ptr, prefix_size31
)) = self.prefix_ptr_size {
2760
31
            either::Left(
2761
31
                self.inner
2762
31
                    .vm
2763
31
                    .read_memory(prefix_ptr, prefix_size)
2764
31
                    .unwrap_or_else(|_| unreachable!()),
2765
31
            )
2766
        } else {
2767
4
            either::Right(&[][..])
2768
        }
2769
35
    }
_RNvMsc_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix6prefix
Line
Count
Source
2758
35
    pub fn prefix(&self) -> impl AsRef<[u8]> {
2759
35
        if let Some((
prefix_ptr, prefix_size31
)) = self.prefix_ptr_size {
2760
31
            either::Left(
2761
31
                self.inner
2762
31
                    .vm
2763
31
                    .read_memory(prefix_ptr, prefix_size)
2764
31
                    .unwrap_or_else(|_| unreachable!()),
2765
31
            )
2766
        } else {
2767
4
            either::Right(&[][..])
2768
        }
2769
35
    }
Unexecuted instantiation: _RNvMsc_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix6prefix
2770
2771
    /// If `Some`, write to the given child trie. If `None`, write to the main trie.
2772
    ///
2773
    /// If [`ExternalStorageClearPrefix::child_trie`] returns `Some` and all the entries of the
2774
    /// child trie are removed, the child trie must implicitly be destroyed.
2775
49
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2776
49
        if let Some((
child_trie_ptr, child_trie_size7
)) = self.child_trie_ptr_size {
2777
7
            let child_trie = self
2778
7
                .inner
2779
7
                .vm
2780
7
                .read_memory(child_trie_ptr, child_trie_size)
2781
7
                .unwrap_or_else(|_| unreachable!());
2782
7
            Some(child_trie)
2783
        } else {
2784
42
            None
2785
        }
2786
49
    }
_RNvMsc_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix10child_trie
Line
Count
Source
2775
49
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2776
49
        if let Some((
child_trie_ptr, child_trie_size7
)) = self.child_trie_ptr_size {
2777
7
            let child_trie = self
2778
7
                .inner
2779
7
                .vm
2780
7
                .read_memory(child_trie_ptr, child_trie_size)
2781
7
                .unwrap_or_else(|_| unreachable!());
2782
7
            Some(child_trie)
2783
        } else {
2784
42
            None
2785
        }
2786
49
    }
Unexecuted instantiation: _RNvMsc_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix10child_trie
2787
2788
    /// Returns the maximum number of keys to remove. `None` means "infinity".
2789
9
    pub fn max_keys_to_remove(&self) -> Option<u32> {
2790
9
        self.max_keys_to_remove
2791
9
    }
_RNvMsc_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix18max_keys_to_remove
Line
Count
Source
2789
9
    pub fn max_keys_to_remove(&self) -> Option<u32> {
2790
9
        self.max_keys_to_remove
2791
9
    }
Unexecuted instantiation: _RNvMsc_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix18max_keys_to_remove
2792
2793
    /// Resumes execution after having cleared the values.
2794
    ///
2795
    /// Must be passed how many keys have been cleared, and whether some keys remaining to be
2796
    /// cleared.
2797
6
    pub fn resume(self, num_cleared: u32, some_keys_remain: bool) -> HostVm {
2798
6
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2799
6
            FunctionImport::Resolved(f) => f,
2800
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2801
        };
2802
2803
6
        match host_fn {
2804
            HostFunction::ext_storage_clear_prefix_version_1
2805
            | HostFunction::ext_default_child_storage_clear_prefix_version_1
2806
            | HostFunction::ext_default_child_storage_storage_kill_version_1 => {
2807
1
                HostVm::ReadyToRun(ReadyToRun {
2808
1
                    inner: self.inner,
2809
1
                    resume_value: None,
2810
1
                })
2811
            }
2812
            HostFunction::ext_default_child_storage_storage_kill_version_2 => {
2813
                HostVm::ReadyToRun(ReadyToRun {
2814
0
                    inner: self.inner,
2815
0
                    resume_value: Some(vm::WasmValue::I32(if some_keys_remain { 0 } else { 1 })),
2816
                })
2817
            }
2818
            HostFunction::ext_storage_clear_prefix_version_2
2819
            | HostFunction::ext_default_child_storage_clear_prefix_version_2
2820
            | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
2821
5
                self.inner.alloc_write_and_return_pointer_size(
2822
5
                    host_fn.name(),
2823
5
                    [
2824
5
                        either::Left(if some_keys_remain { 
[1u8]0
} else { [0u8] }),
2825
5
                        either::Right(num_cleared.to_le_bytes()),
2826
5
                    ]
2827
5
                    .into_iter(),
2828
                )
2829
            }
2830
0
            _ => unreachable!(),
2831
        }
2832
6
    }
_RNvMsc_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix6resume
Line
Count
Source
2797
6
    pub fn resume(self, num_cleared: u32, some_keys_remain: bool) -> HostVm {
2798
6
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2799
6
            FunctionImport::Resolved(f) => f,
2800
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2801
        };
2802
2803
6
        match host_fn {
2804
            HostFunction::ext_storage_clear_prefix_version_1
2805
            | HostFunction::ext_default_child_storage_clear_prefix_version_1
2806
            | HostFunction::ext_default_child_storage_storage_kill_version_1 => {
2807
1
                HostVm::ReadyToRun(ReadyToRun {
2808
1
                    inner: self.inner,
2809
1
                    resume_value: None,
2810
1
                })
2811
            }
2812
            HostFunction::ext_default_child_storage_storage_kill_version_2 => {
2813
                HostVm::ReadyToRun(ReadyToRun {
2814
0
                    inner: self.inner,
2815
0
                    resume_value: Some(vm::WasmValue::I32(if some_keys_remain { 0 } else { 1 })),
2816
                })
2817
            }
2818
            HostFunction::ext_storage_clear_prefix_version_2
2819
            | HostFunction::ext_default_child_storage_clear_prefix_version_2
2820
            | HostFunction::ext_default_child_storage_storage_kill_version_3 => {
2821
5
                self.inner.alloc_write_and_return_pointer_size(
2822
5
                    host_fn.name(),
2823
5
                    [
2824
5
                        either::Left(if some_keys_remain { 
[1u8]0
} else { [0u8] }),
2825
5
                        either::Right(num_cleared.to_le_bytes()),
2826
5
                    ]
2827
5
                    .into_iter(),
2828
                )
2829
            }
2830
0
            _ => unreachable!(),
2831
        }
2832
6
    }
Unexecuted instantiation: _RNvMsc_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefix6resume
2833
}
2834
2835
impl fmt::Debug for ExternalStorageClearPrefix {
2836
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2837
0
        f.debug_tuple("ExternalStorageClearPrefix").finish()
2838
0
    }
Unexecuted instantiation: _RNvXsd_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefixNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsd_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalStorageClearPrefixNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2839
}
2840
2841
/// Must provide the trie root hash of the storage and write the trie root hash of child tries
2842
/// to the main trie.
2843
///
2844
/// If [`ExternalStorageRoot::child_trie`] returns `Some` and the child trie is non-empty, the
2845
/// trie root hash of the child trie must also be written to the main trie at the key
2846
/// `concat(":child_storage:default:", child_trie)`.
2847
/// If [`ExternalStorageRoot::child_trie`] returns `Some` and the child trie is empty, the entry
2848
/// in the main trie at the key `concat(":child_storage:default:", child_trie)` must be removed.
2849
///
2850
/// If [`ExternalStorageRoot::child_trie`] returns `None`, the same operation as above must be
2851
/// done for every single child trie that has been modified in one way or the other during the
2852
/// runtime call.
2853
pub struct ExternalStorageRoot {
2854
    inner: Box<Inner>,
2855
2856
    /// Function currently being called by the Wasm code. Refers to an index within
2857
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
2858
    calling: usize,
2859
2860
    /// Pointer and size of the child trie, if any. Guaranteed to be in range.
2861
    child_trie_ptr_size: Option<(u32, u32)>,
2862
}
2863
2864
impl ExternalStorageRoot {
2865
    /// Returns the child trie whose root hash must be provided. `None` for the main trie.
2866
20
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2867
20
        if let Some((
ptr, size0
)) = self.child_trie_ptr_size {
2868
0
            let child_trie = self
2869
0
                .inner
2870
0
                .vm
2871
0
                .read_memory(ptr, size)
2872
0
                .unwrap_or_else(|_| unreachable!());
2873
0
            Some(child_trie)
2874
        } else {
2875
20
            None
2876
        }
2877
20
    }
_RNvMse_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_19ExternalStorageRoot10child_trie
Line
Count
Source
2866
20
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2867
20
        if let Some((
ptr, size0
)) = self.child_trie_ptr_size {
2868
0
            let child_trie = self
2869
0
                .inner
2870
0
                .vm
2871
0
                .read_memory(ptr, size)
2872
0
                .unwrap_or_else(|_| unreachable!());
2873
0
            Some(child_trie)
2874
        } else {
2875
20
            None
2876
        }
2877
20
    }
Unexecuted instantiation: _RNvMse_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_19ExternalStorageRoot10child_trie
2878
2879
    /// Writes the trie root hash to the Wasm VM and prepares it for resume.
2880
    ///
2881
    /// If [`ExternalStorageRoot::child_trie`] returns `Some` but the child trie doesn't exist,
2882
    /// the root hash of an empty trie must be provided.
2883
5
    pub fn resume(self, hash: &[u8; 32]) -> HostVm {
2884
5
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2885
5
            FunctionImport::Resolved(f) => f,
2886
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2887
        };
2888
2889
5
        self.inner
2890
5
            .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(hash))
2891
5
    }
_RNvMse_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_19ExternalStorageRoot6resume
Line
Count
Source
2883
5
    pub fn resume(self, hash: &[u8; 32]) -> HostVm {
2884
5
        let host_fn = match self.inner.common.registered_functions[self.calling] {
2885
5
            FunctionImport::Resolved(f) => f,
2886
0
            FunctionImport::Unresolved { .. } => unreachable!(),
2887
        };
2888
2889
5
        self.inner
2890
5
            .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(hash))
2891
5
    }
Unexecuted instantiation: _RNvMse_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_19ExternalStorageRoot6resume
2892
}
2893
2894
impl fmt::Debug for ExternalStorageRoot {
2895
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2896
0
        f.debug_tuple("ExternalStorageRoot").finish()
2897
0
    }
Unexecuted instantiation: _RNvXsf_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_19ExternalStorageRootNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsf_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_19ExternalStorageRootNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2898
}
2899
2900
/// Must provide the storage key that follows, in lexicographic order, a specific one.
2901
pub struct ExternalStorageNextKey {
2902
    inner: Box<Inner>,
2903
2904
    /// Pointer to the key whose follow-up must be found. Guaranteed to be in range.
2905
    key_ptr: u32,
2906
    /// Size of the key whose follow-up must be found. Guaranteed to be in range.
2907
    key_size: u32,
2908
    /// Pointer and size of the child trie, if any. Guaranteed to be in range.
2909
    child_trie_ptr_size: Option<(u32, u32)>,
2910
}
2911
2912
impl ExternalStorageNextKey {
2913
    /// Returns the key whose following key must be returned.
2914
2
    pub fn key(&self) -> impl AsRef<[u8]> {
2915
2
        self.inner
2916
2
            .vm
2917
2
            .read_memory(self.key_ptr, self.key_size)
2918
2
            .unwrap_or_else(|_| unreachable!())
2919
2
    }
_RNvMsg_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_22ExternalStorageNextKey3key
Line
Count
Source
2914
2
    pub fn key(&self) -> impl AsRef<[u8]> {
2915
2
        self.inner
2916
2
            .vm
2917
2
            .read_memory(self.key_ptr, self.key_size)
2918
2
            .unwrap_or_else(|_| unreachable!())
2919
2
    }
Unexecuted instantiation: _RNvMsg_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_22ExternalStorageNextKey3key
2920
2921
    /// If `Some`, read from the given child trie. If `None`, read from the main trie.
2922
3
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2923
3
        if let Some((
child_trie_ptr, child_trie_size0
)) = self.child_trie_ptr_size {
2924
0
            let child_trie = self
2925
0
                .inner
2926
0
                .vm
2927
0
                .read_memory(child_trie_ptr, child_trie_size)
2928
0
                .unwrap_or_else(|_| unreachable!());
2929
0
            Some(child_trie)
2930
        } else {
2931
3
            None
2932
        }
2933
3
    }
_RNvMsg_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_22ExternalStorageNextKey10child_trie
Line
Count
Source
2922
3
    pub fn child_trie(&self) -> Option<impl AsRef<[u8]>> {
2923
3
        if let Some((
child_trie_ptr, child_trie_size0
)) = self.child_trie_ptr_size {
2924
0
            let child_trie = self
2925
0
                .inner
2926
0
                .vm
2927
0
                .read_memory(child_trie_ptr, child_trie_size)
2928
0
                .unwrap_or_else(|_| unreachable!());
2929
0
            Some(child_trie)
2930
        } else {
2931
3
            None
2932
        }
2933
3
    }
Unexecuted instantiation: _RNvMsg_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_22ExternalStorageNextKey10child_trie
2934
2935
    /// Writes the follow-up key in the Wasm VM memory and prepares it for execution.
2936
    ///
2937
    /// Must be passed `None` if the key is the last one in the storage or if
2938
    /// [`ExternalStorageNextKey`] returns `Some` and the child trie doesn't exist.
2939
1
    pub fn resume(self, follow_up: Option<&[u8]>) -> HostVm {
2940
1
        let key = self
2941
1
            .inner
2942
1
            .vm
2943
1
            .read_memory(self.key_ptr, self.key_size)
2944
1
            .unwrap_or_else(|_| unreachable!());
2945
1
2946
1
        match follow_up {
2947
1
            Some(next) => {
2948
1
                debug_assert!(key.as_ref() < next);
2949
2950
1
                let value_len_enc = util::encode_scale_compact_usize(next.len());
2951
1
                drop(key);
2952
1
                self.inner.alloc_write_and_return_pointer_size(
2953
1
                    HostFunction::ext_storage_next_key_version_1.name(), // TODO: no
2954
1
                    iter::once(&[1][..])
2955
1
                        .chain(iter::once(value_len_enc.as_ref()))
2956
1
                        .chain(iter::once(next)),
2957
1
                )
2958
            }
2959
            None => {
2960
                // Write a SCALE-encoded `None`.
2961
0
                drop(key);
2962
0
                self.inner.alloc_write_and_return_pointer_size(
2963
0
                    HostFunction::ext_storage_next_key_version_1.name(), // TODO: no
2964
0
                    iter::once(&[0]),
2965
0
                )
2966
            }
2967
        }
2968
1
    }
_RNvMsg_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_22ExternalStorageNextKey6resume
Line
Count
Source
2939
1
    pub fn resume(self, follow_up: Option<&[u8]>) -> HostVm {
2940
1
        let key = self
2941
1
            .inner
2942
1
            .vm
2943
1
            .read_memory(self.key_ptr, self.key_size)
2944
1
            .unwrap_or_else(|_| unreachable!());
2945
1
2946
1
        match follow_up {
2947
1
            Some(next) => {
2948
1
                debug_assert!(key.as_ref() < next);
2949
2950
1
                let value_len_enc = util::encode_scale_compact_usize(next.len());
2951
1
                drop(key);
2952
1
                self.inner.alloc_write_and_return_pointer_size(
2953
1
                    HostFunction::ext_storage_next_key_version_1.name(), // TODO: no
2954
1
                    iter::once(&[1][..])
2955
1
                        .chain(iter::once(value_len_enc.as_ref()))
2956
1
                        .chain(iter::once(next)),
2957
1
                )
2958
            }
2959
            None => {
2960
                // Write a SCALE-encoded `None`.
2961
0
                drop(key);
2962
0
                self.inner.alloc_write_and_return_pointer_size(
2963
0
                    HostFunction::ext_storage_next_key_version_1.name(), // TODO: no
2964
0
                    iter::once(&[0]),
2965
0
                )
2966
            }
2967
        }
2968
1
    }
Unexecuted instantiation: _RNvMsg_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_22ExternalStorageNextKey6resume
2969
}
2970
2971
impl fmt::Debug for ExternalStorageNextKey {
2972
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2973
0
        f.debug_tuple("ExternalStorageNextKey").finish()
2974
0
    }
Unexecuted instantiation: _RNvXsh_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_22ExternalStorageNextKeyNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsh_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_22ExternalStorageNextKeyNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
2975
}
2976
2977
/// Must verify whether a signature is correct.
2978
pub struct SignatureVerification {
2979
    inner: Box<Inner>,
2980
    /// Which cryptographic algorithm.
2981
    algorithm: SignatureVerificationAlgorithm,
2982
    /// Pointer to the signature. The size of the signature depends on the algorithm. Guaranteed
2983
    /// to be in range.
2984
    signature_ptr: u32,
2985
    /// Pointer to the public key. The size of the public key depends on the algorithm. Guaranteed
2986
    /// to be in range.
2987
    public_key_ptr: u32,
2988
    /// Pointer to the message. Guaranteed to be in range.
2989
    message_ptr: u32,
2990
    /// Size of the message. Guaranteed to be in range.
2991
    message_size: u32,
2992
    /// `true` if the host function is a batch verification function.
2993
    is_batch_verification: bool,
2994
}
2995
2996
enum SignatureVerificationAlgorithm {
2997
    Ed25519,
2998
    Sr25519V1,
2999
    Sr25519V2,
3000
    Ecdsa,
3001
    EcdsaPrehashed,
3002
}
3003
3004
impl SignatureVerification {
3005
    /// Returns the message that the signature is expected to sign.
3006
6
    pub fn message(&self) -> impl AsRef<[u8]> {
3007
6
        self.inner
3008
6
            .vm
3009
6
            .read_memory(self.message_ptr, self.message_size)
3010
6
            .unwrap_or_else(|_| unreachable!())
3011
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification7message
Line
Count
Source
3006
6
    pub fn message(&self) -> impl AsRef<[u8]> {
3007
6
        self.inner
3008
6
            .vm
3009
6
            .read_memory(self.message_ptr, self.message_size)
3010
6
            .unwrap_or_else(|_| unreachable!())
3011
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification7message
3012
3013
    /// Returns the signature.
3014
    ///
3015
    /// > **Note**: Be aware that this signature is untrusted input and might not be part of the
3016
    /// >           set of valid signatures.
3017
6
    pub fn signature(&self) -> impl AsRef<[u8]> {
3018
6
        let signature_size = match self.algorithm {
3019
0
            SignatureVerificationAlgorithm::Ed25519 => 64,
3020
0
            SignatureVerificationAlgorithm::Sr25519V1 => 64,
3021
6
            SignatureVerificationAlgorithm::Sr25519V2 => 64,
3022
0
            SignatureVerificationAlgorithm::Ecdsa => 65,
3023
0
            SignatureVerificationAlgorithm::EcdsaPrehashed => 65,
3024
        };
3025
3026
6
        self.inner
3027
6
            .vm
3028
6
            .read_memory(self.signature_ptr, signature_size)
3029
6
            .unwrap_or_else(|_| unreachable!())
3030
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification9signature
Line
Count
Source
3017
6
    pub fn signature(&self) -> impl AsRef<[u8]> {
3018
6
        let signature_size = match self.algorithm {
3019
0
            SignatureVerificationAlgorithm::Ed25519 => 64,
3020
0
            SignatureVerificationAlgorithm::Sr25519V1 => 64,
3021
6
            SignatureVerificationAlgorithm::Sr25519V2 => 64,
3022
0
            SignatureVerificationAlgorithm::Ecdsa => 65,
3023
0
            SignatureVerificationAlgorithm::EcdsaPrehashed => 65,
3024
        };
3025
3026
6
        self.inner
3027
6
            .vm
3028
6
            .read_memory(self.signature_ptr, signature_size)
3029
6
            .unwrap_or_else(|_| unreachable!())
3030
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification9signature
3031
3032
    /// Returns the public key the signature is against.
3033
    ///
3034
    /// > **Note**: Be aware that this public key is untrusted input and might not be part of the
3035
    /// >           set of valid public keys.
3036
6
    pub fn public_key(&self) -> impl AsRef<[u8]> {
3037
6
        let public_key_size = match self.algorithm {
3038
0
            SignatureVerificationAlgorithm::Ed25519 => 32,
3039
0
            SignatureVerificationAlgorithm::Sr25519V1 => 32,
3040
6
            SignatureVerificationAlgorithm::Sr25519V2 => 32,
3041
0
            SignatureVerificationAlgorithm::Ecdsa => 33,
3042
0
            SignatureVerificationAlgorithm::EcdsaPrehashed => 33,
3043
        };
3044
3045
6
        self.inner
3046
6
            .vm
3047
6
            .read_memory(self.public_key_ptr, public_key_size)
3048
6
            .unwrap_or_else(|_| unreachable!())
3049
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification10public_key
Line
Count
Source
3036
6
    pub fn public_key(&self) -> impl AsRef<[u8]> {
3037
6
        let public_key_size = match self.algorithm {
3038
0
            SignatureVerificationAlgorithm::Ed25519 => 32,
3039
0
            SignatureVerificationAlgorithm::Sr25519V1 => 32,
3040
6
            SignatureVerificationAlgorithm::Sr25519V2 => 32,
3041
0
            SignatureVerificationAlgorithm::Ecdsa => 33,
3042
0
            SignatureVerificationAlgorithm::EcdsaPrehashed => 33,
3043
        };
3044
3045
6
        self.inner
3046
6
            .vm
3047
6
            .read_memory(self.public_key_ptr, public_key_size)
3048
6
            .unwrap_or_else(|_| unreachable!())
3049
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification10public_key
3050
3051
    /// Verify the signature. Returns `true` if it is valid.
3052
6
    pub fn is_valid(&self) -> bool {
3053
6
        match self.algorithm {
3054
            SignatureVerificationAlgorithm::Ed25519 => {
3055
0
                let public_key =
3056
0
                    ed25519_zebra::VerificationKey::try_from(self.public_key().as_ref());
3057
3058
0
                if let Ok(public_key) = public_key {
3059
0
                    let signature = ed25519_zebra::Signature::from(
3060
0
                        <[u8; 64]>::try_from(self.signature().as_ref())
3061
0
                            .unwrap_or_else(|_| unreachable!()),
3062
0
                    );
3063
0
                    public_key
3064
0
                        .verify(&signature, self.message().as_ref())
3065
0
                        .is_ok()
3066
                } else {
3067
0
                    false
3068
                }
3069
            }
3070
            SignatureVerificationAlgorithm::Sr25519V1 => {
3071
0
                schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3072
0
                    pk.verify_simple_preaudit_deprecated(
3073
0
                        b"substrate",
3074
0
                        self.message().as_ref(),
3075
0
                        self.signature().as_ref(),
3076
0
                    )
3077
0
                    .is_ok()
3078
0
                })
Unexecuted instantiation: _RNCNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids_0Bb_
Unexecuted instantiation: _RNCNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids_0Bb_
3079
            }
3080
            SignatureVerificationAlgorithm::Sr25519V2 => {
3081
6
                schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3082
6
                    pk.verify_simple(
3083
6
                        b"substrate",
3084
6
                        self.message().as_ref(),
3085
6
                        &schnorrkel::Signature::from_bytes(self.signature().as_ref())
3086
6
                            .unwrap_or_else(|_| unreachable!()),
3087
6
                    )
3088
6
                    .is_ok()
3089
6
                })
_RNCNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids0_0Bb_
Line
Count
Source
3081
6
                schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3082
6
                    pk.verify_simple(
3083
6
                        b"substrate",
3084
6
                        self.message().as_ref(),
3085
6
                        &schnorrkel::Signature::from_bytes(self.signature().as_ref())
3086
6
                            .unwrap_or_else(|_| unreachable!()),
3087
6
                    )
3088
6
                    .is_ok()
3089
6
                })
Unexecuted instantiation: _RNCNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids0_0Bb_
3090
            }
3091
            SignatureVerificationAlgorithm::Ecdsa => {
3092
                // NOTE: safe to unwrap here because we supply the nn to blake2b fn
3093
0
                let data = <[u8; 32]>::try_from(
3094
0
                    blake2_rfc::blake2b::blake2b(32, &[], self.message().as_ref()).as_bytes(),
3095
0
                )
3096
0
                .unwrap_or_else(|_| unreachable!());
3097
0
                let message = libsecp256k1::Message::parse(&data);
3098
0
3099
0
                // signature (64 bytes) + recovery ID (1 byte)
3100
0
                let sig_bytes = self.signature();
3101
0
                libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3102
0
                    .and_then(|sig| {
3103
0
                        libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64])
3104
0
                            .and_then(|ri| libsecp256k1::recover(&message, &sig, &ri))
Unexecuted instantiation: _RNCNCNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB9_21SignatureVerification8is_valids2_00Bd_
Unexecuted instantiation: _RNCNCNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB9_21SignatureVerification8is_valids2_00Bd_
3105
0
                    })
Unexecuted instantiation: _RNCNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids2_0Bb_
Unexecuted instantiation: _RNCNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids2_0Bb_
3106
0
                    .map_or(false, |actual| {
3107
0
                        self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3108
0
                    })
Unexecuted instantiation: _RNCNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids3_0Bb_
Unexecuted instantiation: _RNCNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB7_21SignatureVerification8is_valids3_0Bb_
3109
            }
3110
            SignatureVerificationAlgorithm::EcdsaPrehashed => {
3111
                // We can safely unwrap, as the size is checked when the `SignatureVerification`
3112
                // is constructed.
3113
0
                let message = libsecp256k1::Message::parse(
3114
0
                    &<[u8; 32]>::try_from(self.message().as_ref())
3115
0
                        .unwrap_or_else(|_| unreachable!()),
3116
0
                );
3117
0
3118
0
                // signature (64 bytes) + recovery ID (1 byte)
3119
0
                let sig_bytes = self.signature();
3120
0
                if let Ok(sig) =
3121
0
                    libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3122
                {
3123
0
                    if let Ok(ri) = libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64]) {
3124
0
                        if let Ok(actual) = libsecp256k1::recover(&message, &sig, &ri) {
3125
0
                            self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3126
                        } else {
3127
0
                            false
3128
                        }
3129
                    } else {
3130
0
                        false
3131
                    }
3132
                } else {
3133
0
                    false
3134
                }
3135
            }
3136
        }
3137
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification8is_valid
Line
Count
Source
3052
6
    pub fn is_valid(&self) -> bool {
3053
6
        match self.algorithm {
3054
            SignatureVerificationAlgorithm::Ed25519 => {
3055
0
                let public_key =
3056
0
                    ed25519_zebra::VerificationKey::try_from(self.public_key().as_ref());
3057
3058
0
                if let Ok(public_key) = public_key {
3059
0
                    let signature = ed25519_zebra::Signature::from(
3060
0
                        <[u8; 64]>::try_from(self.signature().as_ref())
3061
0
                            .unwrap_or_else(|_| unreachable!()),
3062
0
                    );
3063
0
                    public_key
3064
0
                        .verify(&signature, self.message().as_ref())
3065
0
                        .is_ok()
3066
                } else {
3067
0
                    false
3068
                }
3069
            }
3070
            SignatureVerificationAlgorithm::Sr25519V1 => {
3071
0
                schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3072
                    pk.verify_simple_preaudit_deprecated(
3073
                        b"substrate",
3074
                        self.message().as_ref(),
3075
                        self.signature().as_ref(),
3076
                    )
3077
                    .is_ok()
3078
0
                })
3079
            }
3080
            SignatureVerificationAlgorithm::Sr25519V2 => {
3081
6
                schnorrkel::PublicKey::from_bytes(self.public_key().as_ref()).map_or(false, |pk| {
3082
                    pk.verify_simple(
3083
                        b"substrate",
3084
                        self.message().as_ref(),
3085
                        &schnorrkel::Signature::from_bytes(self.signature().as_ref())
3086
                            .unwrap_or_else(|_| unreachable!()),
3087
                    )
3088
                    .is_ok()
3089
6
                })
3090
            }
3091
            SignatureVerificationAlgorithm::Ecdsa => {
3092
                // NOTE: safe to unwrap here because we supply the nn to blake2b fn
3093
0
                let data = <[u8; 32]>::try_from(
3094
0
                    blake2_rfc::blake2b::blake2b(32, &[], self.message().as_ref()).as_bytes(),
3095
0
                )
3096
0
                .unwrap_or_else(|_| unreachable!());
3097
0
                let message = libsecp256k1::Message::parse(&data);
3098
0
3099
0
                // signature (64 bytes) + recovery ID (1 byte)
3100
0
                let sig_bytes = self.signature();
3101
0
                libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3102
0
                    .and_then(|sig| {
3103
                        libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64])
3104
                            .and_then(|ri| libsecp256k1::recover(&message, &sig, &ri))
3105
0
                    })
3106
0
                    .map_or(false, |actual| {
3107
                        self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3108
0
                    })
3109
            }
3110
            SignatureVerificationAlgorithm::EcdsaPrehashed => {
3111
                // We can safely unwrap, as the size is checked when the `SignatureVerification`
3112
                // is constructed.
3113
0
                let message = libsecp256k1::Message::parse(
3114
0
                    &<[u8; 32]>::try_from(self.message().as_ref())
3115
0
                        .unwrap_or_else(|_| unreachable!()),
3116
0
                );
3117
0
3118
0
                // signature (64 bytes) + recovery ID (1 byte)
3119
0
                let sig_bytes = self.signature();
3120
0
                if let Ok(sig) =
3121
0
                    libsecp256k1::Signature::parse_standard_slice(&sig_bytes.as_ref()[..64])
3122
                {
3123
0
                    if let Ok(ri) = libsecp256k1::RecoveryId::parse(sig_bytes.as_ref()[64]) {
3124
0
                        if let Ok(actual) = libsecp256k1::recover(&message, &sig, &ri) {
3125
0
                            self.public_key().as_ref()[..] == actual.serialize_compressed()[..]
3126
                        } else {
3127
0
                            false
3128
                        }
3129
                    } else {
3130
0
                        false
3131
                    }
3132
                } else {
3133
0
                    false
3134
                }
3135
            }
3136
        }
3137
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification8is_valid
3138
3139
    /// Verify the signature and resume execution.
3140
6
    pub fn verify_and_resume(self) -> HostVm {
3141
6
        let success = self.is_valid();
3142
6
        self.resume(success)
3143
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification17verify_and_resume
Line
Count
Source
3140
6
    pub fn verify_and_resume(self) -> HostVm {
3141
6
        let success = self.is_valid();
3142
6
        self.resume(success)
3143
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification17verify_and_resume
3144
3145
    /// Resume the execution assuming that the signature is valid.
3146
    ///
3147
    /// > **Note**: You are strongly encouraged to call
3148
    /// >           [`SignatureVerification::verify_and_resume`]. This function is meant to be
3149
    /// >           used only in debugging situations.
3150
0
    pub fn resume_success(self) -> HostVm {
3151
0
        self.resume(true)
3152
0
    }
Unexecuted instantiation: _RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification14resume_success
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification14resume_success
3153
3154
    /// Resume the execution assuming that the signature is invalid.
3155
    ///
3156
    /// > **Note**: You are strongly encouraged to call
3157
    /// >           [`SignatureVerification::verify_and_resume`]. This function is meant to be
3158
    /// >           used only in debugging situations.
3159
0
    pub fn resume_failed(self) -> HostVm {
3160
0
        self.resume(false)
3161
0
    }
Unexecuted instantiation: _RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification13resume_failed
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification13resume_failed
3162
3163
6
    fn resume(mut self, success: bool) -> HostVm {
3164
6
        debug_assert!(
3165
6
            !self.is_batch_verification || 
self.inner.signatures_batch_verification.is_some()0
3166
        );
3167
6
        if self.is_batch_verification && 
!success0
{
3168
0
            self.inner.signatures_batch_verification = Some(false);
3169
6
        }
3170
3171
        // All signature-related host functions work the same way in terms of return value.
3172
        HostVm::ReadyToRun(ReadyToRun {
3173
6
            resume_value: Some(vm::WasmValue::I32(if success { 1 } else { 
00
})),
3174
6
            inner: self.inner,
3175
6
        })
3176
6
    }
_RNvMsi_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerification6resume
Line
Count
Source
3163
6
    fn resume(mut self, success: bool) -> HostVm {
3164
6
        debug_assert!(
3165
6
            !self.is_batch_verification || 
self.inner.signatures_batch_verification.is_some()0
3166
        );
3167
6
        if self.is_batch_verification && 
!success0
{
3168
0
            self.inner.signatures_batch_verification = Some(false);
3169
6
        }
3170
3171
        // All signature-related host functions work the same way in terms of return value.
3172
        HostVm::ReadyToRun(ReadyToRun {
3173
6
            resume_value: Some(vm::WasmValue::I32(if success { 1 } else { 
00
})),
3174
6
            inner: self.inner,
3175
6
        })
3176
6
    }
Unexecuted instantiation: _RNvMsi_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerification6resume
3177
}
3178
3179
impl fmt::Debug for SignatureVerification {
3180
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3181
0
        f.debug_struct("SignatureVerification")
3182
0
            .field("message", &self.message().as_ref())
3183
0
            .field("signature", &self.signature().as_ref())
3184
0
            .field("public_key", &self.public_key().as_ref())
3185
0
            .finish()
3186
0
    }
Unexecuted instantiation: _RNvXsj_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21SignatureVerificationNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsj_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21SignatureVerificationNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3187
}
3188
3189
/// Must provide the runtime version obtained by calling the `Core_version` entry point of a Wasm
3190
/// blob.
3191
pub struct CallRuntimeVersion {
3192
    inner: Box<Inner>,
3193
3194
    /// Pointer to the wasm code whose runtime version must be provided. Guaranteed to be in range.
3195
    wasm_blob_ptr: u32,
3196
    /// Size of the wasm code whose runtime version must be provided. Guaranteed to be in range.
3197
    wasm_blob_size: u32,
3198
}
3199
3200
impl CallRuntimeVersion {
3201
    /// Returns the Wasm code whose runtime version must be provided.
3202
0
    pub fn wasm_code(&self) -> impl AsRef<[u8]> {
3203
0
        self.inner
3204
0
            .vm
3205
0
            .read_memory(self.wasm_blob_ptr, self.wasm_blob_size)
3206
0
            .unwrap_or_else(|_| unreachable!())
3207
0
    }
Unexecuted instantiation: _RNvMsk_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18CallRuntimeVersion9wasm_code
Unexecuted instantiation: _RNvMsk_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18CallRuntimeVersion9wasm_code
3208
3209
    /// Writes the SCALE-encoded runtime version to the memory and prepares for execution.
3210
    ///
3211
    /// If an error happened during the execution (such as an invalid Wasm binary code), pass
3212
    /// an `Err`.
3213
0
    pub fn resume(self, scale_encoded_runtime_version: Result<&[u8], ()>) -> HostVm {
3214
0
        if let Ok(scale_encoded_runtime_version) = scale_encoded_runtime_version {
3215
0
            self.inner.alloc_write_and_return_pointer_size(
3216
0
                HostFunction::ext_misc_runtime_version_version_1.name(),
3217
0
                iter::once(either::Left([1]))
3218
0
                    .chain(iter::once(either::Right(either::Left(
3219
0
                        util::encode_scale_compact_usize(scale_encoded_runtime_version.len()),
3220
0
                    ))))
3221
0
                    .chain(iter::once(either::Right(either::Right(
3222
0
                        scale_encoded_runtime_version,
3223
0
                    )))),
3224
0
            )
3225
        } else {
3226
0
            self.inner.alloc_write_and_return_pointer_size(
3227
0
                HostFunction::ext_misc_runtime_version_version_1.name(),
3228
0
                iter::once([0]),
3229
0
            )
3230
        }
3231
0
    }
Unexecuted instantiation: _RNvMsk_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18CallRuntimeVersion6resume
Unexecuted instantiation: _RNvMsk_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18CallRuntimeVersion6resume
3232
}
3233
3234
impl fmt::Debug for CallRuntimeVersion {
3235
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3236
0
        f.debug_tuple("CallRuntimeVersion").finish()
3237
0
    }
Unexecuted instantiation: _RNvXsl_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18CallRuntimeVersionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsl_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18CallRuntimeVersionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3238
}
3239
3240
/// Must set off-chain index value.
3241
pub struct ExternalOffchainIndexSet {
3242
    inner: Box<Inner>,
3243
3244
    /// Pointer to the key whose value must be set. Guaranteed to be in range.
3245
    key_ptr: u32,
3246
    /// Size of the key whose value must be set. Guaranteed to be in range.
3247
    key_size: u32,
3248
3249
    /// Pointer and size of the value to set. `None` for clearing. Guaranteed to be in range.
3250
    value: Option<(u32, u32)>,
3251
}
3252
3253
impl ExternalOffchainIndexSet {
3254
    /// Returns the key whose value must be set.
3255
0
    pub fn key(&self) -> impl AsRef<[u8]> {
3256
0
        self.inner
3257
0
            .vm
3258
0
            .read_memory(self.key_ptr, self.key_size)
3259
0
            .unwrap_or_else(|_| unreachable!())
3260
0
    }
Unexecuted instantiation: _RNvMsm_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet3key
Unexecuted instantiation: _RNvMsm_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet3key
3261
3262
    /// Returns the value to set.
3263
    ///
3264
    /// If `None` is returned, the key should be removed from the storage entirely.
3265
0
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
3266
0
        if let Some((ptr, size)) = self.value {
3267
0
            Some(
3268
0
                self.inner
3269
0
                    .vm
3270
0
                    .read_memory(ptr, size)
3271
0
                    .unwrap_or_else(|_| unreachable!()),
3272
0
            )
3273
        } else {
3274
0
            None
3275
        }
3276
0
    }
Unexecuted instantiation: _RNvMsm_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet5value
Unexecuted instantiation: _RNvMsm_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet5value
3277
3278
    /// Resumes execution after having set the value.
3279
0
    pub fn resume(self) -> HostVm {
3280
0
        HostVm::ReadyToRun(ReadyToRun {
3281
0
            inner: self.inner,
3282
0
            resume_value: None,
3283
0
        })
3284
0
    }
Unexecuted instantiation: _RNvMsm_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet6resume
Unexecuted instantiation: _RNvMsm_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSet6resume
3285
}
3286
3287
impl fmt::Debug for ExternalOffchainIndexSet {
3288
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3289
0
        f.debug_tuple("ExternalOffchainIndexSet").finish()
3290
0
    }
Unexecuted instantiation: _RNvXsn_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsn_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_24ExternalOffchainIndexSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3291
}
3292
3293
/// Must set the value of the off-chain storage.
3294
pub struct ExternalOffchainStorageSet {
3295
    inner: Box<Inner>,
3296
3297
    /// Pointer to the key whose value must be set. Guaranteed to be in range.
3298
    key_ptr: u32,
3299
    /// Size of the key whose value must be set. Guaranteed to be in range.
3300
    key_size: u32,
3301
3302
    /// Pointer and size of the value to set. `None` for clearing. Guaranteed to be in range.
3303
    value: Option<(u32, u32)>,
3304
3305
    /// Pointer and size of the old value to compare. Guaranteed to be in range.
3306
    old_value: Option<(u32, u32)>,
3307
}
3308
3309
impl ExternalOffchainStorageSet {
3310
    /// Returns the key whose value must be set.
3311
0
    pub fn key(&self) -> impl AsRef<[u8]> {
3312
0
        self.inner
3313
0
            .vm
3314
0
            .read_memory(self.key_ptr, self.key_size)
3315
0
            .unwrap_or_else(|_| unreachable!())
3316
0
    }
Unexecuted instantiation: _RNvMso_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet3key
Unexecuted instantiation: _RNvMso_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet3key
3317
3318
    /// Returns the value to set.
3319
    ///
3320
    /// If `None` is returned, the key should be removed from the storage entirely.
3321
0
    pub fn value(&self) -> Option<impl AsRef<[u8]>> {
3322
0
        if let Some((ptr, size)) = self.value {
3323
0
            Some(
3324
0
                self.inner
3325
0
                    .vm
3326
0
                    .read_memory(ptr, size)
3327
0
                    .unwrap_or_else(|_| unreachable!()),
3328
0
            )
3329
        } else {
3330
0
            None
3331
        }
3332
0
    }
Unexecuted instantiation: _RNvMso_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet5value
Unexecuted instantiation: _RNvMso_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet5value
3333
3334
    /// Returns the value the current value should be compared against. The operation is a no-op if they don't compare equal.
3335
0
    pub fn old_value(&self) -> Option<impl AsRef<[u8]>> {
3336
0
        if let Some((ptr, size)) = self.old_value {
3337
0
            Some(
3338
0
                self.inner
3339
0
                    .vm
3340
0
                    .read_memory(ptr, size)
3341
0
                    .unwrap_or_else(|_| unreachable!()),
3342
0
            )
3343
        } else {
3344
0
            None
3345
        }
3346
0
    }
Unexecuted instantiation: _RNvMso_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet9old_value
Unexecuted instantiation: _RNvMso_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet9old_value
3347
3348
    /// Resumes execution after having set the value. Must indicate whether a value was written.
3349
0
    pub fn resume(self, replaced: bool) -> HostVm {
3350
0
        if self.old_value.is_some() {
3351
            HostVm::ReadyToRun(ReadyToRun {
3352
0
                inner: self.inner,
3353
0
                resume_value: Some(vm::WasmValue::I32(if replaced { 1 } else { 0 })),
3354
            })
3355
        } else {
3356
0
            HostVm::ReadyToRun(ReadyToRun {
3357
0
                inner: self.inner,
3358
0
                resume_value: None,
3359
0
            })
3360
        }
3361
0
    }
Unexecuted instantiation: _RNvMso_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet6resume
Unexecuted instantiation: _RNvMso_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSet6resume
3362
}
3363
3364
impl fmt::Debug for ExternalOffchainStorageSet {
3365
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3366
0
        f.debug_tuple("ExternalOffchainStorageSet").finish()
3367
0
    }
Unexecuted instantiation: _RNvXsp_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsp_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageSetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3368
}
3369
3370
/// Must get the value of the off-chain storage.
3371
pub struct ExternalOffchainStorageGet {
3372
    inner: Box<Inner>,
3373
3374
    /// Function currently being called by the Wasm code. Refers to an index within
3375
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
3376
    calling: usize,
3377
3378
    /// Pointer to the key whose value must be loaded. Guaranteed to be in range.
3379
    key_ptr: u32,
3380
    /// Size of the key whose value must be loaded. Guaranteed to be in range.
3381
    key_size: u32,
3382
}
3383
3384
impl ExternalOffchainStorageGet {
3385
    /// Returns the key whose value must be loaded.
3386
0
    pub fn key(&self) -> impl AsRef<[u8]> {
3387
0
        self.inner
3388
0
            .vm
3389
0
            .read_memory(self.key_ptr, self.key_size)
3390
0
            .unwrap_or_else(|_| unreachable!())
3391
0
    }
Unexecuted instantiation: _RNvMsq_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGet3key
Unexecuted instantiation: _RNvMsq_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGet3key
3392
3393
    /// Resumes execution after having set the value.
3394
0
    pub fn resume(self, value: Option<&[u8]>) -> HostVm {
3395
0
        let host_fn = match self.inner.common.registered_functions[self.calling] {
3396
0
            FunctionImport::Resolved(f) => f,
3397
0
            FunctionImport::Unresolved { .. } => unreachable!(),
3398
        };
3399
3400
0
        if let Some(value) = value {
3401
0
            let value_len_enc = util::encode_scale_compact_usize(value.len());
3402
0
            self.inner.alloc_write_and_return_pointer_size(
3403
0
                host_fn.name(),
3404
0
                iter::once(&[1][..])
3405
0
                    .chain(iter::once(value_len_enc.as_ref()))
3406
0
                    .map(either::Left)
3407
0
                    .chain(iter::once(value).map(either::Right)),
3408
0
            )
3409
        } else {
3410
            // Write a SCALE-encoded `None`.
3411
0
            self.inner
3412
0
                .alloc_write_and_return_pointer_size(host_fn.name(), iter::once(&[0]))
3413
        }
3414
0
    }
Unexecuted instantiation: _RNvMsq_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGet6resume
Unexecuted instantiation: _RNvMsq_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGet6resume
3415
}
3416
3417
impl fmt::Debug for ExternalOffchainStorageGet {
3418
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3419
0
        f.debug_tuple("ExternalOffchainStorageGet").finish()
3420
0
    }
Unexecuted instantiation: _RNvXsr_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsr_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_26ExternalOffchainStorageGetNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3421
}
3422
3423
/// Must return the current UNIX timestamp.
3424
pub struct OffchainTimestamp {
3425
    inner: Box<Inner>,
3426
}
3427
3428
impl OffchainTimestamp {
3429
    /// Resumes execution after having set the value.
3430
0
    pub fn resume(self, value: u64) -> HostVm {
3431
0
        HostVm::ReadyToRun(ReadyToRun {
3432
0
            inner: self.inner,
3433
0
            resume_value: Some(vm::WasmValue::I64(i64::from_ne_bytes(value.to_ne_bytes()))),
3434
0
        })
3435
0
    }
Unexecuted instantiation: _RNvMss_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_17OffchainTimestamp6resume
Unexecuted instantiation: _RNvMss_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_17OffchainTimestamp6resume
3436
}
3437
3438
impl fmt::Debug for OffchainTimestamp {
3439
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3440
0
        f.debug_tuple("OffchainTimestamp").finish()
3441
0
    }
Unexecuted instantiation: _RNvXst_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_17OffchainTimestampNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXst_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_17OffchainTimestampNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3442
}
3443
3444
/// Must provide a randomly-generate number.
3445
pub struct OffchainRandomSeed {
3446
    inner: Box<Inner>,
3447
3448
    /// Function currently being called by the Wasm code. Refers to an index within
3449
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
3450
    calling: usize,
3451
}
3452
3453
impl OffchainRandomSeed {
3454
    /// Resumes execution after having set the value.
3455
0
    pub fn resume(self, value: [u8; 32]) -> HostVm {
3456
0
        let host_fn = match self.inner.common.registered_functions[self.calling] {
3457
0
            FunctionImport::Resolved(f) => f,
3458
0
            FunctionImport::Unresolved { .. } => unreachable!(),
3459
        };
3460
0
        self.inner
3461
0
            .alloc_write_and_return_pointer(host_fn.name(), iter::once(value))
3462
0
    }
Unexecuted instantiation: _RNvMsu_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18OffchainRandomSeed6resume
Unexecuted instantiation: _RNvMsu_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18OffchainRandomSeed6resume
3463
}
3464
3465
impl fmt::Debug for OffchainRandomSeed {
3466
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3467
0
        f.debug_tuple("OffchainRandomSeed").finish()
3468
0
    }
Unexecuted instantiation: _RNvXsv_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_18OffchainRandomSeedNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsv_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_18OffchainRandomSeedNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3469
}
3470
3471
/// Must submit an off-chain transaction.
3472
pub struct OffchainSubmitTransaction {
3473
    inner: Box<Inner>,
3474
3475
    /// Function currently being called by the Wasm code. Refers to an index within
3476
    /// [`VmCommon::registered_functions`]. Guaranteed to be [`FunctionImport::Resolved`̀].
3477
    calling: usize,
3478
3479
    /// Pointer to the transaction whose value must be set. Guaranteed to be in range.
3480
    tx_ptr: u32,
3481
3482
    /// Size of the transaction whose value must be set. Guaranteed to be in range.
3483
    tx_size: u32,
3484
}
3485
3486
impl OffchainSubmitTransaction {
3487
    /// Returns the SCALE-encoded transaction to submit to the chain.
3488
0
    pub fn transaction(&self) -> impl AsRef<[u8]> {
3489
0
        self.inner
3490
0
            .vm
3491
0
            .read_memory(self.tx_ptr, self.tx_size)
3492
0
            .unwrap_or_else(|_| unreachable!())
3493
0
    }
Unexecuted instantiation: _RNvMsw_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_25OffchainSubmitTransaction11transaction
Unexecuted instantiation: _RNvMsw_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_25OffchainSubmitTransaction11transaction
3494
3495
    /// Resumes execution after having submitted the transaction.
3496
0
    pub fn resume(self, success: bool) -> HostVm {
3497
0
        let host_fn = match self.inner.common.registered_functions[self.calling] {
3498
0
            FunctionImport::Resolved(f) => f,
3499
0
            FunctionImport::Unresolved { .. } => unreachable!(),
3500
        };
3501
3502
0
        self.inner.alloc_write_and_return_pointer_size(
3503
0
            host_fn.name(),
3504
0
            if success {
3505
0
                iter::once(&[0x00])
3506
            } else {
3507
0
                iter::once(&[0x01])
3508
            },
3509
        )
3510
0
    }
Unexecuted instantiation: _RNvMsw_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_25OffchainSubmitTransaction6resume
Unexecuted instantiation: _RNvMsw_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_25OffchainSubmitTransaction6resume
3511
}
3512
3513
impl fmt::Debug for OffchainSubmitTransaction {
3514
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3515
0
        f.debug_tuple("OffchainSubmitTransaction").finish()
3516
0
    }
Unexecuted instantiation: _RNvXsx_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_25OffchainSubmitTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsx_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_25OffchainSubmitTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3517
}
3518
3519
/// Report about a log entry being emitted.
3520
///
3521
/// Use [`LogEmit::info`] to obtain what must be printed.
3522
pub struct LogEmit {
3523
    inner: Box<Inner>,
3524
    log_entry: LogEmitInner,
3525
}
3526
3527
enum LogEmitInner {
3528
    Num(u64),
3529
    Utf8 {
3530
        /// Pointer to the string. Guaranteed to be in range and to be UTF-8.
3531
        str_ptr: u32,
3532
        /// Size of the string. Guaranteed to be in range and to be UTF-8.
3533
        str_size: u32,
3534
    },
3535
    Hex {
3536
        /// Pointer to the data. Guaranteed to be in range.
3537
        data_ptr: u32,
3538
        /// Size of the data. Guaranteed to be in range.
3539
        data_size: u32,
3540
    },
3541
    Log {
3542
        /// Log level. Arbitrary number indicated by runtime, but typically in the `1..=5` range.
3543
        log_level: u32,
3544
        /// Pointer to the string of the log target. Guaranteed to be in range and to be UTF-8.
3545
        target_str_ptr: u32,
3546
        /// Size of the string of the log target. Guaranteed to be in range and to be UTF-8.
3547
        target_str_size: u32,
3548
        /// Pointer to the string of the log message. Guaranteed to be in range and to be UTF-8.
3549
        msg_str_ptr: u32,
3550
        /// Size of the string of the log message. Guaranteed to be in range and to be UTF-8.
3551
        msg_str_size: u32,
3552
    },
3553
}
3554
3555
impl LogEmit {
3556
    /// Returns the data that the runtime would like to print.
3557
0
    pub fn info(&self) -> LogEmitInfo {
3558
0
        match self.log_entry {
3559
0
            LogEmitInner::Num(n) => LogEmitInfo::Num(n),
3560
0
            LogEmitInner::Utf8 { str_ptr, str_size } => LogEmitInfo::Utf8(LogEmitInfoStr {
3561
0
                data: Box::new(
3562
0
                    self.inner
3563
0
                        .vm
3564
0
                        .read_memory(str_ptr, str_size)
3565
0
                        .unwrap_or_else(|_| unreachable!()),
3566
0
                ),
3567
0
            }),
3568
            LogEmitInner::Hex {
3569
0
                data_ptr,
3570
0
                data_size,
3571
0
            } => LogEmitInfo::Hex(LogEmitInfoHex {
3572
0
                data: Box::new(
3573
0
                    self.inner
3574
0
                        .vm
3575
0
                        .read_memory(data_ptr, data_size)
3576
0
                        .unwrap_or_else(|_| unreachable!()),
3577
0
                ),
3578
0
            }),
3579
            LogEmitInner::Log {
3580
0
                msg_str_ptr,
3581
0
                msg_str_size,
3582
0
                target_str_ptr,
3583
0
                target_str_size,
3584
0
                log_level,
3585
0
            } => LogEmitInfo::Log {
3586
0
                log_level,
3587
0
                target: LogEmitInfoStr {
3588
0
                    data: Box::new(
3589
0
                        self.inner
3590
0
                            .vm
3591
0
                            .read_memory(target_str_ptr, target_str_size)
3592
0
                            .unwrap_or_else(|_| unreachable!()),
3593
0
                    ),
3594
0
                },
3595
0
                message: LogEmitInfoStr {
3596
0
                    data: Box::new(
3597
0
                        self.inner
3598
0
                            .vm
3599
0
                            .read_memory(msg_str_ptr, msg_str_size)
3600
0
                            .unwrap_or_else(|_| unreachable!()),
3601
0
                    ),
3602
0
                },
3603
0
            },
3604
        }
3605
0
    }
Unexecuted instantiation: _RNvMsy_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_7LogEmit4info
Unexecuted instantiation: _RNvMsy_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_7LogEmit4info
3606
3607
    /// Resumes execution.
3608
0
    pub fn resume(self) -> HostVm {
3609
0
        HostVm::ReadyToRun(ReadyToRun {
3610
0
            inner: self.inner,
3611
0
            resume_value: None,
3612
0
        })
3613
0
    }
Unexecuted instantiation: _RNvMsy_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_7LogEmit6resume
Unexecuted instantiation: _RNvMsy_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_7LogEmit6resume
3614
}
3615
3616
impl fmt::Debug for LogEmit {
3617
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3618
0
        f.debug_struct("LogEmit")
3619
0
            .field("info", &self.info())
3620
0
            .finish()
3621
0
    }
Unexecuted instantiation: _RNvXsz_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_7LogEmitNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsz_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_7LogEmitNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3622
}
3623
3624
/// Detail about what a [`LogEmit`] should output. See [`LogEmit::info`].
3625
#[derive(Debug)]
3626
pub enum LogEmitInfo<'a> {
3627
    /// Must output a single number.
3628
    Num(u64),
3629
    /// Must output a UTF-8 string.
3630
    Utf8(LogEmitInfoStr<'a>),
3631
    /// Must output the hexadecimal encoding of the given buffer.
3632
    Hex(LogEmitInfoHex<'a>),
3633
    /// Must output a log line.
3634
    Log {
3635
        /// Log level. Arbitrary number indicated by runtime, but typically in the `1..=5` range.
3636
        log_level: u32,
3637
        /// "Target" of the log. Arbitrary string indicated by the runtime. Typically indicates
3638
        /// the subsystem which has emitted the log line.
3639
        target: LogEmitInfoStr<'a>,
3640
        /// Actual log message being emitted.
3641
        message: LogEmitInfoStr<'a>,
3642
    },
3643
}
3644
3645
/// See [`LogEmitInfo`]. Use the `AsRef` trait implementation to retrieve the buffer.
3646
pub struct LogEmitInfoHex<'a> {
3647
    // TODO: don't use a Box once Rust supports type Foo = impl Trait;
3648
    data: Box<dyn AsRef<[u8]> + Send + Sync + 'a>,
3649
}
3650
3651
impl<'a> AsRef<[u8]> for LogEmitInfoHex<'a> {
3652
0
    fn as_ref(&self) -> &[u8] {
3653
0
        (*self.data).as_ref()
3654
0
    }
Unexecuted instantiation: _RNvXsA_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoHexINtNtCs2va5m0jqTTM_4core7convert5AsRefShE6as_ref
Unexecuted instantiation: _RNvXsA_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoHexINtNtCs2va5m0jqTTM_4core7convert5AsRefShE6as_ref
3655
}
3656
3657
impl<'a> fmt::Debug for LogEmitInfoHex<'a> {
3658
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3659
0
        fmt::Debug::fmt(self.as_ref(), f)
3660
0
    }
Unexecuted instantiation: _RNvXsB_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoHexNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsB_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoHexNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3661
}
3662
3663
impl<'a> fmt::Display for LogEmitInfoHex<'a> {
3664
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3665
0
        fmt::Debug::fmt(&hex::encode(self.as_ref()), f)
3666
0
    }
Unexecuted instantiation: _RNvXsC_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoHexNtNtCs2va5m0jqTTM_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsC_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoHexNtNtCs2va5m0jqTTM_4core3fmt7Display3fmt
3667
}
3668
3669
/// See [`LogEmitInfo`]. Use the `AsRef` trait implementation to retrieve the string.
3670
pub struct LogEmitInfoStr<'a> {
3671
    // TODO: don't use a Box once Rust supports type Foo = impl Trait;
3672
    data: Box<dyn AsRef<[u8]> + Send + Sync + 'a>,
3673
}
3674
3675
impl<'a> AsRef<str> for LogEmitInfoStr<'a> {
3676
0
    fn as_ref(&self) -> &str {
3677
0
        let data = (*self.data).as_ref();
3678
0
        // The creator of `LogEmitInfoStr` always makes sure that the string is indeed UTF-8
3679
0
        // before creating it.
3680
0
        str::from_utf8(data).unwrap_or_else(|_| unreachable!())
3681
0
    }
Unexecuted instantiation: _RNvXsD_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoStrINtNtCs2va5m0jqTTM_4core7convert5AsRefeE6as_ref
Unexecuted instantiation: _RNvXsD_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoStrINtNtCs2va5m0jqTTM_4core7convert5AsRefeE6as_ref
3682
}
3683
3684
impl<'a> fmt::Debug for LogEmitInfoStr<'a> {
3685
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3686
0
        fmt::Debug::fmt(self.as_ref(), f)
3687
0
    }
Unexecuted instantiation: _RNvXsE_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoStrNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsE_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoStrNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3688
}
3689
3690
impl<'a> fmt::Display for LogEmitInfoStr<'a> {
3691
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3692
0
        fmt::Display::fmt(self.as_ref(), f)
3693
0
    }
Unexecuted instantiation: _RNvXsF_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14LogEmitInfoStrNtNtCs2va5m0jqTTM_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsF_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14LogEmitInfoStrNtNtCs2va5m0jqTTM_4core3fmt7Display3fmt
3694
}
3695
3696
/// Queries the maximum log level.
3697
pub struct GetMaxLogLevel {
3698
    inner: Box<Inner>,
3699
}
3700
3701
impl GetMaxLogLevel {
3702
    /// Resumes execution after indicating the maximum log level.
3703
    ///
3704
    /// 0 means off, 1 means error, 2 means warn, 3 means info, 4 means debug, 5 means trace.
3705
136
    pub fn resume(self, max_level: u32) -> HostVm {
3706
136
        HostVm::ReadyToRun(ReadyToRun {
3707
136
            inner: self.inner,
3708
136
            resume_value: Some(vm::WasmValue::I32(i32::from_ne_bytes(
3709
136
                max_level.to_ne_bytes(),
3710
136
            ))),
3711
136
        })
3712
136
    }
_RNvMsG_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14GetMaxLogLevel6resume
Line
Count
Source
3705
9
    pub fn resume(self, max_level: u32) -> HostVm {
3706
9
        HostVm::ReadyToRun(ReadyToRun {
3707
9
            inner: self.inner,
3708
9
            resume_value: Some(vm::WasmValue::I32(i32::from_ne_bytes(
3709
9
                max_level.to_ne_bytes(),
3710
9
            ))),
3711
9
        })
3712
9
    }
_RNvMsG_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14GetMaxLogLevel6resume
Line
Count
Source
3705
127
    pub fn resume(self, max_level: u32) -> HostVm {
3706
127
        HostVm::ReadyToRun(ReadyToRun {
3707
127
            inner: self.inner,
3708
127
            resume_value: Some(vm::WasmValue::I32(i32::from_ne_bytes(
3709
127
                max_level.to_ne_bytes(),
3710
127
            ))),
3711
127
        })
3712
127
    }
3713
}
3714
3715
impl fmt::Debug for GetMaxLogLevel {
3716
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3717
0
        f.debug_tuple("GetMaxLogLevel").finish()
3718
0
    }
Unexecuted instantiation: _RNvXsH_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_14GetMaxLogLevelNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsH_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_14GetMaxLogLevelNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3719
}
3720
3721
/// Declares the start of a transaction.
3722
pub struct StartStorageTransaction {
3723
    inner: Box<Inner>,
3724
}
3725
3726
impl StartStorageTransaction {
3727
    /// Resumes execution after having acknowledged the event.
3728
14
    pub fn resume(self) -> HostVm {
3729
14
        HostVm::ReadyToRun(ReadyToRun {
3730
14
            inner: self.inner,
3731
14
            resume_value: None,
3732
14
        })
3733
14
    }
_RNvMsI_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_23StartStorageTransaction6resume
Line
Count
Source
3728
14
    pub fn resume(self) -> HostVm {
3729
14
        HostVm::ReadyToRun(ReadyToRun {
3730
14
            inner: self.inner,
3731
14
            resume_value: None,
3732
14
        })
3733
14
    }
Unexecuted instantiation: _RNvMsI_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_23StartStorageTransaction6resume
3734
}
3735
3736
impl fmt::Debug for StartStorageTransaction {
3737
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3738
0
        f.debug_tuple("StartStorageTransaction").finish()
3739
0
    }
Unexecuted instantiation: _RNvXsJ_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_23StartStorageTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsJ_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_23StartStorageTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3740
}
3741
3742
/// Declares the end of a transaction.
3743
pub struct EndStorageTransaction {
3744
    inner: Box<Inner>,
3745
}
3746
3747
impl EndStorageTransaction {
3748
    /// Resumes execution after having acknowledged the event.
3749
14
    pub fn resume(self) -> HostVm {
3750
14
        HostVm::ReadyToRun(ReadyToRun {
3751
14
            inner: self.inner,
3752
14
            resume_value: None,
3753
14
        })
3754
14
    }
_RNvMsK_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21EndStorageTransaction6resume
Line
Count
Source
3749
14
    pub fn resume(self) -> HostVm {
3750
14
        HostVm::ReadyToRun(ReadyToRun {
3751
14
            inner: self.inner,
3752
14
            resume_value: None,
3753
14
        })
3754
14
    }
Unexecuted instantiation: _RNvMsK_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21EndStorageTransaction6resume
3755
}
3756
3757
impl fmt::Debug for EndStorageTransaction {
3758
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3759
0
        f.debug_tuple("EndStorageTransaction").finish()
3760
0
    }
Unexecuted instantiation: _RNvXsL_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_21EndStorageTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsL_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_21EndStorageTransactionNtNtCs2va5m0jqTTM_4core3fmt5Debug3fmt
3761
}
3762
3763
#[derive(Clone)]
3764
enum FunctionImport {
3765
    Resolved(HostFunction),
3766
    Unresolved { module: String, name: String },
3767
}
3768
3769
/// Running virtual machine. Shared between all the variants in [`HostVm`].
3770
struct Inner {
3771
    /// Inner lower-level virtual machine.
3772
    vm: vm::VirtualMachine,
3773
3774
    /// The depth of storage transaction started with `ext_storage_start_transaction_version_1`.
3775
    storage_transaction_depth: u32,
3776
3777
    /// The host provides a "batch signature verification" mechanism, where the runtime can start
3778
    /// verifying multiple signatures at once. This mechanism is deprecated, but is emulated
3779
    /// through a simple field.
3780
    ///
3781
    /// Contains `Some` if and only if the runtime is currently within a batch signatures
3782
    /// verification. If `Some`, contains `true` if all the signatures have been verified
3783
    /// successfully so far.
3784
    signatures_batch_verification: Option<bool>,
3785
3786
    /// Memory allocator in order to answer the calls to `malloc` and `free`.
3787
    allocator: allocator::FreeingBumpHeapAllocator,
3788
3789
    /// Value passed as parameter.
3790
    storage_proof_size_behavior: StorageProofSizeBehavior,
3791
3792
    /// Fields that are kept as is even during the execution.
3793
    common: Box<VmCommon>,
3794
}
3795
3796
impl Inner {
3797
    /// Uses the memory allocator to allocate some memory for the given data, writes the data in
3798
    /// memory, and returns an [`HostVm`] ready for the Wasm `host_fn` return.
3799
    ///
3800
    /// The data is passed as a list of chunks. These chunks will be laid out linearly in memory.
3801
    ///
3802
    /// The function name passed as parameter is used for error-reporting reasons.
3803
    ///
3804
    /// # Panic
3805
    ///
3806
    /// Must only be called while the Wasm is handling an `host_fn`.
3807
    ///
3808
683
    fn alloc_write_and_return_pointer_size(
3809
683
        mut self: Box<Self>,
3810
683
        function_name: &'static str,
3811
683
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
683
    ) -> HostVm {
3813
683
        let mut data_len = 0u32;
3814
1.86k
        for chunk in 
data.clone()683
{
3815
1.86k
            data_len =
3816
1.86k
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
1.86k
        }
3818
3819
683
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
683
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
683
        let mut ptr_iter = dest_ptr;
3830
2.55k
        for 
chunk1.86k
in data {
3831
1.86k
            let chunk = chunk.as_ref();
3832
1.86k
            self.vm
3833
1.86k
                .write_memory(ptr_iter, chunk)
3834
1.86k
                .unwrap_or_else(|_| unreachable!());
3835
1.86k
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
1.86k
        }
3837
3838
683
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
683
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
683
3841
683
        ReadyToRun {
3842
683
            inner: self,
3843
683
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
683
        }
3845
683
        .into()
3846
683
    }
Unexecuted instantiation: _RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeAhj1_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_Ahj4_EIB1x_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtNtB2o_7sources4once4OnceB1w_EB39_EB39_EEBa_
Line
Count
Source
3808
14
    fn alloc_write_and_return_pointer_size(
3809
14
        mut self: Box<Self>,
3810
14
        function_name: &'static str,
3811
14
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
14
    ) -> HostVm {
3813
14
        let mut data_len = 0u32;
3814
16
        for chunk in 
data.clone()14
{
3815
16
            data_len =
3816
16
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
16
        }
3818
3819
14
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
14
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
14
        let mut ptr_iter = dest_ptr;
3830
30
        for 
chunk16
in data {
3831
16
            let chunk = chunk.as_ref();
3832
16
            self.vm
3833
16
                .write_memory(ptr_iter, chunk)
3834
16
                .unwrap_or_else(|_| unreachable!());
3835
16
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
16
        }
3837
3838
14
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
14
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
14
3841
14
        ReadyToRun {
3842
14
            inner: self,
3843
14
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
14
        }
3845
14
        .into()
3846
14
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_Ahj4_EINtNtNtCs2va5m0jqTTM_4core5array4iter8IntoIterB1w_Kj2_EEBa_
Line
Count
Source
3808
5
    fn alloc_write_and_return_pointer_size(
3809
5
        mut self: Box<Self>,
3810
5
        function_name: &'static str,
3811
5
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
5
    ) -> HostVm {
3813
5
        let mut data_len = 0u32;
3814
10
        for chunk in 
data.clone()5
{
3815
10
            data_len =
3816
10
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
10
        }
3818
3819
5
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
5
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
5
        let mut ptr_iter = dest_ptr;
3830
15
        for 
chunk10
in data {
3831
10
            let chunk = chunk.as_ref();
3832
10
            self.vm
3833
10
                .write_memory(ptr_iter, chunk)
3834
10
                .unwrap_or_else(|_| unreachable!());
3835
10
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
10
        }
3837
3838
5
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
5
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
5
3841
5
        ReadyToRun {
3842
5
            inner: self,
3843
5
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
5
        }
3845
5
        .into()
3846
5
    }
Unexecuted instantiation: _RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_IB1x_INtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_ERShEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB37_INtNtNtB3d_7sources4once4OnceB1w_EB43_EB43_EEBa_
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherRShB21_EINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB2e_3map3MapIB2a_INtNtNtB2g_7sources4once4OnceB21_EB3n_ENcNtB1w_4Left0EIB32_B3n_NcNtB1w_5Right0EEEBa_
Line
Count
Source
3808
504
    fn alloc_write_and_return_pointer_size(
3809
504
        mut self: Box<Self>,
3810
504
        function_name: &'static str,
3811
504
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
504
    ) -> HostVm {
3813
504
        let mut data_len = 0u32;
3814
1.51k
        for chunk in 
data.clone()504
{
3815
1.51k
            data_len =
3816
1.51k
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
1.51k
        }
3818
3819
504
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
504
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
504
        let mut ptr_iter = dest_ptr;
3830
2.01k
        for 
chunk1.51k
in data {
3831
1.51k
            let chunk = chunk.as_ref();
3832
1.51k
            self.vm
3833
1.51k
                .write_memory(ptr_iter, chunk)
3834
1.51k
                .unwrap_or_else(|_| unreachable!());
3835
1.51k
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
1.51k
        }
3837
3838
504
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
504
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
504
3841
504
        ReadyToRun {
3842
504
            inner: self,
3843
504
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
504
        }
3845
504
        .into()
3846
504
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRAhj1_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Line
Count
Source
3808
69
    fn alloc_write_and_return_pointer_size(
3809
69
        mut self: Box<Self>,
3810
69
        function_name: &'static str,
3811
69
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
69
    ) -> HostVm {
3813
69
        let mut data_len = 0u32;
3814
69
        for chunk in data.clone() {
3815
69
            data_len =
3816
69
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
69
        }
3818
3819
69
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
69
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
69
        let mut ptr_iter = dest_ptr;
3830
138
        for 
chunk69
in data {
3831
69
            let chunk = chunk.as_ref();
3832
69
            self.vm
3833
69
                .write_memory(ptr_iter, chunk)
3834
69
                .unwrap_or_else(|_| unreachable!());
3835
69
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
69
        }
3837
3838
69
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
69
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
69
3841
69
        ReadyToRun {
3842
69
            inner: self,
3843
69
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
69
        }
3845
69
        .into()
3846
69
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRAhj20_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Line
Count
Source
3808
5
    fn alloc_write_and_return_pointer_size(
3809
5
        mut self: Box<Self>,
3810
5
        function_name: &'static str,
3811
5
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
5
    ) -> HostVm {
3813
5
        let mut data_len = 0u32;
3814
5
        for chunk in data.clone() {
3815
5
            data_len =
3816
5
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
5
        }
3818
3819
5
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
5
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
5
        let mut ptr_iter = dest_ptr;
3830
10
        for 
chunk5
in data {
3831
5
            let chunk = chunk.as_ref();
3832
5
            self.vm
3833
5
                .write_memory(ptr_iter, chunk)
3834
5
                .unwrap_or_else(|_| unreachable!());
3835
5
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
5
        }
3837
3838
5
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
5
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
5
3841
5
        ReadyToRun {
3842
5
            inner: self,
3843
5
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
5
        }
3845
5
        .into()
3846
5
    }
Unexecuted instantiation: _RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Line
Count
Source
3808
1
    fn alloc_write_and_return_pointer_size(
3809
1
        mut self: Box<Self>,
3810
1
        function_name: &'static str,
3811
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
1
    ) -> HostVm {
3813
1
        let mut data_len = 0u32;
3814
1
        for chunk in data.clone() {
3815
1
            data_len =
3816
1
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
1
        }
3818
3819
1
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
1
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
1
        let mut ptr_iter = dest_ptr;
3830
2
        for 
chunk1
in data {
3831
1
            let chunk = chunk.as_ref();
3832
1
            self.vm
3833
1
                .write_memory(ptr_iter, chunk)
3834
1
                .unwrap_or_else(|_| unreachable!());
3835
1
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
1
        }
3837
3838
1
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
1
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
1
3841
1
        ReadyToRun {
3842
1
            inner: self,
3843
1
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
1
        }
3845
1
        .into()
3846
1
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRShINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB1A_INtNtNtB1G_7sources4once4OnceB1w_EB2w_EB2w_EEBa_
Line
Count
Source
3808
1
    fn alloc_write_and_return_pointer_size(
3809
1
        mut self: Box<Self>,
3810
1
        function_name: &'static str,
3811
1
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
1
    ) -> HostVm {
3813
1
        let mut data_len = 0u32;
3814
3
        for chunk in 
data.clone()1
{
3815
3
            data_len =
3816
3
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
3
        }
3818
3819
1
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
1
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
1
        let mut ptr_iter = dest_ptr;
3830
4
        for 
chunk3
in data {
3831
3
            let chunk = chunk.as_ref();
3832
3
            self.vm
3833
3
                .write_memory(ptr_iter, chunk)
3834
3
                .unwrap_or_else(|_| unreachable!());
3835
3
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
3
        }
3837
3838
1
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
1
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
1
3841
1
        ReadyToRun {
3842
1
            inner: self,
3843
1
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
1
        }
3845
1
        .into()
3846
1
    }
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeAhj1_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_Ahj4_EIB1x_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtNtB2o_7sources4once4OnceB1w_EB39_EB39_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_Ahj4_EINtNtNtCs2va5m0jqTTM_4core5array4iter8IntoIterB1w_Kj2_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherAhj1_IB1x_INtNtCs9QpEIdxm4dv_8arrayvec8arrayvec8ArrayVechKj9_ERShEEINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB37_INtNtNtB3d_7sources4once4OnceB1w_EB43_EB43_EEBa_
_RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeINtCs5MhOSyk0iiL_6either6EitherRShB21_EINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtB2e_3map3MapIB2a_INtNtNtB2g_7sources4once4OnceB21_EB3n_ENcNtB1w_4Left0EIB32_B3n_NcNtB1w_5Right0EEEBa_
Line
Count
Source
3808
84
    fn alloc_write_and_return_pointer_size(
3809
84
        mut self: Box<Self>,
3810
84
        function_name: &'static str,
3811
84
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3812
84
    ) -> HostVm {
3813
84
        let mut data_len = 0u32;
3814
252
        for chunk in 
data.clone()84
{
3815
252
            data_len =
3816
252
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3817
252
        }
3818
3819
84
        let dest_ptr = match self.alloc(function_name, data_len) {
3820
84
            Ok(p) => p,
3821
0
            Err(error) => {
3822
0
                return HostVm::Error {
3823
0
                    error,
3824
0
                    prototype: self.into_prototype(),
3825
0
                };
3826
            }
3827
        };
3828
3829
84
        let mut ptr_iter = dest_ptr;
3830
336
        for 
chunk252
in data {
3831
252
            let chunk = chunk.as_ref();
3832
252
            self.vm
3833
252
                .write_memory(ptr_iter, chunk)
3834
252
                .unwrap_or_else(|_| unreachable!());
3835
252
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3836
252
        }
3837
3838
84
        let ret_val = (u64::from(data_len) << 32) | u64::from(dest_ptr);
3839
84
        let ret_val = i64::from_ne_bytes(ret_val.to_ne_bytes());
3840
84
3841
84
        ReadyToRun {
3842
84
            inner: self,
3843
84
            resume_value: Some(vm::WasmValue::I64(ret_val)),
3844
84
        }
3845
84
        .into()
3846
84
    }
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRAhj1_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRAhj20_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRINtNtCs8GO9KFlE3Dq_5alloc3vec3VechEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1w_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner35alloc_write_and_return_pointer_sizeRShINtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB1A_INtNtNtB1G_7sources4once4OnceB1w_EB2w_EB2w_EEBa_
3847
3848
    /// Uses the memory allocator to allocate some memory for the given data, writes the data in
3849
    /// memory, and returns an [`HostVm`] ready for the Wasm `host_fn` return.
3850
    ///
3851
    /// The data is passed as a list of chunks. These chunks will be laid out linearly in memory.
3852
    ///
3853
    /// The function name passed as parameter is used for error-reporting reasons.
3854
    ///
3855
    /// # Panic
3856
    ///
3857
    /// Must only be called while the Wasm is handling an `host_fn`.
3858
    ///
3859
2.07k
    fn alloc_write_and_return_pointer(
3860
2.07k
        mut self: Box<Self>,
3861
2.07k
        function_name: &'static str,
3862
2.07k
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
2.07k
    ) -> HostVm {
3864
2.07k
        let mut data_len = 0u32;
3865
3.89k
        for chunk in 
data.clone()2.07k
{
3866
3.89k
            data_len =
3867
3.89k
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
3.89k
        }
3869
3870
2.07k
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
2.07k
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
2.07k
        let mut ptr_iter = dest_ptr;
3881
5.97k
        for 
chunk3.89k
in data {
3882
3.89k
            let chunk = chunk.as_ref();
3883
3.89k
            self.vm
3884
3.89k
                .write_memory(ptr_iter, chunk)
3885
3.89k
                .unwrap_or_else(|_| unreachable!());
3886
3.89k
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
3.89k
        }
3888
3889
2.07k
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
2.07k
        ReadyToRun {
3891
2.07k
            inner: self,
3892
2.07k
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
2.07k
        }
3894
2.07k
        .into()
3895
2.07k
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj20_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Line
Count
Source
3859
5
    fn alloc_write_and_return_pointer(
3860
5
        mut self: Box<Self>,
3861
5
        function_name: &'static str,
3862
5
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
5
    ) -> HostVm {
3864
5
        let mut data_len = 0u32;
3865
5
        for chunk in data.clone() {
3866
5
            data_len =
3867
5
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
5
        }
3869
3870
5
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
5
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
5
        let mut ptr_iter = dest_ptr;
3881
10
        for 
chunk5
in data {
3882
5
            let chunk = chunk.as_ref();
3883
5
            self.vm
3884
5
                .write_memory(ptr_iter, chunk)
3885
5
                .unwrap_or_else(|_| unreachable!());
3886
5
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
5
        }
3888
3889
5
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
5
        ReadyToRun {
3891
5
            inner: self,
3892
5
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
5
        }
3894
5
        .into()
3895
5
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Line
Count
Source
3859
67
    fn alloc_write_and_return_pointer(
3860
67
        mut self: Box<Self>,
3861
67
        function_name: &'static str,
3862
67
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
67
    ) -> HostVm {
3864
67
        let mut data_len = 0u32;
3865
67
        for chunk in data.clone() {
3866
67
            data_len =
3867
67
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
67
        }
3869
3870
67
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
67
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
67
        let mut ptr_iter = dest_ptr;
3881
134
        for 
chunk67
in data {
3882
67
            let chunk = chunk.as_ref();
3883
67
            self.vm
3884
67
                .write_memory(ptr_iter, chunk)
3885
67
                .unwrap_or_else(|_| unreachable!());
3886
67
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
67
        }
3888
3889
67
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
67
        ReadyToRun {
3891
67
            inner: self,
3892
67
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
67
        }
3894
67
        .into()
3895
67
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB1y_IB1y_INtNtNtB1E_7sources4once4OnceB1r_EB2z_EB2z_EB2z_EEBa_
Line
Count
Source
3859
2
    fn alloc_write_and_return_pointer(
3860
2
        mut self: Box<Self>,
3861
2
        function_name: &'static str,
3862
2
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
2
    ) -> HostVm {
3864
2
        let mut data_len = 0u32;
3865
8
        for chunk in 
data.clone()2
{
3866
8
            data_len =
3867
8
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
8
        }
3869
3870
2
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
2
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
2
        let mut ptr_iter = dest_ptr;
3881
10
        for 
chunk8
in data {
3882
8
            let chunk = chunk.as_ref();
3883
8
            self.vm
3884
8
                .write_memory(ptr_iter, chunk)
3885
8
                .unwrap_or_else(|_| unreachable!());
3886
8
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
8
        }
3888
3889
2
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
2
        ReadyToRun {
3891
2
            inner: self,
3892
2
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
2
        }
3894
2
        .into()
3895
2
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtNtB1E_7sources4once4OnceB1r_EB2p_EEBa_
Line
Count
Source
3859
1.73k
    fn alloc_write_and_return_pointer(
3860
1.73k
        mut self: Box<Self>,
3861
1.73k
        function_name: &'static str,
3862
1.73k
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
1.73k
    ) -> HostVm {
3864
1.73k
        let mut data_len = 0u32;
3865
3.46k
        for chunk in 
data.clone()1.73k
{
3866
3.46k
            data_len =
3867
3.46k
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
3.46k
        }
3869
3870
1.73k
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
1.73k
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
1.73k
        let mut ptr_iter = dest_ptr;
3881
5.19k
        for 
chunk3.46k
in data {
3882
3.46k
            let chunk = chunk.as_ref();
3883
3.46k
            self.vm
3884
3.46k
                .write_memory(ptr_iter, chunk)
3885
3.46k
                .unwrap_or_else(|_| unreachable!());
3886
3.46k
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
3.46k
        }
3888
3889
1.73k
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
1.73k
        ReadyToRun {
3891
1.73k
            inner: self,
3892
1.73k
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
1.73k
        }
3894
1.73k
        .into()
3895
1.73k
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRINtCse9sIFKsx9nf_13generic_array12GenericArrayhINtNtCswkNoRGPTFK_7typenum4uint4UIntIB2e_IB2e_IB2e_IB2e_IB2e_IB2e_NtB2g_5UTermNtNtB2i_3bit2B1ENtB3v_2B0EB3J_EB3J_EB3J_EB3J_EB3J_EEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Line
Count
Source
3859
2
    fn alloc_write_and_return_pointer(
3860
2
        mut self: Box<Self>,
3861
2
        function_name: &'static str,
3862
2
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
2
    ) -> HostVm {
3864
2
        let mut data_len = 0u32;
3865
2
        for chunk in data.clone() {
3866
2
            data_len =
3867
2
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
2
        }
3869
3870
2
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
2
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
2
        let mut ptr_iter = dest_ptr;
3881
4
        for 
chunk2
in data {
3882
2
            let chunk = chunk.as_ref();
3883
2
            self.vm
3884
2
                .write_memory(ptr_iter, chunk)
3885
2
                .unwrap_or_else(|_| unreachable!());
3886
2
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
2
        }
3888
3889
2
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
2
        ReadyToRun {
3891
2
            inner: self,
3892
2
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
2
        }
3894
2
        .into()
3895
2
    }
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRINtCse9sIFKsx9nf_13generic_array12GenericArrayhINtNtCswkNoRGPTFK_7typenum4uint4UIntIB2e_IB2e_IB2e_IB2e_IB2e_NtB2g_5UTermNtNtB2i_3bit2B1ENtB3q_2B0EB3E_EB3E_EB3E_EB3E_EEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Line
Count
Source
3859
4
    fn alloc_write_and_return_pointer(
3860
4
        mut self: Box<Self>,
3861
4
        function_name: &'static str,
3862
4
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
4
    ) -> HostVm {
3864
4
        let mut data_len = 0u32;
3865
4
        for chunk in data.clone() {
3866
4
            data_len =
3867
4
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
4
        }
3869
3870
4
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
4
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
4
        let mut ptr_iter = dest_ptr;
3881
8
        for 
chunk4
in data {
3882
4
            let chunk = chunk.as_ref();
3883
4
            self.vm
3884
4
                .write_memory(ptr_iter, chunk)
3885
4
                .unwrap_or_else(|_| unreachable!());
3886
4
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
4
        }
3888
3889
4
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
4
        ReadyToRun {
3891
4
            inner: self,
3892
4
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
4
        }
3894
4
        .into()
3895
4
    }
Unexecuted instantiation: _RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRShINtNtNtCs2va5m0jqTTM_4core5array4iter8IntoIterB1r_Kj2_EEBa_
_RINvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Line
Count
Source
3859
178
    fn alloc_write_and_return_pointer(
3860
178
        mut self: Box<Self>,
3861
178
        function_name: &'static str,
3862
178
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
178
    ) -> HostVm {
3864
178
        let mut data_len = 0u32;
3865
178
        for chunk in data.clone() {
3866
178
            data_len =
3867
178
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
178
        }
3869
3870
178
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
178
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
178
        let mut ptr_iter = dest_ptr;
3881
356
        for 
chunk178
in data {
3882
178
            let chunk = chunk.as_ref();
3883
178
            self.vm
3884
178
                .write_memory(ptr_iter, chunk)
3885
178
                .unwrap_or_else(|_| unreachable!());
3886
178
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
178
        }
3888
3889
178
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
178
        ReadyToRun {
3891
178
            inner: self,
3892
178
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
178
        }
3894
178
        .into()
3895
178
    }
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerAhj20_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj20_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainIB1y_IB1y_INtNtNtB1E_7sources4once4OnceB1r_EB2z_EB2z_EB2z_EEBa_
_RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRAhj8_INtNtNtNtCs2va5m0jqTTM_4core4iter8adapters5chain5ChainINtNtNtB1E_7sources4once4OnceB1r_EB2p_EEBa_
Line
Count
Source
3859
84
    fn alloc_write_and_return_pointer(
3860
84
        mut self: Box<Self>,
3861
84
        function_name: &'static str,
3862
84
        data: impl Iterator<Item = impl AsRef<[u8]>> + Clone,
3863
84
    ) -> HostVm {
3864
84
        let mut data_len = 0u32;
3865
168
        for chunk in 
data.clone()84
{
3866
168
            data_len =
3867
168
                data_len.saturating_add(u32::try_from(chunk.as_ref().len()).unwrap_or(u32::MAX));
3868
168
        }
3869
3870
84
        let dest_ptr = match self.alloc(function_name, data_len) {
3871
84
            Ok(p) => p,
3872
0
            Err(error) => {
3873
0
                return HostVm::Error {
3874
0
                    error,
3875
0
                    prototype: self.into_prototype(),
3876
0
                };
3877
            }
3878
        };
3879
3880
84
        let mut ptr_iter = dest_ptr;
3881
252
        for 
chunk168
in data {
3882
168
            let chunk = chunk.as_ref();
3883
168
            self.vm
3884
168
                .write_memory(ptr_iter, chunk)
3885
168
                .unwrap_or_else(|_| unreachable!());
3886
168
            ptr_iter += u32::try_from(chunk.len()).unwrap_or(u32::MAX);
3887
168
        }
3888
3889
84
        let ret_val = i32::from_ne_bytes(dest_ptr.to_ne_bytes());
3890
84
        ReadyToRun {
3891
84
            inner: self,
3892
84
            resume_value: Some(vm::WasmValue::I32(ret_val)),
3893
84
        }
3894
84
        .into()
3895
84
    }
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRINtCse9sIFKsx9nf_13generic_array12GenericArrayhINtNtCswkNoRGPTFK_7typenum4uint4UIntIB2e_IB2e_IB2e_IB2e_IB2e_IB2e_NtB2g_5UTermNtNtB2i_3bit2B1ENtB3v_2B0EB3J_EB3J_EB3J_EB3J_EB3J_EEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRINtCse9sIFKsx9nf_13generic_array12GenericArrayhINtNtCswkNoRGPTFK_7typenum4uint4UIntIB2e_IB2e_IB2e_IB2e_IB2e_NtB2g_5UTermNtNtB2i_3bit2B1ENtB3q_2B0EB3E_EB3E_EB3E_EB3E_EEINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRShINtNtNtCs2va5m0jqTTM_4core5array4iter8IntoIterB1r_Kj2_EEBa_
Unexecuted instantiation: _RINvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB6_5Inner30alloc_write_and_return_pointerRShINtNtNtNtCs2va5m0jqTTM_4core4iter7sources4once4OnceB1r_EEBa_
3896
3897
    /// Uses the memory allocator to allocate some memory.
3898
    ///
3899
    /// The function name passed as parameter is used for error-reporting reasons.
3900
    ///
3901
    /// # Panic
3902
    ///
3903
    /// Must only be called while the Wasm is handling an `host_fn`.
3904
    ///
3905
16.8k
    fn alloc(&mut self, function_name: &'static str, size: u32) -> Result<u32, Error> {
3906
        // Use the allocator to decide where the value will be written.
3907
16.8k
        let dest_ptr = match self.allocator.allocate(
3908
16.8k
            &mut MemAccess {
3909
16.8k
                vm: MemAccessVm::Running(&mut self.vm),
3910
16.8k
                memory_total_pages: self.common.memory_total_pages,
3911
16.8k
            },
3912
16.8k
            size,
3913
16.8k
        ) {
3914
16.8k
            Ok(p) => p,
3915
            Err(_) => {
3916
0
                return Err(Error::OutOfMemory {
3917
0
                    function: function_name,
3918
0
                    requested_size: size,
3919
0
                });
3920
            }
3921
        };
3922
3923
        // Unfortunately this function doesn't stop here.
3924
        // We lie to the allocator. The allocator thinks that there are `self.memory_total_pages`
3925
        // allocated and available, while in reality it can be less.
3926
        // The allocator might thus allocate memory at a location above the current memory size.
3927
        // To handle this, we grow the memory.
3928
3929
        // Offset of the memory page where the last allocated byte is found.
3930
16.8k
        let last_byte_memory_page = HeapPages::new((dest_ptr + size - 1) / (64 * 1024));
3931
16.8k
3932
16.8k
        // Grow the memory more if necessary.
3933
16.8k
        // Please note the `=`. For example if we write to page 0, we want to have at least 1 page
3934
16.8k
        // allocated.
3935
16.8k
        let current_num_pages = self.vm.memory_size();
3936
16.8k
        debug_assert!(current_num_pages <= self.common.memory_total_pages);
3937
16.8k
        if current_num_pages <= last_byte_memory_page {
3938
39
            // For now, we grow the memory just enough to fit.
3939
39
            // TODO: do better
3940
39
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
3941
39
            // in case `last_byte_memory_page` is the maximum possible value.
3942
39
            let to_grow = last_byte_memory_page - current_num_pages + HeapPages::new(1);
3943
39
3944
39
            // We check at initialization that the virtual machine is capable of growing up to
3945
39
            // `memory_total_pages`, meaning that this can't panic.
3946
39
            self.vm
3947
39
                .grow_memory(to_grow)
3948
39
                .unwrap_or_else(|_| unreachable!());
3949
16.8k
        }
3950
3951
16.8k
        Ok(dest_ptr)
3952
16.8k
    }
_RNvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_5Inner5alloc
Line
Count
Source
3905
14.3k
    fn alloc(&mut self, function_name: &'static str, size: u32) -> Result<u32, Error> {
3906
        // Use the allocator to decide where the value will be written.
3907
14.3k
        let dest_ptr = match self.allocator.allocate(
3908
14.3k
            &mut MemAccess {
3909
14.3k
                vm: MemAccessVm::Running(&mut self.vm),
3910
14.3k
                memory_total_pages: self.common.memory_total_pages,
3911
14.3k
            },
3912
14.3k
            size,
3913
14.3k
        ) {
3914
14.3k
            Ok(p) => p,
3915
            Err(_) => {
3916
0
                return Err(Error::OutOfMemory {
3917
0
                    function: function_name,
3918
0
                    requested_size: size,
3919
0
                });
3920
            }
3921
        };
3922
3923
        // Unfortunately this function doesn't stop here.
3924
        // We lie to the allocator. The allocator thinks that there are `self.memory_total_pages`
3925
        // allocated and available, while in reality it can be less.
3926
        // The allocator might thus allocate memory at a location above the current memory size.
3927
        // To handle this, we grow the memory.
3928
3929
        // Offset of the memory page where the last allocated byte is found.
3930
14.3k
        let last_byte_memory_page = HeapPages::new((dest_ptr + size - 1) / (64 * 1024));
3931
14.3k
3932
14.3k
        // Grow the memory more if necessary.
3933
14.3k
        // Please note the `=`. For example if we write to page 0, we want to have at least 1 page
3934
14.3k
        // allocated.
3935
14.3k
        let current_num_pages = self.vm.memory_size();
3936
14.3k
        debug_assert!(current_num_pages <= self.common.memory_total_pages);
3937
14.3k
        if current_num_pages <= last_byte_memory_page {
3938
34
            // For now, we grow the memory just enough to fit.
3939
34
            // TODO: do better
3940
34
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
3941
34
            // in case `last_byte_memory_page` is the maximum possible value.
3942
34
            let to_grow = last_byte_memory_page - current_num_pages + HeapPages::new(1);
3943
34
3944
34
            // We check at initialization that the virtual machine is capable of growing up to
3945
34
            // `memory_total_pages`, meaning that this can't panic.
3946
34
            self.vm
3947
34
                .grow_memory(to_grow)
3948
34
                .unwrap_or_else(|_| unreachable!());
3949
14.3k
        }
3950
3951
14.3k
        Ok(dest_ptr)
3952
14.3k
    }
_RNvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_5Inner5alloc
Line
Count
Source
3905
2.53k
    fn alloc(&mut self, function_name: &'static str, size: u32) -> Result<u32, Error> {
3906
        // Use the allocator to decide where the value will be written.
3907
2.53k
        let dest_ptr = match self.allocator.allocate(
3908
2.53k
            &mut MemAccess {
3909
2.53k
                vm: MemAccessVm::Running(&mut self.vm),
3910
2.53k
                memory_total_pages: self.common.memory_total_pages,
3911
2.53k
            },
3912
2.53k
            size,
3913
2.53k
        ) {
3914
2.53k
            Ok(p) => p,
3915
            Err(_) => {
3916
0
                return Err(Error::OutOfMemory {
3917
0
                    function: function_name,
3918
0
                    requested_size: size,
3919
0
                });
3920
            }
3921
        };
3922
3923
        // Unfortunately this function doesn't stop here.
3924
        // We lie to the allocator. The allocator thinks that there are `self.memory_total_pages`
3925
        // allocated and available, while in reality it can be less.
3926
        // The allocator might thus allocate memory at a location above the current memory size.
3927
        // To handle this, we grow the memory.
3928
3929
        // Offset of the memory page where the last allocated byte is found.
3930
2.53k
        let last_byte_memory_page = HeapPages::new((dest_ptr + size - 1) / (64 * 1024));
3931
2.53k
3932
2.53k
        // Grow the memory more if necessary.
3933
2.53k
        // Please note the `=`. For example if we write to page 0, we want to have at least 1 page
3934
2.53k
        // allocated.
3935
2.53k
        let current_num_pages = self.vm.memory_size();
3936
2.53k
        debug_assert!(current_num_pages <= self.common.memory_total_pages);
3937
2.53k
        if current_num_pages <= last_byte_memory_page {
3938
5
            // For now, we grow the memory just enough to fit.
3939
5
            // TODO: do better
3940
5
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
3941
5
            // in case `last_byte_memory_page` is the maximum possible value.
3942
5
            let to_grow = last_byte_memory_page - current_num_pages + HeapPages::new(1);
3943
5
3944
5
            // We check at initialization that the virtual machine is capable of growing up to
3945
5
            // `memory_total_pages`, meaning that this can't panic.
3946
5
            self.vm
3947
5
                .grow_memory(to_grow)
3948
5
                .unwrap_or_else(|_| unreachable!());
3949
2.53k
        }
3950
3951
2.53k
        Ok(dest_ptr)
3952
2.53k
    }
3953
3954
    /// Turns the virtual machine back into a prototype.
3955
145
    fn into_prototype(self) -> HostVmPrototype {
3956
145
        HostVmPrototype {
3957
145
            vm_proto: self.vm.into_prototype(),
3958
145
            common: self.common,
3959
145
        }
3960
145
    }
_RNvMsM_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_5Inner14into_prototype
Line
Count
Source
3955
19
    fn into_prototype(self) -> HostVmPrototype {
3956
19
        HostVmPrototype {
3957
19
            vm_proto: self.vm.into_prototype(),
3958
19
            common: self.common,
3959
19
        }
3960
19
    }
_RNvMsM_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_5Inner14into_prototype
Line
Count
Source
3955
126
    fn into_prototype(self) -> HostVmPrototype {
3956
126
        HostVmPrototype {
3957
126
            vm_proto: self.vm.into_prototype(),
3958
126
            common: self.common,
3959
126
        }
3960
126
    }
3961
}
3962
3963
/// Error that can happen when initializing a VM.
3964
#[derive(Debug, derive_more::From, derive_more::Display, derive_more::Error, Clone)]
3965
pub enum NewErr {
3966
    /// Error in the format of the runtime code.
3967
    #[display("{_0}")]
3968
    BadFormat(ModuleFormatError),
3969
    /// Error while initializing the virtual machine.
3970
    #[display("{_0}")]
3971
    VirtualMachine(vm::NewErr),
3972
    /// Error while finding the runtime-version-related sections in the Wasm blob.
3973
    #[display("Error in runtime spec Wasm sections: {_0}")]
3974
    RuntimeVersion(FindEmbeddedRuntimeVersionError),
3975
    /// Error while calling `Core_version` to determine the runtime version.
3976
    #[display("Error while calling Core_version: {_0}")]
3977
    CoreVersion(CoreVersionError),
3978
    /// Couldn't find the `__heap_base` symbol in the Wasm code.
3979
    HeapBaseNotFound,
3980
    /// Maximum size of the Wasm memory found in the module is too low to provide the requested
3981
    /// number of heap pages.
3982
    MemoryMaxSizeTooLow,
3983
}
3984
3985
/// Error while determining .
3986
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
3987
pub enum FindEmbeddedRuntimeVersionError {
3988
    /// Error while finding the custom section.
3989
    #[display("{_0}")]
3990
    FindSections(FindEncodedEmbeddedRuntimeVersionApisError),
3991
    /// Error while decoding the runtime version.
3992
    RuntimeVersionDecode,
3993
    /// Error while decoding the runtime APIs.
3994
    #[display("{_0}")]
3995
    RuntimeApisDecode(CoreVersionApisFromSliceErr),
3996
}
3997
3998
/// Error that can happen when starting a VM.
3999
#[derive(Debug, Clone, derive_more::From, derive_more::Display, derive_more::Error)]
4000
pub enum StartErr {
4001
    /// Error while starting the virtual machine.
4002
    #[display("{_0}")]
4003
    VirtualMachine(vm::StartErr),
4004
    /// The size of the input data is too large.
4005
    DataSizeOverflow,
4006
}
4007
4008
/// Reason why the Wasm blob isn't conforming to the runtime environment.
4009
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4010
pub enum Error {
4011
    /// Error in the Wasm code execution.
4012
    #[display("{_0}")]
4013
    Trap(vm::Trap),
4014
    /// Runtime has called the `ext_panic_handler_abort_on_panic_version_1` host function.
4015
    #[display("Runtime has aborted: {message:?}")]
4016
    AbortOnPanic {
4017
        /// Message generated by the runtime.
4018
        message: String,
4019
    },
4020
    /// A non-`i64` value has been returned by the Wasm entry point.
4021
    #[display("A non-I64 value has been returned: {actual:?}")]
4022
    BadReturnValue {
4023
        /// Type that has actually gotten returned. `None` for "void".
4024
        actual: Option<vm::ValueType>,
4025
    },
4026
    /// The pointer and size returned by the Wasm entry point function are invalid.
4027
    #[display("The pointer and size returned by the function are invalid")]
4028
    ReturnedPtrOutOfRange {
4029
        /// Pointer that got returned.
4030
        pointer: u32,
4031
        /// Size that got returned.
4032
        size: u32,
4033
        /// Size of the virtual memory.
4034
        memory_size: u32,
4035
    },
4036
    /// Called a function that is unknown to the host.
4037
    ///
4038
    /// > **Note**: Can only happen if `allow_unresolved_imports` was `true`.
4039
    #[display("Called unresolved function `{module_name}`:`{function}`")]
4040
    UnresolvedFunctionCalled {
4041
        /// Name of the function that was unresolved.
4042
        function: String,
4043
        /// Name of module associated with the unresolved function.
4044
        module_name: String,
4045
    },
4046
    /// Failed to decode a SCALE-encoded parameter.
4047
    ParamDecodeError,
4048
    /// One parameter is expected to point to a buffer, but the pointer is out
4049
    /// of range of the memory of the Wasm VM.
4050
    #[display(
4051
        "Bad pointer for parameter of index {param_num} of {function}: 0x{pointer:x}, \
4052
        len = 0x{length:x}"
4053
    )]
4054
    ParamOutOfRange {
4055
        /// Name of the function being called where a type mismatch happens.
4056
        function: &'static str,
4057
        /// Index of the invalid parameter. The first parameter has index 0.
4058
        param_num: usize,
4059
        /// Pointer passed as parameter.
4060
        pointer: u32,
4061
        /// Expected length of the buffer.
4062
        ///
4063
        /// Depending on the function, this can either be an implicit length
4064
        /// or a length passed as parameter.
4065
        length: u32,
4066
    },
4067
    /// One parameter is expected to point to a UTF-8 string, but the buffer
4068
    /// isn't valid UTF-8.
4069
    #[display("UTF-8 error for parameter of index {param_num} of {function}: {error}")]
4070
    Utf8Error {
4071
        /// Name of the function being called where a type mismatch happens.
4072
        function: &'static str,
4073
        /// Index of the invalid parameter. The first parameter has index 0.
4074
        param_num: usize,
4075
        /// Decoding error that happened.
4076
        #[error(source)]
4077
        error: core::str::Utf8Error,
4078
    },
4079
    /// Called `ext_storage_rollback_transaction_version_1` or
4080
    /// `ext_storage_commit_transaction_version_1` but no transaction was in progress.
4081
    #[display("Attempted to end a transaction while none is in progress")]
4082
    NoActiveTransaction,
4083
    /// Execution has finished while a transaction started with
4084
    /// `ext_storage_start_transaction_version_1` was still in progress.
4085
    #[display("Execution returned with a pending storage transaction")]
4086
    FinishedWithPendingTransaction,
4087
    /// Error when allocating memory for a return type.
4088
    #[display("Out of memory allocating 0x{requested_size:x} bytes during {function}")]
4089
    OutOfMemory {
4090
        /// Name of the function being called.
4091
        function: &'static str,
4092
        /// Size of the requested allocation.
4093
        requested_size: u32,
4094
    },
4095
    /// Called `ext_allocator_free_version_1` with an invalid pointer.
4096
    #[display("Bad pointer passed to ext_allocator_free_version_1: 0x{pointer:x}")]
4097
    FreeError {
4098
        /// Pointer that was expected to be freed.
4099
        pointer: u32,
4100
    },
4101
    /// Mismatch between the state trie version provided as parameter and the state trie version
4102
    /// found in the runtime specification.
4103
    #[display(
4104
        "Mismatch between the state trie version provided as parameter ({parameter:?}) and \
4105
        the state trie version found in the runtime specification ({specification:?})."
4106
    )]
4107
    StateVersionMismatch {
4108
        /// The version passed as parameter.
4109
        parameter: TrieEntryVersion,
4110
        /// The version in the specification.
4111
        specification: TrieEntryVersion,
4112
    },
4113
    /// Called `ext_default_child_storage_root_version_1` or
4114
    /// `ext_default_child_storage_root_version_2` on a child trie that doesn't exist.
4115
    #[display(
4116
        "Called `ext_default_child_storage_root_version_1` or
4117
        `ext_default_child_storage_root_version_2` on a child trie that doesn't exist."
4118
    )]
4119
    ChildStorageRootTrieDoesntExist,
4120
    /// Runtime has tried to perform a signature batch verification before initiating a batch
4121
    /// verification.
4122
    BatchVerifyWithoutStarting,
4123
    /// Runtime has tried to initiate a batch signatures verification while there was already one
4124
    /// in progress.
4125
    AlreadyBatchVerify,
4126
    /// Runtime has tried to finish a batch signatures verification while none is in progress.
4127
    NoBatchVerify,
4128
    /// The host function isn't implemented.
4129
    // TODO: this variant should eventually disappear as all functions are implemented
4130
    #[display("Host function not implemented: {function}")]
4131
    HostFunctionNotImplemented {
4132
        /// Name of the function being called.
4133
        function: &'static str,
4134
    },
4135
}
4136
4137
// Glue between the `allocator` module and the `vm` module.
4138
//
4139
// The allocator believes that there are `memory_total_pages` pages available and allocated, where
4140
// `memory_total_pages` is equal to `heap_base + heap_pages`, while in reality, because we grow
4141
// memory lazily, there might be fewer.
4142
struct MemAccess<'a> {
4143
    vm: MemAccessVm<'a>,
4144
    memory_total_pages: HeapPages,
4145
}
4146
4147
enum MemAccessVm<'a> {
4148
    Prepare(&'a mut vm::Prepare),
4149
    Running(&'a mut vm::VirtualMachine),
4150
}
4151
4152
impl<'a> allocator::Memory for MemAccess<'a> {
4153
30.0k
    fn read_le_u64(&self, ptr: u32) -> Result<u64, allocator::Error> {
4154
30.0k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4155
0
            return Err(allocator::Error::Other);
4156
30.0k
        }
4157
30.0k
4158
30.0k
        // Note that this function (`read_le_u64`) really should take ̀`&mut self` but that is
4159
30.0k
        // unfortunately not the case, meaning that we can't "just" grow the memory if trying
4160
30.0k
        // to access an out of bound location.
4161
30.0k
        //
4162
30.0k
        // Additionally, the value being read can in theory overlap between an allocated and
4163
30.0k
        // non-allocated parts of the memory, making this more complicated.
4164
30.0k
4165
30.0k
        // Offset of the memory page where the first byte of the value will be read.
4166
30.0k
        let accessed_memory_page_start = HeapPages::new(ptr / (64 * 1024));
4167
30.0k
        // Offset of the memory page where the last byte of the value will be read.
4168
30.0k
        let accessed_memory_page_end = HeapPages::new((ptr + 7) / (64 * 1024));
4169
        // Number of pages currently allocated.
4170
30.0k
        let current_num_pages = match self.vm {
4171
0
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4172
30.0k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4173
        };
4174
30.0k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4175
4176
30.0k
        if accessed_memory_page_end < current_num_pages {
4177
            // This is the simple case: the memory access is in bounds.
4178
30.0k
            match self.vm {
4179
0
                MemAccessVm::Prepare(ref vm) => {
4180
0
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4181
0
                    Ok(u64::from_le_bytes(
4182
0
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4183
0
                    ))
4184
                }
4185
30.0k
                MemAccessVm::Running(ref vm) => {
4186
30.0k
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4187
30.0k
                    Ok(u64::from_le_bytes(
4188
30.0k
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4189
30.0k
                    ))
4190
                }
4191
            }
4192
0
        } else if accessed_memory_page_start < current_num_pages {
4193
            // Memory access is partially in bounds. This is the most complicated situation.
4194
0
            match self.vm {
4195
0
                MemAccessVm::Prepare(ref vm) => {
4196
0
                    let partial_bytes = vm
4197
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4198
0
                        .unwrap_or_else(|_| unreachable!());
4199
0
                    let partial_bytes = partial_bytes.as_ref();
4200
0
                    debug_assert!(partial_bytes.len() < 8);
4201
4202
0
                    let mut out = [0; 8];
4203
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4204
0
                    Ok(u64::from_le_bytes(out))
4205
                }
4206
0
                MemAccessVm::Running(ref vm) => {
4207
0
                    let partial_bytes = vm
4208
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4209
0
                        .unwrap_or_else(|_| unreachable!());
4210
0
                    let partial_bytes = partial_bytes.as_ref();
4211
0
                    debug_assert!(partial_bytes.len() < 8);
4212
4213
0
                    let mut out = [0; 8];
4214
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4215
0
                    Ok(u64::from_le_bytes(out))
4216
                }
4217
            }
4218
        } else {
4219
            // Everything out bounds. Memory is zero.
4220
0
            Ok(0)
4221
        }
4222
30.0k
    }
_RNvXsN_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory11read_le_u64
Line
Count
Source
4153
27.0k
    fn read_le_u64(&self, ptr: u32) -> Result<u64, allocator::Error> {
4154
27.0k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4155
0
            return Err(allocator::Error::Other);
4156
27.0k
        }
4157
27.0k
4158
27.0k
        // Note that this function (`read_le_u64`) really should take ̀`&mut self` but that is
4159
27.0k
        // unfortunately not the case, meaning that we can't "just" grow the memory if trying
4160
27.0k
        // to access an out of bound location.
4161
27.0k
        //
4162
27.0k
        // Additionally, the value being read can in theory overlap between an allocated and
4163
27.0k
        // non-allocated parts of the memory, making this more complicated.
4164
27.0k
4165
27.0k
        // Offset of the memory page where the first byte of the value will be read.
4166
27.0k
        let accessed_memory_page_start = HeapPages::new(ptr / (64 * 1024));
4167
27.0k
        // Offset of the memory page where the last byte of the value will be read.
4168
27.0k
        let accessed_memory_page_end = HeapPages::new((ptr + 7) / (64 * 1024));
4169
        // Number of pages currently allocated.
4170
27.0k
        let current_num_pages = match self.vm {
4171
0
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4172
27.0k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4173
        };
4174
27.0k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4175
4176
27.0k
        if accessed_memory_page_end < current_num_pages {
4177
            // This is the simple case: the memory access is in bounds.
4178
27.0k
            match self.vm {
4179
0
                MemAccessVm::Prepare(ref vm) => {
4180
0
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4181
0
                    Ok(u64::from_le_bytes(
4182
0
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4183
0
                    ))
4184
                }
4185
27.0k
                MemAccessVm::Running(ref vm) => {
4186
27.0k
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4187
27.0k
                    Ok(u64::from_le_bytes(
4188
27.0k
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4189
27.0k
                    ))
4190
                }
4191
            }
4192
0
        } else if accessed_memory_page_start < current_num_pages {
4193
            // Memory access is partially in bounds. This is the most complicated situation.
4194
0
            match self.vm {
4195
0
                MemAccessVm::Prepare(ref vm) => {
4196
0
                    let partial_bytes = vm
4197
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4198
0
                        .unwrap_or_else(|_| unreachable!());
4199
0
                    let partial_bytes = partial_bytes.as_ref();
4200
0
                    debug_assert!(partial_bytes.len() < 8);
4201
4202
0
                    let mut out = [0; 8];
4203
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4204
0
                    Ok(u64::from_le_bytes(out))
4205
                }
4206
0
                MemAccessVm::Running(ref vm) => {
4207
0
                    let partial_bytes = vm
4208
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4209
0
                        .unwrap_or_else(|_| unreachable!());
4210
0
                    let partial_bytes = partial_bytes.as_ref();
4211
0
                    debug_assert!(partial_bytes.len() < 8);
4212
4213
0
                    let mut out = [0; 8];
4214
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4215
0
                    Ok(u64::from_le_bytes(out))
4216
                }
4217
            }
4218
        } else {
4219
            // Everything out bounds. Memory is zero.
4220
0
            Ok(0)
4221
        }
4222
27.0k
    }
_RNvXsN_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory11read_le_u64
Line
Count
Source
4153
2.94k
    fn read_le_u64(&self, ptr: u32) -> Result<u64, allocator::Error> {
4154
2.94k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4155
0
            return Err(allocator::Error::Other);
4156
2.94k
        }
4157
2.94k
4158
2.94k
        // Note that this function (`read_le_u64`) really should take ̀`&mut self` but that is
4159
2.94k
        // unfortunately not the case, meaning that we can't "just" grow the memory if trying
4160
2.94k
        // to access an out of bound location.
4161
2.94k
        //
4162
2.94k
        // Additionally, the value being read can in theory overlap between an allocated and
4163
2.94k
        // non-allocated parts of the memory, making this more complicated.
4164
2.94k
4165
2.94k
        // Offset of the memory page where the first byte of the value will be read.
4166
2.94k
        let accessed_memory_page_start = HeapPages::new(ptr / (64 * 1024));
4167
2.94k
        // Offset of the memory page where the last byte of the value will be read.
4168
2.94k
        let accessed_memory_page_end = HeapPages::new((ptr + 7) / (64 * 1024));
4169
        // Number of pages currently allocated.
4170
2.94k
        let current_num_pages = match self.vm {
4171
0
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4172
2.94k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4173
        };
4174
2.94k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4175
4176
2.94k
        if accessed_memory_page_end < current_num_pages {
4177
            // This is the simple case: the memory access is in bounds.
4178
2.94k
            match self.vm {
4179
0
                MemAccessVm::Prepare(ref vm) => {
4180
0
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4181
0
                    Ok(u64::from_le_bytes(
4182
0
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4183
0
                    ))
4184
                }
4185
2.94k
                MemAccessVm::Running(ref vm) => {
4186
2.94k
                    let bytes = vm.read_memory(ptr, 8).unwrap_or_else(|_| unreachable!());
4187
2.94k
                    Ok(u64::from_le_bytes(
4188
2.94k
                        <[u8; 8]>::try_from(bytes.as_ref()).unwrap_or_else(|_| unreachable!()),
4189
2.94k
                    ))
4190
                }
4191
            }
4192
0
        } else if accessed_memory_page_start < current_num_pages {
4193
            // Memory access is partially in bounds. This is the most complicated situation.
4194
0
            match self.vm {
4195
0
                MemAccessVm::Prepare(ref vm) => {
4196
0
                    let partial_bytes = vm
4197
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4198
0
                        .unwrap_or_else(|_| unreachable!());
4199
0
                    let partial_bytes = partial_bytes.as_ref();
4200
0
                    debug_assert!(partial_bytes.len() < 8);
4201
4202
0
                    let mut out = [0; 8];
4203
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4204
0
                    Ok(u64::from_le_bytes(out))
4205
                }
4206
0
                MemAccessVm::Running(ref vm) => {
4207
0
                    let partial_bytes = vm
4208
0
                        .read_memory(ptr, u32::from(current_num_pages) * 64 * 1024 - ptr)
4209
0
                        .unwrap_or_else(|_| unreachable!());
4210
0
                    let partial_bytes = partial_bytes.as_ref();
4211
0
                    debug_assert!(partial_bytes.len() < 8);
4212
4213
0
                    let mut out = [0; 8];
4214
0
                    out[..partial_bytes.len()].copy_from_slice(partial_bytes);
4215
0
                    Ok(u64::from_le_bytes(out))
4216
                }
4217
            }
4218
        } else {
4219
            // Everything out bounds. Memory is zero.
4220
0
            Ok(0)
4221
        }
4222
2.94k
    }
4223
4224
33.8k
    fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), allocator::Error> {
4225
33.8k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4226
0
            return Err(allocator::Error::Other);
4227
33.8k
        }
4228
33.8k
4229
33.8k
        let bytes = val.to_le_bytes();
4230
33.8k
4231
33.8k
        // Offset of the memory page where the last byte of the value will be written.
4232
33.8k
        let written_memory_page = HeapPages::new((ptr + 7) / (64 * 1024));
4233
4234
        // Grow the memory more if necessary.
4235
        // Please note the `<=`. For example if we write to page 0, we want to have at least 1 page
4236
        // allocated.
4237
33.8k
        let current_num_pages = match self.vm {
4238
179
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4239
33.6k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4240
        };
4241
33.8k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4242
33.8k
        if current_num_pages <= written_memory_page {
4243
            // For now, we grow the memory just enough to fit.
4244
            // TODO: do better
4245
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
4246
            // in case `written_memory_page` is the maximum possible value.
4247
19
            let to_grow = written_memory_page - current_num_pages + HeapPages::new(1);
4248
19
4249
19
            // We check at initialization that the virtual machine is capable of growing up to
4250
19
            // `memory_total_pages`, meaning that this can't panic.
4251
19
            match self.vm {
4252
14
                MemAccessVm::Prepare(ref mut vm) => {
4253
14
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4254
                }
4255
5
                MemAccessVm::Running(ref mut vm) => {
4256
5
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4257
                }
4258
            }
4259
33.7k
        }
4260
4261
33.8k
        match self.vm {
4262
179
            MemAccessVm::Prepare(ref mut vm) => vm
4263
179
                .write_memory(ptr, &bytes)
4264
179
                .unwrap_or_else(|_| unreachable!()),
4265
33.6k
            MemAccessVm::Running(ref mut vm) => vm
4266
33.6k
                .write_memory(ptr, &bytes)
4267
33.6k
                .unwrap_or_else(|_| unreachable!()),
4268
        }
4269
33.8k
        Ok(())
4270
33.8k
    }
_RNvXsN_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory12write_le_u64
Line
Count
Source
4224
28.7k
    fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), allocator::Error> {
4225
28.7k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4226
0
            return Err(allocator::Error::Other);
4227
28.7k
        }
4228
28.7k
4229
28.7k
        let bytes = val.to_le_bytes();
4230
28.7k
4231
28.7k
        // Offset of the memory page where the last byte of the value will be written.
4232
28.7k
        let written_memory_page = HeapPages::new((ptr + 7) / (64 * 1024));
4233
4234
        // Grow the memory more if necessary.
4235
        // Please note the `<=`. For example if we write to page 0, we want to have at least 1 page
4236
        // allocated.
4237
28.7k
        let current_num_pages = match self.vm {
4238
52
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4239
28.6k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4240
        };
4241
28.7k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4242
28.7k
        if current_num_pages <= written_memory_page {
4243
            // For now, we grow the memory just enough to fit.
4244
            // TODO: do better
4245
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
4246
            // in case `written_memory_page` is the maximum possible value.
4247
18
            let to_grow = written_memory_page - current_num_pages + HeapPages::new(1);
4248
18
4249
18
            // We check at initialization that the virtual machine is capable of growing up to
4250
18
            // `memory_total_pages`, meaning that this can't panic.
4251
18
            match self.vm {
4252
14
                MemAccessVm::Prepare(ref mut vm) => {
4253
14
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4254
                }
4255
4
                MemAccessVm::Running(ref mut vm) => {
4256
4
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4257
                }
4258
            }
4259
28.7k
        }
4260
4261
28.7k
        match self.vm {
4262
52
            MemAccessVm::Prepare(ref mut vm) => vm
4263
52
                .write_memory(ptr, &bytes)
4264
52
                .unwrap_or_else(|_| unreachable!()),
4265
28.6k
            MemAccessVm::Running(ref mut vm) => vm
4266
28.6k
                .write_memory(ptr, &bytes)
4267
28.6k
                .unwrap_or_else(|_| unreachable!()),
4268
        }
4269
28.7k
        Ok(())
4270
28.7k
    }
_RNvXsN_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory12write_le_u64
Line
Count
Source
4224
5.07k
    fn write_le_u64(&mut self, ptr: u32, val: u64) -> Result<(), allocator::Error> {
4225
5.07k
        if (ptr + 8) > u32::from(self.memory_total_pages) * 64 * 1024 {
4226
0
            return Err(allocator::Error::Other);
4227
5.07k
        }
4228
5.07k
4229
5.07k
        let bytes = val.to_le_bytes();
4230
5.07k
4231
5.07k
        // Offset of the memory page where the last byte of the value will be written.
4232
5.07k
        let written_memory_page = HeapPages::new((ptr + 7) / (64 * 1024));
4233
4234
        // Grow the memory more if necessary.
4235
        // Please note the `<=`. For example if we write to page 0, we want to have at least 1 page
4236
        // allocated.
4237
5.07k
        let current_num_pages = match self.vm {
4238
127
            MemAccessVm::Prepare(ref vm) => vm.memory_size(),
4239
4.94k
            MemAccessVm::Running(ref vm) => vm.memory_size(),
4240
        };
4241
5.07k
        debug_assert!(current_num_pages <= self.memory_total_pages);
4242
5.07k
        if current_num_pages <= written_memory_page {
4243
            // For now, we grow the memory just enough to fit.
4244
            // TODO: do better
4245
            // Note the order of operations: we add 1 at the end to avoid a potential overflow
4246
            // in case `written_memory_page` is the maximum possible value.
4247
1
            let to_grow = written_memory_page - current_num_pages + HeapPages::new(1);
4248
1
4249
1
            // We check at initialization that the virtual machine is capable of growing up to
4250
1
            // `memory_total_pages`, meaning that this can't panic.
4251
1
            match self.vm {
4252
0
                MemAccessVm::Prepare(ref mut vm) => {
4253
0
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4254
                }
4255
1
                MemAccessVm::Running(ref mut vm) => {
4256
1
                    vm.grow_memory(to_grow).unwrap_or_else(|_| unreachable!())
4257
                }
4258
            }
4259
5.07k
        }
4260
4261
5.07k
        match self.vm {
4262
127
            MemAccessVm::Prepare(ref mut vm) => vm
4263
127
                .write_memory(ptr, &bytes)
4264
127
                .unwrap_or_else(|_| unreachable!()),
4265
4.94k
            MemAccessVm::Running(ref mut vm) => vm
4266
4.94k
                .write_memory(ptr, &bytes)
4267
4.94k
                .unwrap_or_else(|_| unreachable!()),
4268
        }
4269
5.07k
        Ok(())
4270
5.07k
    }
4271
4272
84.6k
    fn size(&self) -> u32 {
4273
84.6k
        // Lie to the allocator to pretend that `memory_total_pages` are available.
4274
84.6k
        u32::from(self.memory_total_pages)
4275
84.6k
            .saturating_mul(64)
4276
84.6k
            .saturating_mul(1024)
4277
84.6k
    }
_RNvXsN_NtNtCs2njt72CfVQ4_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory4size
Line
Count
Source
4272
71.8k
    fn size(&self) -> u32 {
4273
71.8k
        // Lie to the allocator to pretend that `memory_total_pages` are available.
4274
71.8k
        u32::from(self.memory_total_pages)
4275
71.8k
            .saturating_mul(64)
4276
71.8k
            .saturating_mul(1024)
4277
71.8k
    }
_RNvXsN_NtNtCsdl8uvwe7U3b_7smoldot8executor4hostNtB5_9MemAccessNtNtB7_9allocator6Memory4size
Line
Count
Source
4272
12.8k
    fn size(&self) -> u32 {
4273
12.8k
        // Lie to the allocator to pretend that `memory_total_pages` are available.
4274
12.8k
        u32::from(self.memory_total_pages)
4275
12.8k
            .saturating_mul(64)
4276
12.8k
            .saturating_mul(1024)
4277
12.8k
    }
4278
}