/__w/smoldot/smoldot/repo/lib/src/author/runtime.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2020 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 | | //! Block generation system. |
19 | | //! |
20 | | //! This module provides the actual block generation code. The output is an unsealed header and |
21 | | //! body. |
22 | | //! |
23 | | //! After a block has been generated, it must still be sealed (in other words, signed by its |
24 | | //! author) by adding a corresponding entry to the log items in its header. This is out of scope |
25 | | //! of this module. |
26 | | //! |
27 | | //! # Detail |
28 | | //! |
29 | | //! Building a block consists in four steps: |
30 | | //! |
31 | | //! - A runtime call to `Core_initialize_block`, passing a header prototype as input. This call |
32 | | //! performs some initial storage writes. |
33 | | //! - A runtime call to `BlockBuilder_inherent_extrinsics`, passing as input a list of |
34 | | //! *intrinsics*. This pure call returns a list of extrinsics. |
35 | | //! - Zero or more runtime calls to `BlockBuilder_apply_extrinsic`, passing as input an extrinsic. |
36 | | //! This must be done once per extrinsic returned by the previous step, plus once for each |
37 | | //! transaction to push in the block. |
38 | | //! - A runtime call to `BlockBuilder_finalize_block`, which returns the newly-created unsealed |
39 | | //! block header. |
40 | | //! |
41 | | //! The body of the newly-generated block consists in the extrinsics pushed using |
42 | | //! `BlockBuilder_apply_extrinsic` (including the intrinsics). |
43 | | //! |
44 | | |
45 | | // TODO: expand docs |
46 | | // TODO: explain what an inherent extrinsic is |
47 | | |
48 | | mod tests; |
49 | | |
50 | | use crate::{ |
51 | | executor::{host, runtime_call}, |
52 | | header, util, |
53 | | verify::inherents, |
54 | | }; |
55 | | |
56 | | use alloc::{borrow::ToOwned as _, vec::Vec}; |
57 | | use core::{iter, mem}; |
58 | | |
59 | | pub use runtime_call::{ |
60 | | Nibble, StorageChanges, TrieChange, TrieChangeStorageValue, TrieEntryVersion, |
61 | | }; |
62 | | |
63 | | /// Configuration for a block generation. |
64 | | pub struct Config<'a> { |
65 | | /// Number of bytes used to encode block numbers in the header. |
66 | | pub block_number_bytes: usize, |
67 | | |
68 | | /// Hash of the parent of the block to generate. |
69 | | /// |
70 | | /// Used to populate the header of the new block. |
71 | | pub parent_hash: &'a [u8; 32], |
72 | | |
73 | | /// Height of the parent of the block to generate. |
74 | | /// |
75 | | /// Used to populate the header of the new block. |
76 | | pub parent_number: u64, |
77 | | |
78 | | /// Runtime used to check the new block. Must be built using the Wasm code found at the |
79 | | /// `:code` key of the parent block storage. |
80 | | pub parent_runtime: host::HostVmPrototype, |
81 | | |
82 | | /// Consensus-specific item to put in the digest of the header prototype. |
83 | | /// |
84 | | /// > **Note**: In the case of Aura and Babe, contains the slot being claimed. |
85 | | pub consensus_digest_log_item: ConfigPreRuntime<'a>, |
86 | | |
87 | | /// Capacity to reserve for the number of extrinsics. Should be higher than the approximate |
88 | | /// number of extrinsics that are going to be applied. |
89 | | pub block_body_capacity: usize, |
90 | | |
91 | | /// Maximum log level of the runtime. |
92 | | /// |
93 | | /// > **Note**: This value is opaque from the point of the view of the client, and the runtime |
94 | | /// > is free to interpret it the way it wants. However, usually values are: `0` for |
95 | | /// > "off", `1` for "error", `2` for "warn", `3` for "info", `4` for "debug", |
96 | | /// > and `5` for "trace". |
97 | | pub max_log_level: u32, |
98 | | |
99 | | /// If `true`, then [`StorageChanges::trie_changes_iter_ordered`] will return `Some`. |
100 | | /// Passing `None` requires fewer calculation and fewer storage accesses. |
101 | | pub calculate_trie_changes: bool, |
102 | | } |
103 | | |
104 | | /// Extra configuration depending on the consensus algorithm. |
105 | | // TODO: consider not exposing `header` in the API |
106 | | pub enum ConfigPreRuntime<'a> { |
107 | | /// Chain uses the Aura consensus algorithm. |
108 | | Aura(header::AuraPreDigest), |
109 | | /// Chain uses the Babe consensus algorithm. |
110 | | Babe(header::BabePreDigestRef<'a>), |
111 | | } |
112 | | |
113 | | /// Block successfully verified. |
114 | | pub struct Success { |
115 | | /// SCALE-encoded header of the produced block. |
116 | | pub scale_encoded_header: Vec<u8>, |
117 | | /// Body of the produced block. |
118 | | pub body: Vec<Vec<u8>>, |
119 | | /// Runtime that was passed by [`Config`]. |
120 | | pub parent_runtime: host::HostVmPrototype, |
121 | | /// List of changes to the storage main trie that the block performs. |
122 | | pub storage_changes: StorageChanges, |
123 | | /// State trie version indicated by the runtime. All the storage changes indicated by |
124 | | /// [`Success::storage_changes`] should store this version alongside with them. |
125 | | pub state_trie_version: TrieEntryVersion, |
126 | | } |
127 | | |
128 | | /// Error that can happen during the block production. |
129 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXs6_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_5ErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs6_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_5ErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
130 | | pub enum Error { |
131 | | /// Error while executing the Wasm virtual machine. |
132 | | #[display(fmt = "{_0}")] |
133 | | WasmVm(runtime_call::ErrorDetail), |
134 | | /// Error while initializing the Wasm virtual machine. |
135 | | #[display(fmt = "{_0}")] |
136 | | VmInit(host::StartErr), |
137 | | /// Overflow when incrementing block height. |
138 | | BlockHeightOverflow, |
139 | | /// `Core_initialize_block` has returned a non-empty output. |
140 | | InitializeBlockNonEmptyOutput, |
141 | | /// Error while parsing output of `BlockBuilder_inherent_extrinsics`. |
142 | | BadInherentExtrinsicsOutput, |
143 | | /// Error while parsing output of `BlockBuilder_apply_extrinsic`. |
144 | | BadApplyExtrinsicOutput, |
145 | | /// Applying an inherent extrinsic has returned a [`DispatchError`]. |
146 | | #[display(fmt = "Error while applying inherent extrinsic: {error}\nExtrinsic: {extrinsic:?}")] |
147 | | InherentExtrinsicDispatchError { |
148 | | /// Extrinsic that triggered the problem. |
149 | | extrinsic: Vec<u8>, |
150 | | /// Error returned by the runtime. |
151 | | error: DispatchError, |
152 | | }, |
153 | | /// Applying an inherent extrinsic has returned a [`TransactionValidityError`]. |
154 | | #[display(fmt = "Error while applying inherent extrinsic: {error}\nExtrinsic: {extrinsic:?}")] |
155 | | InherentExtrinsicTransactionValidityError { |
156 | | /// Extrinsic that triggered the problem. |
157 | | extrinsic: Vec<u8>, |
158 | | /// Error returned by the runtime. |
159 | | error: TransactionValidityError, |
160 | | }, |
161 | | } |
162 | | |
163 | | /// Start a block building process. |
164 | 1 | pub fn build_block(config: Config) -> BlockBuild { |
165 | 1 | let init_result = runtime_call::run(runtime_call::Config { |
166 | 1 | function_to_call: "Core_initialize_block", |
167 | 1 | parameter: { |
168 | 1 | // The `Core_initialize_block` function expects a SCALE-encoded partially-initialized |
169 | 1 | // header. |
170 | 1 | header::HeaderRef { |
171 | 1 | parent_hash: config.parent_hash, |
172 | 1 | number: match config.parent_number.checked_add(1) { |
173 | 1 | Some(n) => n, |
174 | | None => { |
175 | 0 | return BlockBuild::Finished(Err(( |
176 | 0 | Error::BlockHeightOverflow, |
177 | 0 | config.parent_runtime, |
178 | 0 | ))) |
179 | | } |
180 | | }, |
181 | 1 | extrinsics_root: &[0; 32], |
182 | 1 | state_root: &[0; 32], |
183 | 1 | digest: header::DigestRef::from_slice(&[match config.consensus_digest_log_item { |
184 | 1 | ConfigPreRuntime::Aura(item) => header::DigestItem::AuraPreDigest(item), |
185 | 0 | ConfigPreRuntime::Babe(item) => header::DigestItem::BabePreDigest(item.into()), |
186 | | }]) |
187 | 1 | .unwrap(), |
188 | 1 | } |
189 | 1 | .scale_encoding(config.block_number_bytes) |
190 | 1 | }, |
191 | 1 | virtual_machine: config.parent_runtime, |
192 | 1 | storage_main_trie_changes: Default::default(), |
193 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, |
194 | 1 | max_log_level: config.max_log_level, |
195 | 1 | calculate_trie_changes: config.calculate_trie_changes, |
196 | | }); |
197 | | |
198 | 1 | let vm = match init_result { |
199 | 1 | Ok(vm) => vm, |
200 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), |
201 | | }; |
202 | | |
203 | 1 | let shared = Shared { |
204 | 1 | stage: Stage::InitializeBlock, |
205 | 1 | block_body: Vec::with_capacity(config.block_body_capacity), |
206 | 1 | max_log_level: config.max_log_level, |
207 | 1 | calculate_trie_changes: config.calculate_trie_changes, |
208 | 1 | }; |
209 | 1 | |
210 | 1 | BlockBuild::from_inner(vm, shared) |
211 | 1 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime11build_block Line | Count | Source | 164 | 1 | pub fn build_block(config: Config) -> BlockBuild { | 165 | 1 | let init_result = runtime_call::run(runtime_call::Config { | 166 | 1 | function_to_call: "Core_initialize_block", | 167 | 1 | parameter: { | 168 | 1 | // The `Core_initialize_block` function expects a SCALE-encoded partially-initialized | 169 | 1 | // header. | 170 | 1 | header::HeaderRef { | 171 | 1 | parent_hash: config.parent_hash, | 172 | 1 | number: match config.parent_number.checked_add(1) { | 173 | 1 | Some(n) => n, | 174 | | None => { | 175 | 0 | return BlockBuild::Finished(Err(( | 176 | 0 | Error::BlockHeightOverflow, | 177 | 0 | config.parent_runtime, | 178 | 0 | ))) | 179 | | } | 180 | | }, | 181 | 1 | extrinsics_root: &[0; 32], | 182 | 1 | state_root: &[0; 32], | 183 | 1 | digest: header::DigestRef::from_slice(&[match config.consensus_digest_log_item { | 184 | 1 | ConfigPreRuntime::Aura(item) => header::DigestItem::AuraPreDigest(item), | 185 | 0 | ConfigPreRuntime::Babe(item) => header::DigestItem::BabePreDigest(item.into()), | 186 | | }]) | 187 | 1 | .unwrap(), | 188 | 1 | } | 189 | 1 | .scale_encoding(config.block_number_bytes) | 190 | 1 | }, | 191 | 1 | virtual_machine: config.parent_runtime, | 192 | 1 | storage_main_trie_changes: Default::default(), | 193 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, | 194 | 1 | max_log_level: config.max_log_level, | 195 | 1 | calculate_trie_changes: config.calculate_trie_changes, | 196 | | }); | 197 | | | 198 | 1 | let vm = match init_result { | 199 | 1 | Ok(vm) => vm, | 200 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), | 201 | | }; | 202 | | | 203 | 1 | let shared = Shared { | 204 | 1 | stage: Stage::InitializeBlock, | 205 | 1 | block_body: Vec::with_capacity(config.block_body_capacity), | 206 | 1 | max_log_level: config.max_log_level, | 207 | 1 | calculate_trie_changes: config.calculate_trie_changes, | 208 | 1 | }; | 209 | 1 | | 210 | 1 | BlockBuild::from_inner(vm, shared) | 211 | 1 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime11build_block |
212 | | |
213 | | /// Current state of the block building process. |
214 | | #[must_use] |
215 | | pub enum BlockBuild { |
216 | | /// Block generation is over. |
217 | | Finished(Result<Success, (Error, host::HostVmPrototype)>), |
218 | | |
219 | | /// The inherent extrinsics are required in order to continue. |
220 | | /// |
221 | | /// [`BlockBuild::InherentExtrinsics`] is guaranteed to only be emitted once per block |
222 | | /// building process. |
223 | | /// |
224 | | /// The extrinsics returned by the call to `BlockBuilder_inherent_extrinsics` are |
225 | | /// automatically pushed to the runtime. |
226 | | InherentExtrinsics(InherentExtrinsics), |
227 | | |
228 | | /// Block building is ready to accept extrinsics. |
229 | | /// |
230 | | /// If [`ApplyExtrinsic::add_extrinsic`] is used, then a [`BlockBuild::ApplyExtrinsicResult`] |
231 | | /// stage will be emitted later. |
232 | | /// |
233 | | /// > **Note**: These extrinsics are generally coming from a transactions pool, but this is |
234 | | /// > out of scope of this module. |
235 | | ApplyExtrinsic(ApplyExtrinsic), |
236 | | |
237 | | /// Result of the previous call to [`ApplyExtrinsic::add_extrinsic`]. |
238 | | /// |
239 | | /// An [`ApplyExtrinsic`] object is provided in order to continue the operation. |
240 | | ApplyExtrinsicResult { |
241 | | /// Result of the previous call to [`ApplyExtrinsic::add_extrinsic`]. |
242 | | result: Result<Result<(), DispatchError>, TransactionValidityError>, |
243 | | /// Object to use to continue trying to push other transactions or finish the block. |
244 | | resume: ApplyExtrinsic, |
245 | | }, |
246 | | |
247 | | /// Loading a storage value from the parent storage is required in order to continue. |
248 | | StorageGet(StorageGet), |
249 | | |
250 | | /// Obtaining the Merkle value of the closest descendant of a trie node is required in order |
251 | | /// to continue. |
252 | | ClosestDescendantMerkleValue(ClosestDescendantMerkleValue), |
253 | | |
254 | | /// Fetching the key that follows a given one in the parent storage is required in order to |
255 | | /// continue. |
256 | | NextKey(NextKey), |
257 | | |
258 | | /// Setting an offchain storage value is required in order to continue. |
259 | | OffchainStorageSet(OffchainStorageSet), |
260 | | } |
261 | | |
262 | | impl BlockBuild { |
263 | 4.20k | fn from_inner(inner: runtime_call::RuntimeCall, mut shared: Shared) -> Self { |
264 | 4.20k | enum Inner { |
265 | 4.20k | Runtime(runtime_call::RuntimeCall), |
266 | 4.20k | Transition(runtime_call::Success), |
267 | 4.20k | } |
268 | 4.20k | |
269 | 4.20k | let mut inner = Inner::Runtime(inner); |
270 | | |
271 | | loop { |
272 | 4.20k | match (inner, &mut shared.stage) { |
273 | 0 | (Inner::Runtime(runtime_call::RuntimeCall::Finished(Err(err))), _) => { |
274 | 0 | return BlockBuild::Finished(Err((Error::WasmVm(err.detail), err.prototype))); |
275 | | } |
276 | 146 | (Inner::Runtime(runtime_call::RuntimeCall::StorageGet(inner)), _) => { |
277 | 146 | return BlockBuild::StorageGet(StorageGet(inner, shared)) |
278 | | } |
279 | | ( |
280 | 1.86k | Inner::Runtime(runtime_call::RuntimeCall::ClosestDescendantMerkleValue(inner)), |
281 | 1.86k | _, |
282 | 1.86k | ) => { |
283 | 1.86k | return BlockBuild::ClosestDescendantMerkleValue(ClosestDescendantMerkleValue( |
284 | 1.86k | inner, shared, |
285 | 1.86k | )) |
286 | | } |
287 | 2.19k | (Inner::Runtime(runtime_call::RuntimeCall::NextKey(inner)), _) => { |
288 | 2.19k | return BlockBuild::NextKey(NextKey(inner, shared)) |
289 | | } |
290 | 0 | (Inner::Runtime(runtime_call::RuntimeCall::OffchainStorageSet(inner)), _) => { |
291 | 0 | return BlockBuild::OffchainStorageSet(OffchainStorageSet(inner, shared)) |
292 | | } |
293 | | |
294 | | ( |
295 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), |
296 | 1 | Stage::InitializeBlock, |
297 | 1 | ) => { |
298 | 1 | if !success.virtual_machine.value().as_ref().is_empty() { |
299 | 0 | return BlockBuild::Finished(Err(( |
300 | 0 | Error::InitializeBlockNonEmptyOutput, |
301 | 0 | success.virtual_machine.into_prototype(), |
302 | 0 | ))); |
303 | 1 | } |
304 | 1 | |
305 | 1 | shared.stage = Stage::InherentExtrinsics; |
306 | 1 | |
307 | 1 | return BlockBuild::InherentExtrinsics(InherentExtrinsics { |
308 | 1 | shared, |
309 | 1 | parent_runtime: success.virtual_machine.into_prototype(), |
310 | 1 | storage_changes: success.storage_changes, |
311 | 1 | }); |
312 | | } |
313 | | |
314 | | ( |
315 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), |
316 | 1 | Stage::InherentExtrinsics, |
317 | 1 | ) => { |
318 | 1 | let parse_result = |
319 | 1 | parse_inherent_extrinsics_output(success.virtual_machine.value().as_ref()); |
320 | 1 | let extrinsics = match parse_result { |
321 | 1 | Ok(extrinsics) => extrinsics, |
322 | 0 | Err(err) => { |
323 | 0 | return BlockBuild::Finished(Err(( |
324 | 0 | err, |
325 | 0 | success.virtual_machine.into_prototype(), |
326 | 0 | ))) |
327 | | } |
328 | | }; |
329 | | |
330 | 1 | shared.block_body.reserve(extrinsics.len()); |
331 | 1 | shared.stage = Stage::ApplyInherentExtrinsic { extrinsics }; |
332 | 1 | inner = Inner::Transition(success); |
333 | | } |
334 | | |
335 | 2 | (Inner::Transition(success1 ), Stage::ApplyInherentExtrinsic { extrinsics }) |
336 | 2 | if !extrinsics.is_empty() => |
337 | 1 | { |
338 | 1 | let extrinsic = &extrinsics[0]; |
339 | 1 | |
340 | 1 | let init_result = runtime_call::run(runtime_call::Config { |
341 | 1 | virtual_machine: success.virtual_machine.into_prototype(), |
342 | 1 | function_to_call: "BlockBuilder_apply_extrinsic", |
343 | 1 | parameter: iter::once(extrinsic), |
344 | 1 | storage_main_trie_changes: success.storage_changes.into_main_trie_diff(), |
345 | 1 | storage_proof_size_behavior: |
346 | 1 | runtime_call::StorageProofSizeBehavior::Unimplemented, |
347 | 1 | max_log_level: shared.max_log_level, |
348 | 1 | calculate_trie_changes: shared.calculate_trie_changes, |
349 | 1 | }); |
350 | | |
351 | 1 | inner = Inner::Runtime(match init_result { |
352 | 1 | Ok(vm) => vm, |
353 | 0 | Err((err, proto)) => { |
354 | 0 | return BlockBuild::Finished(Err((Error::VmInit(err), proto))) |
355 | | } |
356 | | }); |
357 | | } |
358 | | |
359 | 1 | (Inner::Transition(success), Stage::ApplyInherentExtrinsic { .. }) => { |
360 | 1 | return BlockBuild::ApplyExtrinsic(ApplyExtrinsic { |
361 | 1 | shared, |
362 | 1 | parent_runtime: success.virtual_machine.into_prototype(), |
363 | 1 | storage_changes: success.storage_changes, |
364 | 1 | }); |
365 | | } |
366 | | |
367 | | ( |
368 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), |
369 | | Stage::ApplyInherentExtrinsic { .. }, |
370 | | ) => { |
371 | 1 | let (extrinsic, new_stage) = match shared.stage { |
372 | 1 | Stage::ApplyInherentExtrinsic { mut extrinsics } => { |
373 | 1 | let extrinsic = extrinsics.remove(0); |
374 | 1 | (extrinsic, Stage::ApplyInherentExtrinsic { extrinsics }) |
375 | | } |
376 | 0 | _ => unreachable!(), |
377 | | }; |
378 | | |
379 | 1 | shared.stage = new_stage; |
380 | 1 | |
381 | 1 | let parse_result = |
382 | 1 | parse_apply_extrinsic_output(success.virtual_machine.value().as_ref()); |
383 | 1 | match parse_result { |
384 | 1 | Ok(Ok(Ok(()))) => {} |
385 | 0 | Ok(Ok(Err(error))) => { |
386 | 0 | return BlockBuild::Finished(Err(( |
387 | 0 | Error::InherentExtrinsicDispatchError { extrinsic, error }, |
388 | 0 | success.virtual_machine.into_prototype(), |
389 | 0 | ))) |
390 | | } |
391 | 0 | Ok(Err(error)) => { |
392 | 0 | return BlockBuild::Finished(Err(( |
393 | 0 | Error::InherentExtrinsicTransactionValidityError { |
394 | 0 | extrinsic, |
395 | 0 | error, |
396 | 0 | }, |
397 | 0 | success.virtual_machine.into_prototype(), |
398 | 0 | ))) |
399 | | } |
400 | 0 | Err(err) => { |
401 | 0 | return BlockBuild::Finished(Err(( |
402 | 0 | err, |
403 | 0 | success.virtual_machine.into_prototype(), |
404 | 0 | ))) |
405 | | } |
406 | | } |
407 | | |
408 | 1 | shared.block_body.push(extrinsic); |
409 | 1 | |
410 | 1 | inner = Inner::Transition(success); |
411 | | } |
412 | | |
413 | | ( |
414 | 0 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), |
415 | 0 | Stage::ApplyExtrinsic(_), |
416 | 0 | ) => { |
417 | 0 | let parse_result = |
418 | 0 | parse_apply_extrinsic_output(success.virtual_machine.value().as_ref()); |
419 | 0 | let result = match parse_result { |
420 | 0 | Ok(r) => r, |
421 | 0 | Err(err) => { |
422 | 0 | return BlockBuild::Finished(Err(( |
423 | 0 | err, |
424 | 0 | success.virtual_machine.into_prototype(), |
425 | 0 | ))) |
426 | | } |
427 | | }; |
428 | | |
429 | 0 | if result.is_ok() { |
430 | 0 | shared.block_body.push(match &mut shared.stage { |
431 | 0 | Stage::ApplyExtrinsic(ext) => mem::take(ext), |
432 | 0 | _ => unreachable!(), |
433 | | }); |
434 | 0 | } |
435 | | |
436 | | // TODO: consider giving back extrinsic to user in case of failure |
437 | | |
438 | | // TODO: IMPORTANT /!\ must throw away storage changes in case of error |
439 | | |
440 | 0 | return BlockBuild::ApplyExtrinsicResult { |
441 | 0 | result, |
442 | 0 | resume: ApplyExtrinsic { |
443 | 0 | shared, |
444 | 0 | parent_runtime: success.virtual_machine.into_prototype(), |
445 | 0 | storage_changes: success.storage_changes, |
446 | 0 | }, |
447 | 0 | }; |
448 | | } |
449 | | |
450 | | ( |
451 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), |
452 | 1 | Stage::FinalizeBlock, |
453 | 1 | ) => { |
454 | 1 | let scale_encoded_header = success.virtual_machine.value().as_ref().to_owned(); |
455 | 1 | return BlockBuild::Finished(Ok(Success { |
456 | 1 | scale_encoded_header, |
457 | 1 | body: shared.block_body, |
458 | 1 | parent_runtime: success.virtual_machine.into_prototype(), |
459 | 1 | storage_changes: success.storage_changes, |
460 | 1 | state_trie_version: success.state_trie_version, |
461 | 1 | })); |
462 | | } |
463 | | |
464 | | // TODO: what about SignatureVerification and EmitLog? at the time of writing of this comment, it's not worth fixing as this code would get removed by <https://github.com/smol-dot/smoldot/issues/1517> |
465 | 0 | (_, s) => unreachable!("{:?}", s), |
466 | | } |
467 | | } |
468 | 4.20k | } _RNvMNtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB2_10BlockBuild10from_inner Line | Count | Source | 263 | 4.20k | fn from_inner(inner: runtime_call::RuntimeCall, mut shared: Shared) -> Self { | 264 | 4.20k | enum Inner { | 265 | 4.20k | Runtime(runtime_call::RuntimeCall), | 266 | 4.20k | Transition(runtime_call::Success), | 267 | 4.20k | } | 268 | 4.20k | | 269 | 4.20k | let mut inner = Inner::Runtime(inner); | 270 | | | 271 | | loop { | 272 | 4.20k | match (inner, &mut shared.stage) { | 273 | 0 | (Inner::Runtime(runtime_call::RuntimeCall::Finished(Err(err))), _) => { | 274 | 0 | return BlockBuild::Finished(Err((Error::WasmVm(err.detail), err.prototype))); | 275 | | } | 276 | 146 | (Inner::Runtime(runtime_call::RuntimeCall::StorageGet(inner)), _) => { | 277 | 146 | return BlockBuild::StorageGet(StorageGet(inner, shared)) | 278 | | } | 279 | | ( | 280 | 1.86k | Inner::Runtime(runtime_call::RuntimeCall::ClosestDescendantMerkleValue(inner)), | 281 | 1.86k | _, | 282 | 1.86k | ) => { | 283 | 1.86k | return BlockBuild::ClosestDescendantMerkleValue(ClosestDescendantMerkleValue( | 284 | 1.86k | inner, shared, | 285 | 1.86k | )) | 286 | | } | 287 | 2.19k | (Inner::Runtime(runtime_call::RuntimeCall::NextKey(inner)), _) => { | 288 | 2.19k | return BlockBuild::NextKey(NextKey(inner, shared)) | 289 | | } | 290 | 0 | (Inner::Runtime(runtime_call::RuntimeCall::OffchainStorageSet(inner)), _) => { | 291 | 0 | return BlockBuild::OffchainStorageSet(OffchainStorageSet(inner, shared)) | 292 | | } | 293 | | | 294 | | ( | 295 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), | 296 | 1 | Stage::InitializeBlock, | 297 | 1 | ) => { | 298 | 1 | if !success.virtual_machine.value().as_ref().is_empty() { | 299 | 0 | return BlockBuild::Finished(Err(( | 300 | 0 | Error::InitializeBlockNonEmptyOutput, | 301 | 0 | success.virtual_machine.into_prototype(), | 302 | 0 | ))); | 303 | 1 | } | 304 | 1 | | 305 | 1 | shared.stage = Stage::InherentExtrinsics; | 306 | 1 | | 307 | 1 | return BlockBuild::InherentExtrinsics(InherentExtrinsics { | 308 | 1 | shared, | 309 | 1 | parent_runtime: success.virtual_machine.into_prototype(), | 310 | 1 | storage_changes: success.storage_changes, | 311 | 1 | }); | 312 | | } | 313 | | | 314 | | ( | 315 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), | 316 | 1 | Stage::InherentExtrinsics, | 317 | 1 | ) => { | 318 | 1 | let parse_result = | 319 | 1 | parse_inherent_extrinsics_output(success.virtual_machine.value().as_ref()); | 320 | 1 | let extrinsics = match parse_result { | 321 | 1 | Ok(extrinsics) => extrinsics, | 322 | 0 | Err(err) => { | 323 | 0 | return BlockBuild::Finished(Err(( | 324 | 0 | err, | 325 | 0 | success.virtual_machine.into_prototype(), | 326 | 0 | ))) | 327 | | } | 328 | | }; | 329 | | | 330 | 1 | shared.block_body.reserve(extrinsics.len()); | 331 | 1 | shared.stage = Stage::ApplyInherentExtrinsic { extrinsics }; | 332 | 1 | inner = Inner::Transition(success); | 333 | | } | 334 | | | 335 | 2 | (Inner::Transition(success1 ), Stage::ApplyInherentExtrinsic { extrinsics }) | 336 | 2 | if !extrinsics.is_empty() => | 337 | 1 | { | 338 | 1 | let extrinsic = &extrinsics[0]; | 339 | 1 | | 340 | 1 | let init_result = runtime_call::run(runtime_call::Config { | 341 | 1 | virtual_machine: success.virtual_machine.into_prototype(), | 342 | 1 | function_to_call: "BlockBuilder_apply_extrinsic", | 343 | 1 | parameter: iter::once(extrinsic), | 344 | 1 | storage_main_trie_changes: success.storage_changes.into_main_trie_diff(), | 345 | 1 | storage_proof_size_behavior: | 346 | 1 | runtime_call::StorageProofSizeBehavior::Unimplemented, | 347 | 1 | max_log_level: shared.max_log_level, | 348 | 1 | calculate_trie_changes: shared.calculate_trie_changes, | 349 | 1 | }); | 350 | | | 351 | 1 | inner = Inner::Runtime(match init_result { | 352 | 1 | Ok(vm) => vm, | 353 | 0 | Err((err, proto)) => { | 354 | 0 | return BlockBuild::Finished(Err((Error::VmInit(err), proto))) | 355 | | } | 356 | | }); | 357 | | } | 358 | | | 359 | 1 | (Inner::Transition(success), Stage::ApplyInherentExtrinsic { .. }) => { | 360 | 1 | return BlockBuild::ApplyExtrinsic(ApplyExtrinsic { | 361 | 1 | shared, | 362 | 1 | parent_runtime: success.virtual_machine.into_prototype(), | 363 | 1 | storage_changes: success.storage_changes, | 364 | 1 | }); | 365 | | } | 366 | | | 367 | | ( | 368 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), | 369 | | Stage::ApplyInherentExtrinsic { .. }, | 370 | | ) => { | 371 | 1 | let (extrinsic, new_stage) = match shared.stage { | 372 | 1 | Stage::ApplyInherentExtrinsic { mut extrinsics } => { | 373 | 1 | let extrinsic = extrinsics.remove(0); | 374 | 1 | (extrinsic, Stage::ApplyInherentExtrinsic { extrinsics }) | 375 | | } | 376 | 0 | _ => unreachable!(), | 377 | | }; | 378 | | | 379 | 1 | shared.stage = new_stage; | 380 | 1 | | 381 | 1 | let parse_result = | 382 | 1 | parse_apply_extrinsic_output(success.virtual_machine.value().as_ref()); | 383 | 1 | match parse_result { | 384 | 1 | Ok(Ok(Ok(()))) => {} | 385 | 0 | Ok(Ok(Err(error))) => { | 386 | 0 | return BlockBuild::Finished(Err(( | 387 | 0 | Error::InherentExtrinsicDispatchError { extrinsic, error }, | 388 | 0 | success.virtual_machine.into_prototype(), | 389 | 0 | ))) | 390 | | } | 391 | 0 | Ok(Err(error)) => { | 392 | 0 | return BlockBuild::Finished(Err(( | 393 | 0 | Error::InherentExtrinsicTransactionValidityError { | 394 | 0 | extrinsic, | 395 | 0 | error, | 396 | 0 | }, | 397 | 0 | success.virtual_machine.into_prototype(), | 398 | 0 | ))) | 399 | | } | 400 | 0 | Err(err) => { | 401 | 0 | return BlockBuild::Finished(Err(( | 402 | 0 | err, | 403 | 0 | success.virtual_machine.into_prototype(), | 404 | 0 | ))) | 405 | | } | 406 | | } | 407 | | | 408 | 1 | shared.block_body.push(extrinsic); | 409 | 1 | | 410 | 1 | inner = Inner::Transition(success); | 411 | | } | 412 | | | 413 | | ( | 414 | 0 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), | 415 | 0 | Stage::ApplyExtrinsic(_), | 416 | 0 | ) => { | 417 | 0 | let parse_result = | 418 | 0 | parse_apply_extrinsic_output(success.virtual_machine.value().as_ref()); | 419 | 0 | let result = match parse_result { | 420 | 0 | Ok(r) => r, | 421 | 0 | Err(err) => { | 422 | 0 | return BlockBuild::Finished(Err(( | 423 | 0 | err, | 424 | 0 | success.virtual_machine.into_prototype(), | 425 | 0 | ))) | 426 | | } | 427 | | }; | 428 | | | 429 | 0 | if result.is_ok() { | 430 | 0 | shared.block_body.push(match &mut shared.stage { | 431 | 0 | Stage::ApplyExtrinsic(ext) => mem::take(ext), | 432 | 0 | _ => unreachable!(), | 433 | | }); | 434 | 0 | } | 435 | | | 436 | | // TODO: consider giving back extrinsic to user in case of failure | 437 | | | 438 | | // TODO: IMPORTANT /!\ must throw away storage changes in case of error | 439 | | | 440 | 0 | return BlockBuild::ApplyExtrinsicResult { | 441 | 0 | result, | 442 | 0 | resume: ApplyExtrinsic { | 443 | 0 | shared, | 444 | 0 | parent_runtime: success.virtual_machine.into_prototype(), | 445 | 0 | storage_changes: success.storage_changes, | 446 | 0 | }, | 447 | 0 | }; | 448 | | } | 449 | | | 450 | | ( | 451 | 1 | Inner::Runtime(runtime_call::RuntimeCall::Finished(Ok(success))), | 452 | 1 | Stage::FinalizeBlock, | 453 | 1 | ) => { | 454 | 1 | let scale_encoded_header = success.virtual_machine.value().as_ref().to_owned(); | 455 | 1 | return BlockBuild::Finished(Ok(Success { | 456 | 1 | scale_encoded_header, | 457 | 1 | body: shared.block_body, | 458 | 1 | parent_runtime: success.virtual_machine.into_prototype(), | 459 | 1 | storage_changes: success.storage_changes, | 460 | 1 | state_trie_version: success.state_trie_version, | 461 | 1 | })); | 462 | | } | 463 | | | 464 | | // TODO: what about SignatureVerification and EmitLog? at the time of writing of this comment, it's not worth fixing as this code would get removed by <https://github.com/smol-dot/smoldot/issues/1517> | 465 | 0 | (_, s) => unreachable!("{:?}", s), | 466 | | } | 467 | | } | 468 | 4.20k | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB2_10BlockBuild10from_inner |
469 | | } |
470 | | |
471 | | /// Extra information maintained in parallel of the [`runtime_call::RuntimeCall`]. |
472 | | #[derive(Debug)] |
473 | | struct Shared { |
474 | | /// The block building process is separated into multiple stages. |
475 | | stage: Stage, |
476 | | /// Body of the block under construction. Items are added as construction progresses. |
477 | | block_body: Vec<Vec<u8>>, |
478 | | /// Value provided by [`Config::max_log_level`]. |
479 | | max_log_level: u32, |
480 | | /// Value provided by [`Config::calculate_trie_changes`]. |
481 | | calculate_trie_changes: bool, |
482 | | } |
483 | | |
484 | | /// The block building process is separated into multiple stages. |
485 | | #[derive(Debug, Clone)] |
486 | | enum Stage { |
487 | | InitializeBlock, |
488 | | InherentExtrinsics, |
489 | | ApplyInherentExtrinsic { |
490 | | /// List of inherent extrinsics being applied, including the one currently being applied. |
491 | | /// This list should thus never be empty. |
492 | | extrinsics: Vec<Vec<u8>>, |
493 | | }, |
494 | | ApplyExtrinsic(Vec<u8>), |
495 | | FinalizeBlock, |
496 | | } |
497 | | |
498 | | /// The list of inherent extrinsics are needed in order to continue. |
499 | | #[must_use] |
500 | | pub struct InherentExtrinsics { |
501 | | shared: Shared, |
502 | | parent_runtime: host::HostVmPrototype, |
503 | | storage_changes: StorageChanges, |
504 | | } |
505 | | |
506 | | impl InherentExtrinsics { |
507 | | /// Injects the inherents extrinsics and resumes execution. |
508 | | /// |
509 | | /// See the module-level documentation for more information. |
510 | 1 | pub fn inject_inherents(self, inherents: inherents::InherentData) -> BlockBuild { |
511 | 1 | self.inject_raw_inherents_list(inherents.as_raw_list()) |
512 | 1 | } _RNvMs_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB4_18InherentExtrinsics16inject_inherents Line | Count | Source | 510 | 1 | pub fn inject_inherents(self, inherents: inherents::InherentData) -> BlockBuild { | 511 | 1 | self.inject_raw_inherents_list(inherents.as_raw_list()) | 512 | 1 | } |
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB4_18InherentExtrinsics16inject_inherents |
513 | | |
514 | | /// Injects a raw list of inherents and resumes execution. |
515 | | /// |
516 | | /// This method is a more weakly-typed equivalent to [`InherentExtrinsics::inject_inherents`]. |
517 | | /// Only use this method if you know what you're doing. |
518 | 1 | pub fn inject_raw_inherents_list( |
519 | 1 | self, |
520 | 1 | list: impl ExactSizeIterator<Item = ([u8; 8], impl AsRef<[u8]> + Clone)> + Clone, |
521 | 1 | ) -> BlockBuild { |
522 | 1 | debug_assert!(matches!0 (self.shared.stage, Stage::InherentExtrinsics)); |
523 | | |
524 | 1 | let init_result = runtime_call::run(runtime_call::Config { |
525 | 1 | virtual_machine: self.parent_runtime, |
526 | 1 | function_to_call: "BlockBuilder_inherent_extrinsics", |
527 | 1 | parameter: { |
528 | 1 | // The `BlockBuilder_inherent_extrinsics` function expects a SCALE-encoded list of |
529 | 1 | // tuples containing an "inherent identifier" (`[u8; 8]`) and a value (`Vec<u8>`). |
530 | 1 | let len = util::encode_scale_compact_usize(list.len()); |
531 | 2 | let encoded_list = list.flat_map(|(id, value)| { |
532 | 2 | let value_len = util::encode_scale_compact_usize(value.as_ref().len()); |
533 | 2 | let value_and_len = iter::once(value_len) |
534 | 2 | .map(either::Left) |
535 | 2 | .chain(iter::once(value).map(either::Right)); |
536 | 2 | iter::once(id) |
537 | 2 | .map(either::Left) |
538 | 2 | .chain(value_and_len.map(either::Right)) |
539 | 2 | }); _RNCINvMs_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB7_18InherentExtrinsics25inject_raw_inherents_listAhj8_INtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterTB1B_B1B_EKj1_EE0Bb_ Line | Count | Source | 531 | 2 | let encoded_list = list.flat_map(|(id, value)| { | 532 | 2 | let value_len = util::encode_scale_compact_usize(value.as_ref().len()); | 533 | 2 | let value_and_len = iter::once(value_len) | 534 | 2 | .map(either::Left) | 535 | 2 | .chain(iter::once(value).map(either::Right)); | 536 | 2 | iter::once(id) | 537 | 2 | .map(either::Left) | 538 | 2 | .chain(value_and_len.map(either::Right)) | 539 | 2 | }); |
Unexecuted instantiation: _RNCINvMs_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB7_18InherentExtrinsics25inject_raw_inherents_listAhj8_INtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterTB1C_B1C_EKj1_EE0Bb_ |
540 | 1 | |
541 | 1 | iter::once(len) |
542 | 1 | .map(either::Left) |
543 | 1 | .chain(encoded_list.map(either::Right)) |
544 | 1 | }, |
545 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, |
546 | 1 | storage_main_trie_changes: self.storage_changes.into_main_trie_diff(), |
547 | 1 | max_log_level: self.shared.max_log_level, |
548 | 1 | calculate_trie_changes: self.shared.calculate_trie_changes, |
549 | 1 | }); |
550 | | |
551 | 1 | let vm = match init_result { |
552 | 1 | Ok(vm) => vm, |
553 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), |
554 | | }; |
555 | | |
556 | 1 | BlockBuild::from_inner(vm, self.shared) |
557 | 1 | } _RINvMs_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18InherentExtrinsics25inject_raw_inherents_listAhj8_INtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterTB1z_B1z_EKj1_EEB9_ Line | Count | Source | 518 | 1 | pub fn inject_raw_inherents_list( | 519 | 1 | self, | 520 | 1 | list: impl ExactSizeIterator<Item = ([u8; 8], impl AsRef<[u8]> + Clone)> + Clone, | 521 | 1 | ) -> BlockBuild { | 522 | 1 | debug_assert!(matches!0 (self.shared.stage, Stage::InherentExtrinsics)); | 523 | | | 524 | 1 | let init_result = runtime_call::run(runtime_call::Config { | 525 | 1 | virtual_machine: self.parent_runtime, | 526 | 1 | function_to_call: "BlockBuilder_inherent_extrinsics", | 527 | 1 | parameter: { | 528 | 1 | // The `BlockBuilder_inherent_extrinsics` function expects a SCALE-encoded list of | 529 | 1 | // tuples containing an "inherent identifier" (`[u8; 8]`) and a value (`Vec<u8>`). | 530 | 1 | let len = util::encode_scale_compact_usize(list.len()); | 531 | 1 | let encoded_list = list.flat_map(|(id, value)| { | 532 | | let value_len = util::encode_scale_compact_usize(value.as_ref().len()); | 533 | | let value_and_len = iter::once(value_len) | 534 | | .map(either::Left) | 535 | | .chain(iter::once(value).map(either::Right)); | 536 | | iter::once(id) | 537 | | .map(either::Left) | 538 | | .chain(value_and_len.map(either::Right)) | 539 | 1 | }); | 540 | 1 | | 541 | 1 | iter::once(len) | 542 | 1 | .map(either::Left) | 543 | 1 | .chain(encoded_list.map(either::Right)) | 544 | 1 | }, | 545 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, | 546 | 1 | storage_main_trie_changes: self.storage_changes.into_main_trie_diff(), | 547 | 1 | max_log_level: self.shared.max_log_level, | 548 | 1 | calculate_trie_changes: self.shared.calculate_trie_changes, | 549 | 1 | }); | 550 | | | 551 | 1 | let vm = match init_result { | 552 | 1 | Ok(vm) => vm, | 553 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), | 554 | | }; | 555 | | | 556 | 1 | BlockBuild::from_inner(vm, self.shared) | 557 | 1 | } |
Unexecuted instantiation: _RINvMs_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18InherentExtrinsics25inject_raw_inherents_listAhj8_INtNtNtCsaYZPK01V26L_4core5array4iter8IntoIterTB1A_B1A_EKj1_EEB9_ |
558 | | } |
559 | | |
560 | | /// More transactions can be added. |
561 | | #[must_use] |
562 | | pub struct ApplyExtrinsic { |
563 | | shared: Shared, |
564 | | parent_runtime: host::HostVmPrototype, |
565 | | storage_changes: StorageChanges, |
566 | | } |
567 | | |
568 | | impl ApplyExtrinsic { |
569 | | /// Adds a SCALE-encoded extrinsic and resumes execution. |
570 | | /// |
571 | | /// See the module-level documentation for more information. |
572 | 0 | pub fn add_extrinsic(mut self, extrinsic: Vec<u8>) -> BlockBuild { |
573 | 0 | let init_result = runtime_call::run(runtime_call::Config { |
574 | 0 | virtual_machine: self.parent_runtime, |
575 | 0 | function_to_call: "BlockBuilder_apply_extrinsic", |
576 | 0 | parameter: iter::once(&extrinsic), |
577 | 0 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, |
578 | 0 | storage_main_trie_changes: self.storage_changes.into_main_trie_diff(), |
579 | 0 | max_log_level: self.shared.max_log_level, |
580 | 0 | calculate_trie_changes: self.shared.calculate_trie_changes, |
581 | 0 | }); |
582 | 0 |
|
583 | 0 | self.shared.stage = Stage::ApplyExtrinsic(extrinsic); |
584 | | |
585 | 0 | let vm = match init_result { |
586 | 0 | Ok(vm) => vm, |
587 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), |
588 | | }; |
589 | | |
590 | 0 | BlockBuild::from_inner(vm, self.shared) |
591 | 0 | } Unexecuted instantiation: _RNvMs0_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_14ApplyExtrinsic13add_extrinsic Unexecuted instantiation: _RNvMs0_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_14ApplyExtrinsic13add_extrinsic |
592 | | |
593 | | /// Indicate that no more extrinsics will be added, and resume execution. |
594 | 1 | pub fn finish(mut self) -> BlockBuild { |
595 | 1 | self.shared.stage = Stage::FinalizeBlock; |
596 | 1 | |
597 | 1 | let init_result = runtime_call::run(runtime_call::Config { |
598 | 1 | virtual_machine: self.parent_runtime, |
599 | 1 | function_to_call: "BlockBuilder_finalize_block", |
600 | 1 | parameter: iter::empty::<&[u8]>(), |
601 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, |
602 | 1 | storage_main_trie_changes: self.storage_changes.into_main_trie_diff(), |
603 | 1 | max_log_level: self.shared.max_log_level, |
604 | 1 | calculate_trie_changes: self.shared.calculate_trie_changes, |
605 | 1 | }); |
606 | | |
607 | 1 | let vm = match init_result { |
608 | 1 | Ok(vm) => vm, |
609 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), |
610 | | }; |
611 | | |
612 | 1 | BlockBuild::from_inner(vm, self.shared) |
613 | 1 | } _RNvMs0_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_14ApplyExtrinsic6finish Line | Count | Source | 594 | 1 | pub fn finish(mut self) -> BlockBuild { | 595 | 1 | self.shared.stage = Stage::FinalizeBlock; | 596 | 1 | | 597 | 1 | let init_result = runtime_call::run(runtime_call::Config { | 598 | 1 | virtual_machine: self.parent_runtime, | 599 | 1 | function_to_call: "BlockBuilder_finalize_block", | 600 | 1 | parameter: iter::empty::<&[u8]>(), | 601 | 1 | storage_proof_size_behavior: runtime_call::StorageProofSizeBehavior::Unimplemented, | 602 | 1 | storage_main_trie_changes: self.storage_changes.into_main_trie_diff(), | 603 | 1 | max_log_level: self.shared.max_log_level, | 604 | 1 | calculate_trie_changes: self.shared.calculate_trie_changes, | 605 | 1 | }); | 606 | | | 607 | 1 | let vm = match init_result { | 608 | 1 | Ok(vm) => vm, | 609 | 0 | Err((err, proto)) => return BlockBuild::Finished(Err((Error::VmInit(err), proto))), | 610 | | }; | 611 | | | 612 | 1 | BlockBuild::from_inner(vm, self.shared) | 613 | 1 | } |
Unexecuted instantiation: _RNvMs0_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_14ApplyExtrinsic6finish |
614 | | } |
615 | | |
616 | | /// Loading a storage value from the parent storage is required in order to continue. |
617 | | #[must_use] |
618 | | pub struct StorageGet(runtime_call::StorageGet, Shared); |
619 | | |
620 | | impl StorageGet { |
621 | | /// Returns the key whose value must be passed to [`StorageGet::inject_value`]. |
622 | 8.72k | pub fn key(&'_ self) -> impl AsRef<[u8]> + '_ { |
623 | 8.72k | self.0.key() |
624 | 8.72k | } _RNvMs1_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_10StorageGet3key Line | Count | Source | 622 | 8.72k | pub fn key(&'_ self) -> impl AsRef<[u8]> + '_ { | 623 | 8.72k | self.0.key() | 624 | 8.72k | } |
Unexecuted instantiation: _RNvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_10StorageGet3key |
625 | | |
626 | | /// If `Some`, read from the given child trie. If `None`, read from the main trie. |
627 | 0 | pub fn child_trie(&'_ self) -> Option<impl AsRef<[u8]> + '_> { |
628 | 0 | self.0.child_trie() |
629 | 0 | } Unexecuted instantiation: _RNvMs1_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_10StorageGet10child_trie Unexecuted instantiation: _RNvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_10StorageGet10child_trie |
630 | | |
631 | | /// Injects the corresponding storage value. |
632 | 146 | pub fn inject_value( |
633 | 146 | self, |
634 | 146 | value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>, |
635 | 146 | ) -> BlockBuild { |
636 | 146 | BlockBuild::from_inner(self.0.inject_value(value), self.1) |
637 | 146 | } _RINvMs1_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB6_10StorageGet12inject_valueRShINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceB1f_EEBa_ Line | Count | Source | 632 | 146 | pub fn inject_value( | 633 | 146 | self, | 634 | 146 | value: Option<(impl Iterator<Item = impl AsRef<[u8]>>, TrieEntryVersion)>, | 635 | 146 | ) -> BlockBuild { | 636 | 146 | BlockBuild::from_inner(self.0.inject_value(value), self.1) | 637 | 146 | } |
Unexecuted instantiation: _RINvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_10StorageGet12inject_valueppEBa_ Unexecuted instantiation: _RINvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_10StorageGet12inject_valueRShINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceB1g_EECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_10StorageGet12inject_valueRShINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceB1g_EECscDgN54JpMGG_6author Unexecuted instantiation: _RINvMs1_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_10StorageGet12inject_valueRShINtNtNtNtCsaYZPK01V26L_4core4iter7sources4once4OnceB1g_EECsibGXYHQB8Ea_25json_rpc_general_requests |
638 | | } |
639 | | |
640 | | /// Obtaining the Merkle value of the closest descendant of a trie node is required in order |
641 | | /// to continue. |
642 | | #[must_use] |
643 | | pub struct ClosestDescendantMerkleValue(runtime_call::ClosestDescendantMerkleValue, Shared); |
644 | | |
645 | | impl ClosestDescendantMerkleValue { |
646 | | /// Returns the key whose closest descendant Merkle value must be passed to |
647 | | /// [`ClosestDescendantMerkleValue::inject_merkle_value`]. |
648 | 0 | pub fn key(&'_ self) -> impl Iterator<Item = Nibble> + '_ { |
649 | 0 | self.0.key() |
650 | 0 | } Unexecuted instantiation: _RNvMs2_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue3key Unexecuted instantiation: _RNvMs2_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue3key |
651 | | |
652 | | /// If `Some`, read from the given child trie. If `None`, read from the main trie. |
653 | 0 | pub fn child_trie(&'_ self) -> Option<impl AsRef<[u8]> + '_> { |
654 | 0 | self.0.child_trie() |
655 | 0 | } Unexecuted instantiation: _RNvMs2_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue10child_trie Unexecuted instantiation: _RNvMs2_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue10child_trie |
656 | | |
657 | | /// Indicate that the value is unknown and resume the calculation. |
658 | | /// |
659 | | /// This function be used if you are unaware of the Merkle value. The algorithm will perform |
660 | | /// the calculation of this Merkle value manually, which takes more time. |
661 | 1.86k | pub fn resume_unknown(self) -> BlockBuild { |
662 | 1.86k | BlockBuild::from_inner(self.0.resume_unknown(), self.1) |
663 | 1.86k | } _RNvMs2_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue14resume_unknown Line | Count | Source | 661 | 1.86k | pub fn resume_unknown(self) -> BlockBuild { | 662 | 1.86k | BlockBuild::from_inner(self.0.resume_unknown(), self.1) | 663 | 1.86k | } |
Unexecuted instantiation: _RNvMs2_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue14resume_unknown |
664 | | |
665 | | /// Injects the corresponding Merkle value. |
666 | | /// |
667 | | /// `None` can be passed if there is no descendant or, in the case of a child trie read, in |
668 | | /// order to indicate that the child trie does not exist. |
669 | 0 | pub fn inject_merkle_value(self, merkle_value: Option<&[u8]>) -> BlockBuild { |
670 | 0 | BlockBuild::from_inner(self.0.inject_merkle_value(merkle_value), self.1) |
671 | 0 | } Unexecuted instantiation: _RNvMs2_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue19inject_merkle_value Unexecuted instantiation: _RNvMs2_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_28ClosestDescendantMerkleValue19inject_merkle_value |
672 | | } |
673 | | |
674 | | /// Fetching the key that follows a given one in the parent storage is required in order to |
675 | | /// continue. |
676 | | #[must_use] |
677 | | pub struct NextKey(runtime_call::NextKey, Shared); |
678 | | |
679 | | impl NextKey { |
680 | | /// Returns the key whose next key must be passed back. |
681 | 2.19k | pub fn key(&'_ self) -> impl Iterator<Item = Nibble> + '_ { |
682 | 2.19k | self.0.key() |
683 | 2.19k | } _RNvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_7NextKey3key Line | Count | Source | 681 | 2.19k | pub fn key(&'_ self) -> impl Iterator<Item = Nibble> + '_ { | 682 | 2.19k | self.0.key() | 683 | 2.19k | } |
Unexecuted instantiation: _RNvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_7NextKey3key |
684 | | |
685 | | /// If `Some`, read from the given child trie. If `None`, read from the main trie. |
686 | 0 | pub fn child_trie(&'_ self) -> Option<impl AsRef<[u8]> + '_> { |
687 | 0 | self.0.child_trie() |
688 | 0 | } Unexecuted instantiation: _RNvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_7NextKey10child_trie Unexecuted instantiation: _RNvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_7NextKey10child_trie |
689 | | |
690 | | /// If `true`, then the provided value must the one superior or equal to the requested key. |
691 | | /// If `false`, then the provided value must be strictly superior to the requested key. |
692 | 2.19k | pub fn or_equal(&self) -> bool { |
693 | 2.19k | self.0.or_equal() |
694 | 2.19k | } _RNvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_7NextKey8or_equal Line | Count | Source | 692 | 2.19k | pub fn or_equal(&self) -> bool { | 693 | 2.19k | self.0.or_equal() | 694 | 2.19k | } |
Unexecuted instantiation: _RNvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_7NextKey8or_equal |
695 | | |
696 | | /// If `true`, then the search must include both branch nodes and storage nodes. If `false`, |
697 | | /// the search only covers storage nodes. |
698 | 2.19k | pub fn branch_nodes(&self) -> bool { |
699 | 2.19k | self.0.branch_nodes() |
700 | 2.19k | } _RNvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_7NextKey12branch_nodes Line | Count | Source | 698 | 2.19k | pub fn branch_nodes(&self) -> bool { | 699 | 2.19k | self.0.branch_nodes() | 700 | 2.19k | } |
Unexecuted instantiation: _RNvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_7NextKey12branch_nodes |
701 | | |
702 | | /// Returns the prefix the next key must start with. If the next key doesn't start with the |
703 | | /// given prefix, then `None` should be provided. |
704 | 2.19k | pub fn prefix(&'_ self) -> impl Iterator<Item = Nibble> + '_ { |
705 | 2.19k | self.0.prefix() |
706 | 2.19k | } _RNvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_7NextKey6prefix Line | Count | Source | 704 | 2.19k | pub fn prefix(&'_ self) -> impl Iterator<Item = Nibble> + '_ { | 705 | 2.19k | self.0.prefix() | 706 | 2.19k | } |
Unexecuted instantiation: _RNvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_7NextKey6prefix |
707 | | |
708 | | /// Injects the key. |
709 | | /// |
710 | | /// # Panic |
711 | | /// |
712 | | /// Panics if the key passed as parameter isn't strictly superior to the requested key. |
713 | | /// |
714 | 2.19k | pub fn inject_key(self, key: Option<impl Iterator<Item = Nibble>>) -> BlockBuild { |
715 | 2.19k | BlockBuild::from_inner(self.0.inject_key(key), self.1) |
716 | 2.19k | } _RINvMs3_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB6_7NextKey10inject_keyNtNtNtBa_4trie13branch_search21BranchTrieNodeKeyIterEBa_ Line | Count | Source | 714 | 2.19k | pub fn inject_key(self, key: Option<impl Iterator<Item = Nibble>>) -> BlockBuild { | 715 | 2.19k | BlockBuild::from_inner(self.0.inject_key(key), self.1) | 716 | 2.19k | } |
Unexecuted instantiation: _RINvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_7NextKey10inject_keypEBa_ Unexecuted instantiation: _RINvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_7NextKey10inject_keyINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB2Z_14SyncBackground12author_block0s6_00EECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_7NextKey10inject_keyINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB2Z_14SyncBackground12author_block0s6_00EECscDgN54JpMGG_6author Unexecuted instantiation: _RINvMs3_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB6_7NextKey10inject_keyINtNtNtNtCsaYZPK01V26L_4core4iter8adapters3map3MapINtNtNtCsdZExvAaxgia_5alloc3vec9into_iter8IntoIterhENCNCNCNvMs_NtCsiUjFBJteJ7x_17smoldot_full_node17consensus_serviceNtB2Z_14SyncBackground12author_block0s6_00EECsibGXYHQB8Ea_25json_rpc_general_requests |
717 | | } |
718 | | |
719 | | /// Setting the value of an offchain storage value is required. |
720 | | #[must_use] |
721 | | pub struct OffchainStorageSet(runtime_call::OffchainStorageSet, Shared); |
722 | | |
723 | | impl OffchainStorageSet { |
724 | | /// Returns the key whose value must be set. |
725 | 0 | pub fn key(&'_ self) -> impl AsRef<[u8]> + '_ { |
726 | 0 | self.0.key() |
727 | 0 | } Unexecuted instantiation: _RNvMs4_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18OffchainStorageSet3key Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18OffchainStorageSet3key |
728 | | |
729 | | /// Returns the value to set. |
730 | | /// |
731 | | /// If `None` is returned, the key should be removed from the storage entirely. |
732 | 0 | pub fn value(&'_ self) -> Option<impl AsRef<[u8]> + '_> { |
733 | 0 | self.0.value() |
734 | 0 | } Unexecuted instantiation: _RNvMs4_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18OffchainStorageSet5value Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18OffchainStorageSet5value |
735 | | |
736 | | /// Resumes execution after having set the value. |
737 | 0 | pub fn resume(self) -> BlockBuild { |
738 | 0 | BlockBuild::from_inner(self.0.resume(), self.1) |
739 | 0 | } Unexecuted instantiation: _RNvMs4_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18OffchainStorageSet6resume Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18OffchainStorageSet6resume |
740 | | } |
741 | | |
742 | | /// Analyzes the output of a call to `BlockBuilder_inherent_extrinsics`, and returns the resulting |
743 | | /// extrinsics. |
744 | | // TODO: this method implementation is hacky ; the `BlockBuilder_inherent_extrinsics` function |
745 | | // returns a `Vec<Extrinsic>`, where `Extrinsic` is opaque and depends on the chain. Because |
746 | | // we don't know the type of `Extrinsic`, a `Vec<Extrinsic>` is undecodable. However, most |
747 | | // Substrate chains use `type Extrinsic = OpaqueExtrinsic;` where |
748 | | // `type OpaqueExtrinsic = Vec<u8>;` here, which happens to start with a length prefix |
749 | | // containing its remaining size; this length prefix is fully part of the `Extrinsic` though. |
750 | | // In other words, this function might succeed or fail depending on the Substrate chain. |
751 | 1 | fn parse_inherent_extrinsics_output(output: &[u8]) -> Result<Vec<Vec<u8>>, Error> { |
752 | 1 | nom::combinator::all_consuming(nom::combinator::flat_map( |
753 | 1 | crate::util::nom_scale_compact_usize, |
754 | 1 | |num_elems| { |
755 | 1 | nom::multi::many_m_n( |
756 | 1 | num_elems, |
757 | 1 | num_elems, |
758 | 1 | nom::combinator::map( |
759 | 1 | nom::combinator::recognize(nom::combinator::flat_map( |
760 | 1 | crate::util::nom_scale_compact_usize, |
761 | 1 | nom::bytes::streaming::take, |
762 | 1 | )), |
763 | 1 | |v: &[u8]| v.to_vec(), _RNCNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime32parse_inherent_extrinsics_output00B9_ Line | Count | Source | 763 | 1 | |v: &[u8]| v.to_vec(), |
Unexecuted instantiation: _RNCNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime32parse_inherent_extrinsics_output00B9_ |
764 | 1 | ), |
765 | 1 | ) |
766 | 1 | }, _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime32parse_inherent_extrinsics_output0B7_ Line | Count | Source | 754 | 1 | |num_elems| { | 755 | 1 | nom::multi::many_m_n( | 756 | 1 | num_elems, | 757 | 1 | num_elems, | 758 | 1 | nom::combinator::map( | 759 | 1 | nom::combinator::recognize(nom::combinator::flat_map( | 760 | 1 | crate::util::nom_scale_compact_usize, | 761 | 1 | nom::bytes::streaming::take, | 762 | 1 | )), | 763 | 1 | |v: &[u8]| v.to_vec(), | 764 | 1 | ), | 765 | 1 | ) | 766 | 1 | }, |
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime32parse_inherent_extrinsics_output0B7_ |
767 | 1 | ))(output) |
768 | 1 | .map(|(_, parse_result)| parse_result) _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime32parse_inherent_extrinsics_outputs_0B7_ Line | Count | Source | 768 | 1 | .map(|(_, parse_result)| parse_result) |
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime32parse_inherent_extrinsics_outputs_0B7_ |
769 | 1 | .map_err(|_: nom::Err<(&[u8], nom::error::ErrorKind)>| Error::BadInherentExtrinsicsOutput0 ) Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime32parse_inherent_extrinsics_outputs0_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime32parse_inherent_extrinsics_outputs0_0B7_ |
770 | 1 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime32parse_inherent_extrinsics_output Line | Count | Source | 751 | 1 | fn parse_inherent_extrinsics_output(output: &[u8]) -> Result<Vec<Vec<u8>>, Error> { | 752 | 1 | nom::combinator::all_consuming(nom::combinator::flat_map( | 753 | 1 | crate::util::nom_scale_compact_usize, | 754 | 1 | |num_elems| { | 755 | | nom::multi::many_m_n( | 756 | | num_elems, | 757 | | num_elems, | 758 | | nom::combinator::map( | 759 | | nom::combinator::recognize(nom::combinator::flat_map( | 760 | | crate::util::nom_scale_compact_usize, | 761 | | nom::bytes::streaming::take, | 762 | | )), | 763 | | |v: &[u8]| v.to_vec(), | 764 | | ), | 765 | | ) | 766 | 1 | }, | 767 | 1 | ))(output) | 768 | 1 | .map(|(_, parse_result)| parse_result) | 769 | 1 | .map_err(|_: nom::Err<(&[u8], nom::error::ErrorKind)>| Error::BadInherentExtrinsicsOutput) | 770 | 1 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime32parse_inherent_extrinsics_output |
771 | | |
772 | | /// Analyzes the output of a call to `BlockBuilder_apply_extrinsic`. |
773 | 1 | fn parse_apply_extrinsic_output( |
774 | 1 | output: &[u8], |
775 | 1 | ) -> Result<Result<Result<(), DispatchError>, TransactionValidityError>, Error> { |
776 | 1 | nom::combinator::all_consuming(apply_extrinsic_result)(output) |
777 | 1 | .map(|(_, parse_result)| parse_result) _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime28parse_apply_extrinsic_output0B7_ Line | Count | Source | 777 | 1 | .map(|(_, parse_result)| parse_result) |
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime28parse_apply_extrinsic_output0B7_ |
778 | 1 | .map_err(|_: nom::Err<nom::error::Error<&[u8]>>| Error::BadApplyExtrinsicOutput0 ) Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime28parse_apply_extrinsic_outputs_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime28parse_apply_extrinsic_outputs_0B7_ |
779 | 1 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime28parse_apply_extrinsic_output Line | Count | Source | 773 | 1 | fn parse_apply_extrinsic_output( | 774 | 1 | output: &[u8], | 775 | 1 | ) -> Result<Result<Result<(), DispatchError>, TransactionValidityError>, Error> { | 776 | 1 | nom::combinator::all_consuming(apply_extrinsic_result)(output) | 777 | 1 | .map(|(_, parse_result)| parse_result) | 778 | 1 | .map_err(|_: nom::Err<nom::error::Error<&[u8]>>| Error::BadApplyExtrinsicOutput) | 779 | 1 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime28parse_apply_extrinsic_output |
780 | | |
781 | | // TODO: some parsers below are common with the tx-pool ; figure out how/whether they should be merged |
782 | | |
783 | | /// Errors that can occur while checking the validity of a transaction. |
784 | 0 | #[derive(Debug, derive_more::Display, Clone, PartialEq, Eq)] Unexecuted instantiation: _RNvXsb_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_24TransactionValidityErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsb_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_24TransactionValidityErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
785 | | pub enum TransactionValidityError { |
786 | | /// The transaction is invalid. |
787 | | #[display(fmt = "Transaction is invalid: {_0}")] |
788 | | Invalid(InvalidTransaction), |
789 | | /// Transaction validity can't be determined. |
790 | | #[display(fmt = "Transaction validity couldn't be determined: {_0}")] |
791 | | Unknown(UnknownTransaction), |
792 | | } |
793 | | |
794 | | /// An invalid transaction validity. |
795 | 0 | #[derive(Debug, derive_more::Display, Clone, PartialEq, Eq)] Unexecuted instantiation: _RNvXsh_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18InvalidTransactionNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsh_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18InvalidTransactionNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
796 | | pub enum InvalidTransaction { |
797 | | /// The call of the transaction is not expected. |
798 | | Call, |
799 | | /// General error to do with the inability to pay some fees (e.g. account balance too low). |
800 | | Payment, |
801 | | /// General error to do with the transaction not yet being valid (e.g. nonce too high). |
802 | | Future, |
803 | | /// General error to do with the transaction being outdated (e.g. nonce too low). |
804 | | Stale, |
805 | | /// General error to do with the transaction's proofs (e.g. signature). |
806 | | /// |
807 | | /// # Possible causes |
808 | | /// |
809 | | /// When using a signed extension that provides additional data for signing, it is required |
810 | | /// that the signing and the verifying side use the same additional data. Additional |
811 | | /// data will only be used to generate the signature, but will not be part of the transaction |
812 | | /// itself. As the verifying side does not know which additional data was used while signing |
813 | | /// it will only be able to assume a bad signature and cannot express a more meaningful error. |
814 | | BadProof, |
815 | | /// The transaction birth block is ancient. |
816 | | AncientBirthBlock, |
817 | | /// The transaction would exhaust the resources of current block. |
818 | | /// |
819 | | /// The transaction might be valid, but there are not enough resources |
820 | | /// left in the current block. |
821 | | ExhaustsResources, |
822 | | /// Any other custom invalid validity that is not covered by this enum. |
823 | | #[display(fmt = "Other reason (code: {_0})")] |
824 | | Custom(u8), |
825 | | /// An extrinsic with a Mandatory dispatch resulted in Error. This is indicative of either a |
826 | | /// malicious validator or a buggy `provide_inherent`. In any case, it can result in dangerously |
827 | | /// overweight blocks and therefore if found, invalidates the block. |
828 | | BadMandatory, |
829 | | /// A transaction with a mandatory dispatch. This is invalid; only inherent extrinsics are |
830 | | /// allowed to have mandatory dispatches. |
831 | | MandatoryDispatch, |
832 | | } |
833 | | |
834 | | /// An unknown transaction validity. |
835 | 0 | #[derive(Debug, derive_more::Display, Clone, PartialEq, Eq)] Unexecuted instantiation: _RNvXsn_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_18UnknownTransactionNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsn_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_18UnknownTransactionNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
836 | | pub enum UnknownTransaction { |
837 | | /// Could not lookup some information that is required to validate the transaction. |
838 | | CannotLookup, |
839 | | /// No validator found for the given unsigned transaction. |
840 | | NoUnsignedValidator, |
841 | | /// Any other custom unknown validity that is not covered by this enum. |
842 | | #[display(fmt = "Other reason (code: {_0})")] |
843 | | Custom(u8), |
844 | | } |
845 | | |
846 | | /// Reason why a dispatch call failed. |
847 | 0 | #[derive(Debug, derive_more::Display, Clone, PartialEq, Eq)] Unexecuted instantiation: _RNvXst_NtNtCsN16ciHI6Qf_7smoldot6author7runtimeNtB5_13DispatchErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXst_NtNtCseuYC0Zibziv_7smoldot6author7runtimeNtB5_13DispatchErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
848 | | pub enum DispatchError { |
849 | | /// Failed to lookup some data. |
850 | | CannotLookup, |
851 | | /// A bad origin. |
852 | | BadOrigin, |
853 | | /// A custom error in a module. |
854 | | #[display(fmt = "Error in module #{index}, error number #{error}")] |
855 | | Module { |
856 | | /// Module index, matching the metadata module index. |
857 | | index: u8, |
858 | | /// Module specific error value. |
859 | | error: u8, |
860 | | }, |
861 | | } |
862 | | |
863 | 1 | fn apply_extrinsic_result( |
864 | 1 | bytes: &[u8], |
865 | 1 | ) -> nom::IResult<&[u8], Result<Result<(), DispatchError>, TransactionValidityError>> { |
866 | 1 | nom::error::context( |
867 | 1 | "apply extrinsic result", |
868 | 1 | nom::branch::alt(( |
869 | 1 | nom::combinator::map( |
870 | 1 | nom::sequence::preceded(nom::bytes::streaming::tag(&[0]), dispatch_outcome), |
871 | 1 | Ok, |
872 | 1 | ), |
873 | 1 | nom::combinator::map( |
874 | 1 | nom::sequence::preceded( |
875 | 1 | nom::bytes::streaming::tag(&[1]), |
876 | 1 | transaction_validity_error, |
877 | 1 | ), |
878 | 1 | Err, |
879 | 1 | ), |
880 | 1 | )), |
881 | 1 | )(bytes) |
882 | 1 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime22apply_extrinsic_result Line | Count | Source | 863 | 1 | fn apply_extrinsic_result( | 864 | 1 | bytes: &[u8], | 865 | 1 | ) -> nom::IResult<&[u8], Result<Result<(), DispatchError>, TransactionValidityError>> { | 866 | 1 | nom::error::context( | 867 | 1 | "apply extrinsic result", | 868 | 1 | nom::branch::alt(( | 869 | 1 | nom::combinator::map( | 870 | 1 | nom::sequence::preceded(nom::bytes::streaming::tag(&[0]), dispatch_outcome), | 871 | 1 | Ok, | 872 | 1 | ), | 873 | 1 | nom::combinator::map( | 874 | 1 | nom::sequence::preceded( | 875 | 1 | nom::bytes::streaming::tag(&[1]), | 876 | 1 | transaction_validity_error, | 877 | 1 | ), | 878 | 1 | Err, | 879 | 1 | ), | 880 | 1 | )), | 881 | 1 | )(bytes) | 882 | 1 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime22apply_extrinsic_result |
883 | | |
884 | 1 | fn dispatch_outcome(bytes: &[u8]) -> nom::IResult<&[u8], Result<(), DispatchError>> { |
885 | 1 | nom::error::context( |
886 | 1 | "dispatch outcome", |
887 | 1 | nom::branch::alt(( |
888 | 1 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| Ok(())), _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime16dispatch_outcome0B7_ Line | Count | Source | 888 | 1 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| Ok(())), |
Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime16dispatch_outcome0B7_ |
889 | 1 | nom::combinator::map( |
890 | 1 | nom::sequence::preceded(nom::bytes::streaming::tag(&[1]), dispatch_error), |
891 | 1 | Err, |
892 | 1 | ), |
893 | 1 | )), |
894 | 1 | )(bytes) |
895 | 1 | } _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime16dispatch_outcome Line | Count | Source | 884 | 1 | fn dispatch_outcome(bytes: &[u8]) -> nom::IResult<&[u8], Result<(), DispatchError>> { | 885 | 1 | nom::error::context( | 886 | 1 | "dispatch outcome", | 887 | 1 | nom::branch::alt(( | 888 | 1 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| Ok(())), | 889 | 1 | nom::combinator::map( | 890 | 1 | nom::sequence::preceded(nom::bytes::streaming::tag(&[1]), dispatch_error), | 891 | 1 | Err, | 892 | 1 | ), | 893 | 1 | )), | 894 | 1 | )(bytes) | 895 | 1 | } |
Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime16dispatch_outcome |
896 | | |
897 | 0 | fn dispatch_error(bytes: &[u8]) -> nom::IResult<&[u8], DispatchError> { |
898 | 0 | nom::error::context( |
899 | 0 | "dispatch error", |
900 | 0 | nom::branch::alt(( |
901 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| { |
902 | 0 | DispatchError::CannotLookup |
903 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime14dispatch_error0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime14dispatch_error0B7_ |
904 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[1]), |_| { |
905 | 0 | DispatchError::BadOrigin |
906 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime14dispatch_errors_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime14dispatch_errors_0B7_ |
907 | 0 | nom::combinator::map( |
908 | 0 | nom::sequence::preceded( |
909 | 0 | nom::bytes::streaming::tag(&[2]), |
910 | 0 | nom::sequence::tuple((nom::number::streaming::u8, nom::number::streaming::u8)), |
911 | 0 | ), |
912 | 0 | |(index, error)| DispatchError::Module { index, error }, Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime14dispatch_errors0_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime14dispatch_errors0_0B7_ |
913 | 0 | ), |
914 | 0 | )), |
915 | 0 | )(bytes) |
916 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime14dispatch_error Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime14dispatch_error |
917 | | |
918 | 0 | fn transaction_validity_error(bytes: &[u8]) -> nom::IResult<&[u8], TransactionValidityError> { |
919 | 0 | nom::error::context( |
920 | 0 | "transaction validity error", |
921 | 0 | nom::branch::alt(( |
922 | 0 | nom::combinator::map( |
923 | 0 | nom::sequence::preceded(nom::bytes::streaming::tag(&[0]), invalid_transaction), |
924 | 0 | TransactionValidityError::Invalid, |
925 | 0 | ), |
926 | 0 | nom::combinator::map( |
927 | 0 | nom::sequence::preceded(nom::bytes::streaming::tag(&[1]), unknown_transaction), |
928 | 0 | TransactionValidityError::Unknown, |
929 | 0 | ), |
930 | 0 | )), |
931 | 0 | )(bytes) |
932 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime26transaction_validity_error Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime26transaction_validity_error |
933 | | |
934 | 0 | fn invalid_transaction(bytes: &[u8]) -> nom::IResult<&[u8], InvalidTransaction> { |
935 | 0 | nom::error::context( |
936 | 0 | "invalid transaction", |
937 | 0 | nom::branch::alt(( |
938 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| { |
939 | 0 | InvalidTransaction::Call |
940 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transaction0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transaction0B7_ |
941 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[1]), |_| { |
942 | 0 | InvalidTransaction::Payment |
943 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions_0B7_ |
944 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[2]), |_| { |
945 | 0 | InvalidTransaction::Future |
946 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions0_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions0_0B7_ |
947 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[3]), |_| { |
948 | 0 | InvalidTransaction::Stale |
949 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions1_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions1_0B7_ |
950 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[4]), |_| { |
951 | 0 | InvalidTransaction::BadProof |
952 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions2_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions2_0B7_ |
953 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[5]), |_| { |
954 | 0 | InvalidTransaction::AncientBirthBlock |
955 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions3_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions3_0B7_ |
956 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[6]), |_| { |
957 | 0 | InvalidTransaction::ExhaustsResources |
958 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions4_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions4_0B7_ |
959 | 0 | nom::combinator::map( |
960 | 0 | nom::sequence::preceded( |
961 | 0 | nom::bytes::streaming::tag(&[7]), |
962 | 0 | nom::bytes::streaming::take(1u32), |
963 | 0 | ), |
964 | 0 | |n: &[u8]| InvalidTransaction::Custom(n[0]), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions5_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions5_0B7_ |
965 | 0 | ), |
966 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[8]), |_| { |
967 | 0 | InvalidTransaction::BadMandatory |
968 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions6_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions6_0B7_ |
969 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[9]), |_| { |
970 | 0 | InvalidTransaction::MandatoryDispatch |
971 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transactions7_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transactions7_0B7_ |
972 | 0 | )), |
973 | 0 | )(bytes) |
974 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19invalid_transaction Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19invalid_transaction |
975 | | |
976 | 0 | fn unknown_transaction(bytes: &[u8]) -> nom::IResult<&[u8], UnknownTransaction> { |
977 | 0 | nom::error::context( |
978 | 0 | "unknown transaction", |
979 | 0 | nom::branch::alt(( |
980 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[0]), |_| { |
981 | 0 | UnknownTransaction::CannotLookup |
982 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19unknown_transaction0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19unknown_transaction0B7_ |
983 | 0 | nom::combinator::map(nom::bytes::streaming::tag(&[1]), |_| { |
984 | 0 | UnknownTransaction::NoUnsignedValidator |
985 | 0 | }), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19unknown_transactions_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19unknown_transactions_0B7_ |
986 | 0 | nom::combinator::map( |
987 | 0 | nom::sequence::preceded( |
988 | 0 | nom::bytes::streaming::tag(&[2]), |
989 | 0 | nom::bytes::streaming::take(1u32), |
990 | 0 | ), |
991 | 0 | |n: &[u8]| UnknownTransaction::Custom(n[0]), Unexecuted instantiation: _RNCNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19unknown_transactions0_0B7_ Unexecuted instantiation: _RNCNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19unknown_transactions0_0B7_ |
992 | 0 | ), |
993 | 0 | )), |
994 | 0 | )(bytes) |
995 | 0 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot6author7runtime19unknown_transaction Unexecuted instantiation: _RNvNtNtCseuYC0Zibziv_7smoldot6author7runtime19unknown_transaction |