Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/light-base/src/runtime_service.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! Background runtime download service.
19
//!
20
//! This service plugs on top of a [`sync_service`], listens for new best blocks and checks
21
//! whether the runtime has changed in any way. Its objective is to always provide an up-to-date
22
//! [`executor::host::HostVmPrototype`] ready to be called by other services.
23
//!
24
//! # Usage
25
//!
26
//! The runtime service lets user subscribe to block updates, similar to the [`sync_service`].
27
//! These subscriptions are implemented by subscribing to the underlying [`sync_service`] and,
28
//! for each notification, checking whether the runtime has changed (thanks to the presence or
29
//! absence of a header digest item), and downloading the runtime code if necessary. Therefore,
30
//! these notifications might come with a delay compared to directly using the [`sync_service`].
31
//!
32
//! If it isn't possible to download the runtime code of a block (for example because peers refuse
33
//! to answer or have already pruned the block) or if the runtime service already has too many
34
//! pending downloads, this block is simply not reported on the subscriptions. The download will
35
//! be repeatedly tried until it succeeds.
36
//!
37
//! Consequently, you are strongly encouraged to not use both the [`sync_service`] *and* the
38
//! [`RuntimeService`] of the same chain. They each provide a consistent view of the chain, but
39
//! this view isn't necessarily the same on both services.
40
//!
41
//! The main service offered by the runtime service is [`RuntimeService::subscribe_all`], that
42
//! notifies about new blocks once their runtime is known.
43
//!
44
//! # Blocks pinning
45
//!
46
//! Blocks that are reported through [`RuntimeService::subscribe_all`] are automatically *pinned*.
47
//! If multiple subscriptions exist, each block is pinned once per subscription.
48
//!
49
//! As long as a block is pinned, the [`RuntimeService`] is guaranteed to keep in its internal
50
//! state the runtime of this block and its properties.
51
//!
52
//! Blocks must be manually unpinned by calling [`Subscription::unpin_block`].
53
//! Failing to do so is effectively a memory leak. If the number of pinned blocks becomes too
54
//! large, the subscription is force-killed by the [`RuntimeService`].
55
//!
56
57
use crate::{log, network_service, platform::PlatformRef, sync_service};
58
59
use alloc::{
60
    borrow::{Cow, ToOwned as _},
61
    boxed::Box,
62
    collections::{BTreeMap, VecDeque},
63
    format,
64
    string::{String, ToString as _},
65
    sync::{Arc, Weak},
66
    vec::Vec,
67
};
68
use async_lock::Mutex;
69
use core::{
70
    cmp, iter, mem,
71
    num::{NonZeroU32, NonZeroUsize},
72
    ops,
73
    pin::Pin,
74
    time::Duration,
75
};
76
use futures_channel::oneshot;
77
use futures_lite::FutureExt as _;
78
use futures_util::{future, stream, Stream, StreamExt as _};
79
use itertools::Itertools as _;
80
use rand::seq::IteratorRandom as _;
81
use rand_chacha::rand_core::SeedableRng as _;
82
use smoldot::{
83
    chain::async_tree,
84
    executor, header,
85
    informant::{BytesDisplay, HashDisplay},
86
    trie::{self, proof_decode, Nibble},
87
};
88
89
/// Configuration for a runtime service.
90
pub struct Config<TPlat: PlatformRef> {
91
    /// Name of the chain, for logging purposes.
92
    ///
93
    /// > **Note**: This name will be directly printed out. Any special character should already
94
    /// >           have been filtered out from this name.
95
    pub log_name: String,
96
97
    /// Access to the platform's capabilities.
98
    pub platform: TPlat,
99
100
    /// Service responsible for synchronizing the chain.
101
    pub sync_service: Arc<sync_service::SyncService<TPlat>>,
102
103
    /// Service responsible for accessing the networking of the chain.
104
    pub network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
105
106
    /// Header of the genesis block of the chain, in SCALE encoding.
107
    pub genesis_block_scale_encoded_header: Vec<u8>,
108
}
109
110
/// Runtime currently pinned within a [`RuntimeService`].
111
///
112
/// Destroying this object automatically unpins the runtime.
113
#[derive(Clone)]
114
pub struct PinnedRuntime(Arc<Runtime>);
115
116
/// See [the module-level documentation](..).
117
pub struct RuntimeService<TPlat: PlatformRef> {
118
    /// Configuration of the background task. Used to restart the background task if necessary.
119
    background_task_config: BackgroundTaskConfig<TPlat>,
120
121
    /// Sender to send messages to the background task.
122
    to_background: Mutex<async_channel::Sender<ToBackground<TPlat>>>,
123
}
124
125
impl<TPlat: PlatformRef> RuntimeService<TPlat> {
126
    /// Initializes a new runtime service.
127
0
    pub fn new(config: Config<TPlat>) -> Self {
128
0
        // Target to use for all the logs of this service.
129
0
        let log_target = format!("runtime-{}", config.log_name);
130
0
131
0
        let background_task_config = BackgroundTaskConfig {
132
0
            log_target: log_target.clone(),
133
0
            platform: config.platform.clone(),
134
0
            sync_service: config.sync_service,
135
0
            network_service: config.network_service,
136
0
            genesis_block_scale_encoded_header: config.genesis_block_scale_encoded_header,
137
0
        };
138
0
139
0
        // Spawns a task that runs in the background and updates the content of the mutex.
140
0
        let to_background;
141
0
        config.platform.spawn_task(log_target.clone().into(), {
142
0
            let (tx, rx) = async_channel::bounded(16);
143
0
            let tx_weak = tx.downgrade();
144
0
            to_background = tx;
145
0
            let background_task_config = background_task_config.clone();
146
0
            run_background(background_task_config, rx, tx_weak)
147
0
        });
148
0
149
0
        RuntimeService {
150
0
            background_task_config,
151
0
            to_background: Mutex::new(to_background),
152
0
        }
153
0
    }
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE3newB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE3newB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE3newB4_
154
155
    /// Calls [`sync_service::SyncService::block_number_bytes`] on the sync service associated to
156
    /// this runtime service.
157
0
    pub fn block_number_bytes(&self) -> usize {
158
0
        self.background_task_config
159
0
            .sync_service
160
0
            .block_number_bytes()
161
0
    }
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE18block_number_bytesB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE18block_number_bytesB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE18block_number_bytesB4_
162
163
    /// Subscribes to the state of the chain: the current state and the new blocks.
164
    ///
165
    /// This function only returns once the runtime of the current finalized block is known. This
166
    /// might take a long time.
167
    ///
168
    /// Only up to `buffer_size` block notifications are buffered in the channel. If the channel
169
    /// is full when a new notification is attempted to be pushed, the channel gets closed.
170
    ///
171
    /// A maximum number of finalized or non-canonical (i.e. not part of the finalized chain)
172
    /// pinned blocks must be passed, indicating the maximum number of blocks that are finalized
173
    /// or non-canonical that the runtime service will pin at the same time for this subscription.
174
    /// If this maximum is reached, the channel will get closed. In situations where the subscriber
175
    /// is guaranteed to always properly unpin blocks, a value of `usize::MAX` can be
176
    /// passed in order to ignore this maximum.
177
    ///
178
    /// The channel also gets closed if a gap in the finality happens, such as after a Grandpa
179
    /// warp syncing.
180
    ///
181
    /// See [`SubscribeAll`] for information about the return value.
182
0
    pub async fn subscribe_all(
183
0
        &self,
184
0
        buffer_size: usize,
185
0
        max_pinned_blocks: NonZeroUsize,
186
0
    ) -> SubscribeAll<TPlat> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE13subscribe_allB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE13subscribe_allB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE13subscribe_allB4_
187
0
        loop {
188
0
            let (result_tx, result_rx) = oneshot::channel();
189
0
            let _ = self
190
0
                .send_message_or_restart_service(ToBackground::SubscribeAll(
191
0
                    ToBackgroundSubscribeAll {
192
0
                        result_tx,
193
0
                        buffer_size,
194
0
                        max_pinned_blocks,
195
0
                    },
196
0
                ))
197
0
                .await;
198
199
0
            if let Ok(subscribe_all) = result_rx.await {
200
0
                break subscribe_all;
201
0
            }
202
        }
203
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE13subscribe_all0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE13subscribe_all0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE13subscribe_all0B6_
204
205
    /// Unpins a block after it has been reported by a subscription.
206
    ///
207
    /// Has no effect if the [`SubscriptionId`] is not or no longer valid (as the runtime service
208
    /// can kill any subscription at any moment).
209
    ///
210
    /// # Panic
211
    ///
212
    /// Panics if the block hash has not been reported or has already been unpinned.
213
    ///
214
    // TODO: add #[track_caller] once possible, see https://github.com/rust-lang/rust/issues/87417
215
0
    pub async fn unpin_block(&self, subscription_id: SubscriptionId, block_hash: [u8; 32]) {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE11unpin_blockB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE11unpin_blockB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE11unpin_blockB4_
216
0
        let (result_tx, result_rx) = oneshot::channel();
217
0
        let _ = self
218
0
            .to_background
219
0
            .lock()
220
0
            .await
221
0
            .send(ToBackground::UnpinBlock {
222
0
                result_tx,
223
0
                subscription_id,
224
0
                block_hash,
225
0
            })
226
0
            .await;
227
0
        match result_rx.await {
228
0
            Ok(Ok(())) => {
229
0
                // Background task has indicated success.
230
0
            }
231
0
            Err(_) => {
232
0
                // Background task has crashed. Subscription is stale. Function has no effect.
233
0
            }
234
            Ok(Err(_)) => {
235
                // Background task has indicated that the block has already been unpinned.
236
0
                panic!()
237
            }
238
        }
239
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE11unpin_block0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE11unpin_block0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE11unpin_block0B6_
240
241
    /// Returns the storage value and Merkle value of the `:code` key of the finalized block.
242
    ///
243
    /// Returns `None` if the runtime of the current finalized block is not known yet.
244
    // TODO: this function has a bad API but is hopefully temporary
245
0
    pub async fn finalized_runtime_storage_merkle_values(
246
0
        &self,
247
0
    ) -> Option<(Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<Nibble>>)> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE39finalized_runtime_storage_merkle_valuesB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE39finalized_runtime_storage_merkle_valuesB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE39finalized_runtime_storage_merkle_valuesB4_
248
0
        let (result_tx, result_rx) = oneshot::channel();
249
0
250
0
        let _ = self
251
0
            .to_background
252
0
            .lock()
253
0
            .await
254
0
            .send(ToBackground::FinalizedRuntimeStorageMerkleValues { result_tx })
255
0
            .await;
256
257
0
        result_rx.await.unwrap_or(None)
258
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE39finalized_runtime_storage_merkle_values0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE39finalized_runtime_storage_merkle_values0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE39finalized_runtime_storage_merkle_values0B6_
259
260
    /// Pins the runtime of a pinned block.
261
    ///
262
    /// The hash of the block passed as parameter corresponds to the block whose runtime is to
263
    /// be pinned. The block must be currently pinned in the context of the provided
264
    /// [`SubscriptionId`].
265
    ///
266
    /// Returns the pinned runtime, plus the state trie root hash and height of the block.
267
    ///
268
    /// Returns an error if the subscription is stale, meaning that it has been reset by the
269
    /// runtime service.
270
0
    pub async fn pin_pinned_block_runtime(
271
0
        &self,
272
0
        subscription_id: SubscriptionId,
273
0
        block_hash: [u8; 32],
274
0
    ) -> Result<(PinnedRuntime, [u8; 32], u64), PinPinnedBlockRuntimeError> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE24pin_pinned_block_runtimeB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE24pin_pinned_block_runtimeB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE24pin_pinned_block_runtimeB4_
275
0
        let (result_tx, result_rx) = oneshot::channel();
276
0
277
0
        let _ = self
278
0
            .to_background
279
0
            .lock()
280
0
            .await
281
0
            .send(ToBackground::PinPinnedBlockRuntime {
282
0
                result_tx,
283
0
                subscription_id,
284
0
                block_hash,
285
0
            })
286
0
            .await;
287
288
0
        match result_rx.await {
289
0
            Ok(result) => result.map(|(r, v, n)| (PinnedRuntime(r), v, n)),
Unexecuted instantiation: _RNCNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE24pin_pinned_block_runtime00B8_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE24pin_pinned_block_runtime00B1i_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE24pin_pinned_block_runtime00B8_
290
            Err(_) => {
291
                // Background service has crashed. This means that the subscription is obsolete.
292
0
                Err(PinPinnedBlockRuntimeError::ObsoleteSubscription)
293
            }
294
        }
295
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE24pin_pinned_block_runtime0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE24pin_pinned_block_runtime0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE24pin_pinned_block_runtime0B6_
296
297
    /// Performs a runtime call.
298
    ///
299
    /// The hash of the block passed as parameter corresponds to the block whose runtime to use
300
    /// to make the call. The block must be currently pinned in the context of the provided
301
    /// [`SubscriptionId`].
302
    ///
303
    /// Returns an error if the subscription is stale, meaning that it has been reset by the
304
    /// runtime service.
305
0
    pub async fn runtime_call(
306
0
        &self,
307
0
        pinned_runtime: PinnedRuntime,
308
0
        block_hash: [u8; 32],
309
0
        block_number: u64,
310
0
        block_state_trie_root_hash: [u8; 32],
311
0
        function_name: String,
312
0
        required_api_version: Option<(String, ops::RangeInclusive<u32>)>,
313
0
        parameters_vectored: Vec<u8>,
314
0
        total_attempts: u32,
315
0
        timeout_per_request: Duration,
316
0
        max_parallel: NonZeroU32,
317
0
    ) -> Result<RuntimeCallSuccess, RuntimeCallError> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE12runtime_callB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE12runtime_callB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE12runtime_callB4_
318
0
        let (result_tx, result_rx) = oneshot::channel();
319
0
320
0
        self.send_message_or_restart_service(ToBackground::RuntimeCall {
321
0
            result_tx,
322
0
            pinned_runtime: pinned_runtime.0,
323
0
            block_hash,
324
0
            block_number,
325
0
            block_state_trie_root_hash,
326
0
            function_name,
327
0
            required_api_version,
328
0
            parameters_vectored,
329
0
            total_attempts,
330
0
            timeout_per_request,
331
0
            _max_parallel: max_parallel,
332
0
        })
333
0
        .await;
334
335
0
        match result_rx.await {
336
0
            Ok(result) => result,
337
            Err(_) => {
338
                // Background service has crashed.
339
0
                Err(RuntimeCallError::Crash)
340
            }
341
        }
342
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE12runtime_call0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE12runtime_call0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE12runtime_call0B6_
343
344
    /// Tries to find a runtime within the [`RuntimeService`] that has the given storage code and
345
    /// heap pages. If none is found, compiles the runtime and stores it within the
346
    /// [`RuntimeService`].
347
0
    pub async fn compile_and_pin_runtime(
348
0
        &self,
349
0
        storage_code: Option<Vec<u8>>,
350
0
        storage_heap_pages: Option<Vec<u8>>,
351
0
        code_merkle_value: Option<Vec<u8>>,
352
0
        closest_ancestor_excluding: Option<Vec<Nibble>>,
353
0
    ) -> Result<PinnedRuntime, CompileAndPinRuntimeError> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE23compile_and_pin_runtimeB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE23compile_and_pin_runtimeB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE23compile_and_pin_runtimeB4_
354
0
        let (result_tx, result_rx) = oneshot::channel();
355
0
356
0
        let _ = self
357
0
            .send_message_or_restart_service(ToBackground::CompileAndPinRuntime {
358
0
                result_tx,
359
0
                storage_code,
360
0
                storage_heap_pages,
361
0
                code_merkle_value,
362
0
                closest_ancestor_excluding,
363
0
            })
364
0
            .await;
365
366
        Ok(PinnedRuntime(
367
0
            result_rx
368
0
                .await
369
0
                .map_err(|_| CompileAndPinRuntimeError::Crash)?,
Unexecuted instantiation: _RNCNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE23compile_and_pin_runtime00B8_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE23compile_and_pin_runtime00B1i_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE23compile_and_pin_runtime00B8_
370
        ))
371
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE23compile_and_pin_runtime0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE23compile_and_pin_runtime0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE23compile_and_pin_runtime0B6_
372
373
    /// Returns the runtime specification of the given runtime.
374
0
    pub async fn pinned_runtime_specification(
375
0
        &self,
376
0
        pinned_runtime: PinnedRuntime,
377
0
    ) -> Result<executor::CoreVersion, PinnedRuntimeSpecificationError> {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE28pinned_runtime_specificationB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE28pinned_runtime_specificationB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE28pinned_runtime_specificationB4_
378
0
        match &pinned_runtime.0.runtime {
379
0
            Ok(rt) => Ok(rt.runtime_version().clone()),
380
0
            Err(error) => Err(PinnedRuntimeSpecificationError::InvalidRuntime(
381
0
                error.clone(),
382
0
            )),
383
        }
384
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE28pinned_runtime_specification0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE28pinned_runtime_specification0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE28pinned_runtime_specification0B6_
385
386
    /// Returns true if it is believed that we are near the head of the chain.
387
    ///
388
    /// The way this method is implemented is opaque and cannot be relied on. The return value
389
    /// should only ever be shown to the user and not used for any meaningful logic.
390
0
    pub async fn is_near_head_of_chain_heuristic(&self) -> bool {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE31is_near_head_of_chain_heuristicB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE31is_near_head_of_chain_heuristicB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE31is_near_head_of_chain_heuristicB4_
391
0
        let (result_tx, result_rx) = oneshot::channel();
392
0
        let _ = self
393
0
            .to_background
394
0
            .lock()
395
0
            .await
396
0
            .send(ToBackground::IsNearHeadOfChainHeuristic { result_tx })
397
0
            .await;
398
0
        result_rx.await.unwrap_or(false)
399
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE31is_near_head_of_chain_heuristic0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE31is_near_head_of_chain_heuristic0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE31is_near_head_of_chain_heuristic0B6_
400
401
    /// Sends a message to the background task. Restarts the background task if it has crashed.
402
0
    async fn send_message_or_restart_service(&self, message: ToBackground<TPlat>) {
Unexecuted instantiation: _RNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE31send_message_or_restart_serviceB4_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE31send_message_or_restart_serviceB1e_
Unexecuted instantiation: _RNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB2_14RuntimeServicepE31send_message_or_restart_serviceB4_
403
0
        let mut lock = self.to_background.lock().await;
404
405
0
        if lock.is_closed() {
406
0
            let (tx, rx) = async_channel::bounded(16);
407
0
            let tx_weak = tx.downgrade();
408
0
            *lock = tx;
409
0
410
0
            self.background_task_config.platform.spawn_task(
411
0
                self.background_task_config.log_target.clone().into(),
412
0
                {
413
0
                    let background_task_config = self.background_task_config.clone();
414
0
                    let platform = background_task_config.platform.clone();
415
0
                    async move {
416
0
                        // Sleep for a bit in order to avoid infinite loops of repeated crashes.
417
0
                        background_task_config
418
0
                            .platform
419
0
                            .sleep(Duration::from_secs(2))
420
0
                            .await;
421
0
                        let log_target = background_task_config.log_target.clone();
422
0
                        log!(&platform, Debug, &log_target, "restart");
423
0
                        run_background(background_task_config, rx, tx_weak).await;
424
0
                        log!(&platform, Debug, &log_target, "shutdown");
425
0
                    }
Unexecuted instantiation: _RNCNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE31send_message_or_restart_service00B8_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE31send_message_or_restart_service00B1i_
Unexecuted instantiation: _RNCNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_14RuntimeServicepE31send_message_or_restart_service00B8_
426
0
                },
427
0
            );
428
0
        }
429
430
        // Note that the background task might have crashed again at this point already, and thus
431
        // errors are not impossible.
432
0
        let _ = lock.send(message).await;
433
0
    }
Unexecuted instantiation: _RNCNvMNtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE31send_message_or_restart_service0B6_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServiceNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE31send_message_or_restart_service0B1g_
Unexecuted instantiation: _RNCNvMNtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_14RuntimeServicepE31send_message_or_restart_service0B6_
434
}
435
436
/// Return value of [`RuntimeService::subscribe_all`].
437
pub struct SubscribeAll<TPlat: PlatformRef> {
438
    /// SCALE-encoded header of the finalized block at the time of the subscription.
439
    pub finalized_block_scale_encoded_header: Vec<u8>,
440
441
    /// If the runtime of the finalized block is known, contains the information about it.
442
    pub finalized_block_runtime: Result<executor::CoreVersion, RuntimeError>,
443
444
    /// List of all known non-finalized blocks at the time of subscription.
445
    ///
446
    /// Only one element in this list has [`BlockNotification::is_new_best`] equal to true.
447
    ///
448
    /// The blocks are guaranteed to be ordered so that parents are always found before their
449
    /// children.
450
    pub non_finalized_blocks_ancestry_order: Vec<BlockNotification>,
451
452
    /// Channel onto which new blocks are sent. The channel gets closed if it is full when a new
453
    /// block needs to be reported.
454
    pub new_blocks: Subscription<TPlat>,
455
}
456
457
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
458
pub struct SubscriptionId(u64);
459
460
pub struct Subscription<TPlat: PlatformRef> {
461
    subscription_id: u64,
462
    channel: Pin<Box<async_channel::Receiver<Notification>>>,
463
    to_background: async_channel::Sender<ToBackground<TPlat>>,
464
}
465
466
impl<TPlat: PlatformRef> Subscription<TPlat> {
467
0
    pub async fn next(&mut self) -> Option<Notification> {
Unexecuted instantiation: _RNvMs_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE4nextB6_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE4nextB1e_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE4nextB6_
468
0
        self.channel.next().await
469
0
    }
Unexecuted instantiation: _RNCNvMs_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB6_12SubscriptionpE4next0B8_
Unexecuted instantiation: _RNCNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_12SubscriptionNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE4next0B1g_
Unexecuted instantiation: _RNCNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_12SubscriptionpE4next0B8_
470
471
    /// Returns an opaque identifier that can be used to call [`RuntimeService::unpin_block`].
472
0
    pub fn id(&self) -> SubscriptionId {
473
0
        SubscriptionId(self.subscription_id)
474
0
    }
Unexecuted instantiation: _RNvMs_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE2idB6_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE2idB1e_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE2idB6_
475
476
    /// Unpins a block after it has been reported.
477
    ///
478
    /// # Panic
479
    ///
480
    /// Panics if the block hash has not been reported or has already been unpinned.
481
    ///
482
0
    pub async fn unpin_block(&self, block_hash: [u8; 32]) {
Unexecuted instantiation: _RNvMs_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE11unpin_blockB6_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE11unpin_blockB1e_
Unexecuted instantiation: _RNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB4_12SubscriptionpE11unpin_blockB6_
483
0
        let (result_tx, result_rx) = oneshot::channel();
484
0
        let _ = self
485
0
            .to_background
486
0
            .send(ToBackground::UnpinBlock {
487
0
                result_tx,
488
0
                subscription_id: SubscriptionId(self.subscription_id),
489
0
                block_hash,
490
0
            })
491
0
            .await;
492
0
        result_rx.await.unwrap().unwrap()
493
0
    }
Unexecuted instantiation: _RNCNvMs_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceINtB6_12SubscriptionpE11unpin_block0B8_
Unexecuted instantiation: _RNCNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_12SubscriptionNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE11unpin_block0B1g_
Unexecuted instantiation: _RNCNvMs_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceINtB6_12SubscriptionpE11unpin_block0B8_
494
}
495
496
/// Notification about a new block or a new finalized block.
497
///
498
/// See [`RuntimeService::subscribe_all`].
499
#[derive(Debug, Clone)]
500
pub enum Notification {
501
    /// A non-finalized block has been finalized.
502
    Finalized {
503
        /// BLAKE2 hash of the header of the block that has been finalized.
504
        ///
505
        /// A block with this hash is guaranteed to have earlier been reported in a
506
        /// [`BlockNotification`], either in [`SubscribeAll::non_finalized_blocks_ancestry_order`]
507
        /// or in a [`Notification::Block`].
508
        ///
509
        /// It is also guaranteed that this block is a child of the previously-finalized block. In
510
        /// other words, if multiple blocks are finalized at the same time, only one
511
        /// [`Notification::Finalized`] is generated and contains the highest finalized block.
512
        ///
513
        /// If it is not possible for the [`RuntimeService`] to avoid a gap in the list of
514
        /// finalized blocks, then the [`SubscribeAll::new_blocks`] channel is force-closed.
515
        hash: [u8; 32],
516
517
        /// If the current best block is pruned by the finalization, contains the updated hash
518
        /// of the best block after the finalization.
519
        ///
520
        /// If the newly-finalized block is an ancestor of the current best block, then this field
521
        /// contains the hash of this current best block. Otherwise, the best block is now
522
        /// the non-finalized block with the given hash.
523
        ///
524
        /// A block with this hash is guaranteed to have earlier been reported in a
525
        /// [`BlockNotification`], either in [`SubscribeAll::non_finalized_blocks_ancestry_order`]
526
        /// or in a [`Notification::Block`].
527
        best_block_hash_if_changed: Option<[u8; 32]>,
528
529
        /// List of BLAKE2 hashes of the headers of the blocks that have been discarded because
530
        /// they're not descendants of the newly-finalized block.
531
        ///
532
        /// This list contains all the siblings of the newly-finalized block and all their
533
        /// descendants.
534
        pruned_blocks: Vec<[u8; 32]>,
535
    },
536
537
    /// A new block has been added to the list of unfinalized blocks.
538
    Block(BlockNotification),
539
540
    /// The best block has changed to a different one.
541
    BestBlockChanged {
542
        /// Hash of the new best block.
543
        ///
544
        /// This can be either the hash of the latest finalized block or the hash of a
545
        /// non-finalized block.
546
        hash: [u8; 32],
547
    },
548
}
549
550
/// Notification about a new block.
551
///
552
/// See [`RuntimeService::subscribe_all`].
553
#[derive(Debug, Clone)]
554
pub struct BlockNotification {
555
    /// True if this block is considered as the best block of the chain.
556
    pub is_new_best: bool,
557
558
    /// SCALE-encoded header of the block.
559
    pub scale_encoded_header: Vec<u8>,
560
561
    /// BLAKE2 hash of the header of the parent of this block.
562
    ///
563
    ///
564
    /// A block with this hash is guaranteed to have earlier been reported in a
565
    /// [`BlockNotification`], either in [`SubscribeAll::non_finalized_blocks_ancestry_order`] or
566
    /// in a [`Notification::Block`].
567
    ///
568
    /// > **Note**: The header of a block contains the hash of its parent. When it comes to
569
    /// >           consensus algorithms such as Babe or Aura, the syncing code verifies that this
570
    /// >           hash, stored in the header, actually corresponds to a valid block. However,
571
    /// >           when it comes to parachain consensus, no such verification is performed.
572
    /// >           Contrary to the hash stored in the header, the value of this field is
573
    /// >           guaranteed to refer to a block that is known by the syncing service. This
574
    /// >           allows a subscriber of the state of the chain to precisely track the hierarchy
575
    /// >           of blocks, without risking to run into a problem in case of a block with an
576
    /// >           invalid header.
577
    pub parent_hash: [u8; 32],
578
579
    /// If the runtime of the block is different from its parent, contains the information about
580
    /// the new runtime.
581
    pub new_runtime: Option<Result<executor::CoreVersion, RuntimeError>>,
582
}
583
584
/// Successful runtime call.
585
#[derive(Debug)]
586
pub struct RuntimeCallSuccess {
587
    /// Output of the runtime call.
588
    pub output: Vec<u8>,
589
590
    /// Version of the API that was found. `Some` if and only if an API requirement was passed.
591
    pub api_version: Option<u32>,
592
}
593
594
/// See [`RuntimeService::pin_pinned_block_runtime`].
595
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsh_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_26PinPinnedBlockRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsh_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_26PinPinnedBlockRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
596
pub enum PinPinnedBlockRuntimeError {
597
    /// Subscription is dead.
598
    ObsoleteSubscription,
599
600
    /// Requested block isn't pinned by the subscription.
601
    BlockNotPinned,
602
}
603
604
/// See [`RuntimeService::pinned_runtime_specification`].
605
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsk_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_31PinnedRuntimeSpecificationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsk_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_31PinnedRuntimeSpecificationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
606
pub enum PinnedRuntimeSpecificationError {
607
    /// The runtime is invalid.
608
    InvalidRuntime(RuntimeError),
609
}
610
611
/// See [`RuntimeService::runtime_call`].
612
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsn_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_16RuntimeCallErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsn_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_16RuntimeCallErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
613
pub enum RuntimeCallError {
614
    /// The runtime of the requested block is invalid.
615
    InvalidRuntime(RuntimeError),
616
617
    /// API version required for the call isn't fulfilled.
618
    ApiVersionRequirementUnfulfilled,
619
620
    /// Runtime service has crashed while the call was in progress.
621
    ///
622
    /// This doesn't necessarily indicate that the call was responsible for this crash.
623
    Crash,
624
625
    /// Error during the execution of the runtime.
626
    ///
627
    /// There is no point in trying the same call again, as it would result in the same error.
628
    #[display(fmt = "Error during the execution of the runtime: {_0}")]
629
    Execution(RuntimeCallExecutionError),
630
631
    /// Error trying to access the storage required for the runtime call.
632
    ///
633
    /// Because these errors are non-fatal, the operation is attempted multiple times, and as such
634
    /// there can be multiple errors.
635
    ///
636
    /// Trying the same call again might succeed.
637
    #[display(fmt = "Error trying to access the storage required for the runtime call")]
638
    // TODO: better display?
639
    Inaccessible(Vec<RuntimeCallInaccessibleError>),
640
}
641
642
/// See [`RuntimeCallError::Execution`].
643
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsq_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_25RuntimeCallExecutionErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsq_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_25RuntimeCallExecutionErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
644
pub enum RuntimeCallExecutionError {
645
    /// Failed to initialize the virtual machine.
646
    Start(executor::host::StartErr),
647
    /// Error during the execution of the virtual machine.
648
    Execution(executor::runtime_call::ErrorDetail),
649
    /// Virtual machine has called a host function that it is not allowed to call.
650
    ForbiddenHostFunction,
651
}
652
653
/// See [`RuntimeCallError::Inaccessible`].
654
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXst_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_28RuntimeCallInaccessibleErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXst_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_28RuntimeCallInaccessibleErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
655
pub enum RuntimeCallInaccessibleError {
656
    /// Failed to download the call proof from the network.
657
    Network(network_service::CallProofRequestError),
658
    /// Call proof downloaded from the network has an invalid format.
659
    InvalidCallProof(proof_decode::Error),
660
    /// One or more entries are missing from the downloaded call proof.
661
    MissingProofEntry,
662
}
663
664
/// Error when analyzing the runtime.
665
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsw_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_12RuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsw_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_12RuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
666
pub enum RuntimeError {
667
    /// The `:code` key of the storage is empty.
668
    CodeNotFound,
669
    /// Error while parsing the `:heappages` storage value.
670
    #[display(fmt = "Failed to parse `:heappages` storage value: {_0}")]
671
    InvalidHeapPages(executor::InvalidHeapPagesError),
672
    /// Error while compiling the runtime.
673
    #[display(fmt = "{_0}")]
674
    Build(executor::host::NewErr),
675
}
676
677
/// Error potentially returned by [`RuntimeService::compile_and_pin_runtime`].
678
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsz_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_25CompileAndPinRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsz_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_25CompileAndPinRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
679
pub enum CompileAndPinRuntimeError {
680
    /// Background service has crashed while compiling this runtime. The crash might however not
681
    /// necessarily be caused by the runtime compilation.
682
    Crash,
683
}
684
685
/// Message towards the background task.
686
enum ToBackground<TPlat: PlatformRef> {
687
    SubscribeAll(ToBackgroundSubscribeAll<TPlat>),
688
    CompileAndPinRuntime {
689
        result_tx: oneshot::Sender<Arc<Runtime>>,
690
        storage_code: Option<Vec<u8>>,
691
        storage_heap_pages: Option<Vec<u8>>,
692
        code_merkle_value: Option<Vec<u8>>,
693
        closest_ancestor_excluding: Option<Vec<Nibble>>,
694
    },
695
    FinalizedRuntimeStorageMerkleValues {
696
        // TODO: overcomplicated
697
        result_tx: oneshot::Sender<Option<(Option<Vec<u8>>, Option<Vec<u8>>, Option<Vec<Nibble>>)>>,
698
    },
699
    IsNearHeadOfChainHeuristic {
700
        result_tx: oneshot::Sender<bool>,
701
    },
702
    UnpinBlock {
703
        result_tx: oneshot::Sender<Result<(), ()>>,
704
        subscription_id: SubscriptionId,
705
        block_hash: [u8; 32],
706
    },
707
    PinPinnedBlockRuntime {
708
        result_tx:
709
            oneshot::Sender<Result<(Arc<Runtime>, [u8; 32], u64), PinPinnedBlockRuntimeError>>,
710
        subscription_id: SubscriptionId,
711
        block_hash: [u8; 32],
712
    },
713
    RuntimeCall {
714
        result_tx: oneshot::Sender<Result<RuntimeCallSuccess, RuntimeCallError>>,
715
        pinned_runtime: Arc<Runtime>,
716
        block_hash: [u8; 32],
717
        block_number: u64,
718
        block_state_trie_root_hash: [u8; 32],
719
        function_name: String,
720
        required_api_version: Option<(String, ops::RangeInclusive<u32>)>,
721
        parameters_vectored: Vec<u8>,
722
        total_attempts: u32,
723
        timeout_per_request: Duration,
724
        _max_parallel: NonZeroU32,
725
    },
726
}
727
728
struct ToBackgroundSubscribeAll<TPlat: PlatformRef> {
729
    result_tx: oneshot::Sender<SubscribeAll<TPlat>>,
730
    buffer_size: usize,
731
    max_pinned_blocks: NonZeroUsize,
732
}
733
734
#[derive(Clone)]
735
struct PinnedBlock {
736
    /// Reference-counted runtime of the pinned block.
737
    runtime: Arc<Runtime>,
738
739
    /// Hash of the trie root of the pinned block.
740
    state_trie_root_hash: [u8; 32],
741
742
    /// Height of the pinned block.
743
    block_number: u64,
744
745
    /// `true` if the block is non-finalized and part of the canonical chain.
746
    /// If `true`, then the block doesn't count towards the maximum number of pinned blocks of
747
    /// the subscription.
748
    block_ignores_limit: bool,
749
}
750
751
#[derive(Clone)]
752
struct Block {
753
    /// Hash of the block in question. Redundant with `header`, but the hash is so often needed
754
    /// that it makes sense to cache it.
755
    hash: [u8; 32],
756
757
    /// Height of the block.
758
    height: u64,
759
760
    /// Header of the block in question.
761
    /// Guaranteed to always be valid for the output best and finalized blocks. Otherwise,
762
    /// not guaranteed to be valid.
763
    scale_encoded_header: Vec<u8>,
764
}
765
766
#[derive(Clone)]
767
struct BackgroundTaskConfig<TPlat: PlatformRef> {
768
    log_target: String,
769
    platform: TPlat,
770
    sync_service: Arc<sync_service::SyncService<TPlat>>,
771
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
772
    genesis_block_scale_encoded_header: Vec<u8>,
773
}
774
775
0
async fn run_background<TPlat: PlatformRef>(
776
0
    config: BackgroundTaskConfig<TPlat>,
777
0
    to_background: async_channel::Receiver<ToBackground<TPlat>>,
778
0
    to_background_tx: async_channel::WeakSender<ToBackground<TPlat>>,
779
0
) {
Unexecuted instantiation: _RINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpEB4_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefEB18_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpEB4_
780
0
    log!(
781
0
        &config.platform,
782
0
        Trace,
783
0
        &config.log_target,
784
0
        "start",
785
0
        genesis_block_hash = HashDisplay(&header::hash_from_scale_encoded_header(
786
0
            &config.genesis_block_scale_encoded_header
787
0
        ))
788
0
    );
789
0
790
0
    // State machine containing all the state that will be manipulated below.
791
0
    let mut background = {
792
0
        let tree = {
793
0
            let mut tree = async_tree::AsyncTree::new(async_tree::Config {
794
0
                finalized_async_user_data: None,
795
0
                retry_after_failed: Duration::from_secs(10),
796
0
                blocks_capacity: 32,
797
0
            });
798
0
            let node_index = tree.input_insert_block(
799
0
                Block {
800
0
                    hash: header::hash_from_scale_encoded_header(
801
0
                        &config.genesis_block_scale_encoded_header,
802
0
                    ),
803
0
                    height: 0,
804
0
                    scale_encoded_header: config.genesis_block_scale_encoded_header,
805
0
                },
806
0
                None,
807
0
                false,
808
0
                true,
809
0
            );
810
0
            tree.input_finalize(node_index);
811
0
812
0
            Tree::FinalizedBlockRuntimeUnknown { tree }
813
0
        };
814
0
815
0
        Background {
816
0
            log_target: config.log_target.clone(),
817
0
            platform: config.platform.clone(),
818
0
            sync_service: config.sync_service.clone(),
819
0
            network_service: config.network_service.clone(),
820
0
            to_background: Box::pin(to_background.clone()),
821
0
            to_background_tx: to_background_tx.clone(),
822
0
            next_subscription_id: 0,
823
0
            tree,
824
0
            runtimes: slab::Slab::with_capacity(2),
825
0
            pending_subscriptions: VecDeque::with_capacity(8),
826
0
            blocks_stream: None,
827
0
            runtime_downloads: stream::FuturesUnordered::new(),
828
0
            progress_runtime_call_requests: stream::FuturesUnordered::new(),
829
0
        }
830
    };
831
832
    // Inner loop. Process incoming events.
833
    loop {
834
        // Yield at every loop in order to provide better tasks granularity.
835
0
        futures_lite::future::yield_now().await;
836
837
        enum WakeUpReason<TPlat: PlatformRef> {
838
            MustSubscribe,
839
            StartDownload(async_tree::AsyncOpId, async_tree::NodeIndex),
840
            TreeAdvanceFinalizedKnown(async_tree::OutputUpdate<Block, Arc<Runtime>>),
841
            TreeAdvanceFinalizedUnknown(async_tree::OutputUpdate<Block, Option<Arc<Runtime>>>),
842
            StartPendingSubscribeAll(ToBackgroundSubscribeAll<TPlat>),
843
            Notification(sync_service::Notification),
844
            SyncServiceSubscriptionReset,
845
            ToBackground(ToBackground<TPlat>),
846
            ForegroundClosed,
847
            RuntimeDownloadFinished(
848
                async_tree::AsyncOpId,
849
                Result<
850
                    (
851
                        Option<Vec<u8>>,
852
                        Option<Vec<u8>>,
853
                        Option<Vec<u8>>,
854
                        Option<Vec<Nibble>>,
855
                    ),
856
                    RuntimeDownloadError,
857
                >,
858
            ),
859
            ProgressRuntimeCallRequest(ProgressRuntimeCallRequest),
860
        }
861
862
        // Wait for something to happen or for some processing to be necessary.
863
0
        let wake_up_reason: WakeUpReason<_> = {
864
0
            let finalized_block_known =
865
0
                matches!(background.tree, Tree::FinalizedBlockRuntimeKnown { .. });
866
0
            let num_runtime_downloads = background.runtime_downloads.len();
867
0
            let any_subscription = match &background.tree {
868
                Tree::FinalizedBlockRuntimeKnown {
869
0
                    all_blocks_subscriptions,
870
0
                    ..
871
0
                } => !all_blocks_subscriptions.is_empty(),
872
0
                Tree::FinalizedBlockRuntimeUnknown { .. } => false,
873
            };
874
0
            let any_pending_subscription = !background.pending_subscriptions.is_empty();
875
0
            async {
876
0
                if finalized_block_known {
877
0
                    if let Some(pending_subscription) = background.pending_subscriptions.pop_front()
878
                    {
879
0
                        WakeUpReason::StartPendingSubscribeAll(pending_subscription)
880
                    } else {
881
0
                        future::pending().await
882
                    }
883
                } else {
884
0
                    future::pending().await
885
                }
886
0
            }
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE00B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE00B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE00B8_
887
0
            .or(async {
888
0
                if let Some(blocks_stream) = background.blocks_stream.as_mut() {
889
0
                    if !any_subscription && !any_pending_subscription {
890
0
                        WakeUpReason::SyncServiceSubscriptionReset
891
                    } else {
892
0
                        blocks_stream.next().await.map_or(
893
0
                            WakeUpReason::SyncServiceSubscriptionReset,
894
0
                            WakeUpReason::Notification,
895
0
                        )
896
                    }
897
0
                } else if any_pending_subscription {
898
                    // Only start subscribing to the sync service if there is any pending
899
                    // runtime service subscription.
900
0
                    WakeUpReason::MustSubscribe
901
                } else {
902
0
                    future::pending().await
903
                }
904
0
            })
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s_0B8_
905
0
            .or(async {
906
0
                background
907
0
                    .to_background
908
0
                    .next()
909
0
                    .await
910
0
                    .map_or(WakeUpReason::ForegroundClosed, WakeUpReason::ToBackground)
911
0
            })
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s0_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s0_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s0_0B8_
912
0
            .or(async {
913
0
                if !background.runtime_downloads.is_empty() {
914
0
                    let (async_op_id, download_result) =
915
0
                        background.runtime_downloads.select_next_some().await;
916
0
                    WakeUpReason::RuntimeDownloadFinished(async_op_id, download_result)
917
                } else {
918
0
                    future::pending().await
919
                }
920
0
            })
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s1_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s1_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s1_0B8_
921
0
            .or(async {
922
0
                if !background.progress_runtime_call_requests.is_empty() {
923
0
                    let result = background
924
0
                        .progress_runtime_call_requests
925
0
                        .select_next_some()
926
0
                        .await;
927
0
                    WakeUpReason::ProgressRuntimeCallRequest(result)
928
                } else {
929
0
                    future::pending().await
930
                }
931
0
            })
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s2_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s2_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s2_0B8_
932
0
            .or(async {
933
                loop {
934
                    // There might be a new runtime download to start.
935
                    // Don't download more than 2 runtimes at a time.
936
0
                    let wait = if num_runtime_downloads < 2 {
937
                        // Grab what to download. If there's nothing more to download, do nothing.
938
0
                        let async_op = match &mut background.tree {
939
0
                            Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
940
0
                                tree.next_necessary_async_op(&background.platform.now())
941
                            }
942
0
                            Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
943
0
                                tree.next_necessary_async_op(&background.platform.now())
944
                            }
945
                        };
946
947
0
                        match async_op {
948
0
                            async_tree::NextNecessaryAsyncOp::Ready(dl) => {
949
0
                                break WakeUpReason::StartDownload(dl.id, dl.block_index)
950
                            }
951
0
                            async_tree::NextNecessaryAsyncOp::NotReady { when } => {
952
0
                                if let Some(when) = when {
953
0
                                    either::Left(background.platform.sleep_until(when))
954
                                } else {
955
0
                                    either::Right(future::pending())
956
                                }
957
                            }
958
                        }
959
                    } else {
960
0
                        either::Right(future::pending())
961
                    };
962
963
0
                    match &mut background.tree {
964
0
                        Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
965
0
                            match tree.try_advance_output() {
966
0
                                Some(update) => {
967
0
                                    break WakeUpReason::TreeAdvanceFinalizedKnown(update)
968
                                }
969
0
                                None => wait.await,
970
                            }
971
                        }
972
0
                        Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
973
0
                            match tree.try_advance_output() {
974
0
                                Some(update) => {
975
0
                                    break WakeUpReason::TreeAdvanceFinalizedUnknown(update)
976
                                }
977
0
                                None => wait.await,
978
                            }
979
                        }
980
                    }
981
                }
982
0
            })
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s3_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s3_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s3_0B8_
983
0
            .await
984
        };
985
986
0
        match wake_up_reason {
987
0
            WakeUpReason::StartDownload(download_id, block_index) => {
988
0
                let block = match &mut background.tree {
989
0
                    Tree::FinalizedBlockRuntimeKnown { tree, .. } => &tree[block_index],
990
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => &tree[block_index],
991
                };
992
993
0
                log!(
994
0
                    &background.platform,
995
0
                    Debug,
996
0
                    &background.log_target,
997
0
                    "block-runtime-download-start",
998
0
                    block_hash = HashDisplay(&block.hash)
999
0
                );
1000
0
1001
0
                // Dispatches a runtime download task to `runtime_downloads`.
1002
0
                background.runtime_downloads.push(Box::pin({
1003
0
                    let future = download_runtime(
1004
0
                        background.sync_service.clone(),
1005
0
                        block.hash,
1006
0
                        &block.scale_encoded_header,
1007
0
                    );
1008
0
1009
0
                    async move { (download_id, future.await) }
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s4_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s4_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s4_0B8_
1010
0
                }));
1011
            }
1012
1013
            WakeUpReason::TreeAdvanceFinalizedKnown(async_tree::OutputUpdate::Finalized {
1014
0
                user_data: new_finalized,
1015
0
                best_output_block_updated,
1016
0
                pruned_blocks,
1017
0
                former_finalized_async_op_user_data: former_finalized_runtime,
1018
                ..
1019
            }) => {
1020
                let Tree::FinalizedBlockRuntimeKnown {
1021
0
                    tree,
1022
0
                    finalized_block,
1023
0
                    all_blocks_subscriptions,
1024
0
                    pinned_blocks,
1025
0
                } = &mut background.tree
1026
                else {
1027
0
                    unreachable!()
1028
                };
1029
1030
0
                *finalized_block = new_finalized;
1031
0
                let best_block_hash_if_changed = if best_output_block_updated {
1032
0
                    Some(
1033
0
                        tree.output_best_block_index()
1034
0
                            .map_or(finalized_block.hash, |(idx, _)| tree[idx].hash),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s5_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s5_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s5_0B8_
1035
0
                    )
1036
                } else {
1037
0
                    None
1038
                };
1039
1040
0
                log!(
1041
0
                    &background.platform,
1042
0
                    Trace,
1043
0
                    &background.log_target,
1044
0
                    "output-chain-finalized",
1045
0
                    block_hash = HashDisplay(&finalized_block.hash),
1046
0
                    best_block_hash = if let Some(best_block_hash) = best_block_hash_if_changed {
1047
0
                        Cow::Owned(HashDisplay(&best_block_hash).to_string())
1048
                    } else {
1049
0
                        Cow::Borrowed("<unchanged>")
1050
                    },
1051
0
                    num_subscribers = all_blocks_subscriptions.len()
1052
0
                );
1053
0
1054
0
                // The finalization might cause some runtimes in the list of runtimes
1055
0
                // to have become unused. Clean them up.
1056
0
                drop(former_finalized_runtime);
1057
0
                background
1058
0
                    .runtimes
1059
0
                    .retain(|_, runtime| runtime.strong_count() > 0);
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s6_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s6_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s6_0B8_
1060
0
1061
0
                let all_blocks_notif = Notification::Finalized {
1062
0
                    best_block_hash_if_changed,
1063
0
                    hash: finalized_block.hash,
1064
0
                    pruned_blocks: pruned_blocks.iter().map(|(_, b, _)| b.hash).collect(),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s7_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s7_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s7_0B8_
1065
0
                };
1066
0
1067
0
                let mut to_remove = Vec::new();
1068
0
                for (subscription_id, (sender, finalized_pinned_remaining)) in
1069
0
                    all_blocks_subscriptions.iter_mut()
1070
                {
1071
0
                    let count_limit = pruned_blocks.len() + 1;
1072
0
1073
0
                    if *finalized_pinned_remaining < count_limit {
1074
0
                        to_remove.push(*subscription_id);
1075
0
                        continue;
1076
0
                    }
1077
0
1078
0
                    if sender.try_send(all_blocks_notif.clone()).is_err() {
1079
0
                        to_remove.push(*subscription_id);
1080
0
                        continue;
1081
0
                    }
1082
0
1083
0
                    *finalized_pinned_remaining -= count_limit;
1084
1085
                    // Mark the finalized and pruned blocks as finalized or non-canonical.
1086
0
                    for block in iter::once(&finalized_block.hash)
1087
0
                        .chain(pruned_blocks.iter().map(|(_, b, _)| &b.hash))
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s8_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s8_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s8_0B8_
1088
                    {
1089
0
                        if let Some(pin) = pinned_blocks.get_mut(&(*subscription_id, *block)) {
1090
0
                            debug_assert!(pin.block_ignores_limit);
1091
0
                            pin.block_ignores_limit = false;
1092
0
                        }
1093
                    }
1094
                }
1095
0
                for to_remove in to_remove {
1096
0
                    all_blocks_subscriptions.remove(&to_remove);
1097
0
                    let pinned_blocks_to_remove = pinned_blocks
1098
0
                        .range((to_remove, [0; 32])..=(to_remove, [0xff; 32]))
1099
0
                        .map(|((_, h), _)| *h)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0s9_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s9_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0s9_0B8_
1100
0
                        .collect::<Vec<_>>();
1101
0
                    for block in pinned_blocks_to_remove {
1102
0
                        pinned_blocks.remove(&(to_remove, block));
1103
0
                    }
1104
                }
1105
            }
1106
1107
0
            WakeUpReason::TreeAdvanceFinalizedKnown(async_tree::OutputUpdate::Block(block)) => {
1108
                let Tree::FinalizedBlockRuntimeKnown {
1109
0
                    tree,
1110
0
                    finalized_block,
1111
0
                    all_blocks_subscriptions,
1112
0
                    pinned_blocks,
1113
0
                } = &mut background.tree
1114
                else {
1115
0
                    unreachable!()
1116
                };
1117
1118
0
                let block_index = block.index;
1119
0
                let block_runtime = tree.block_async_user_data(block_index).unwrap().clone();
1120
0
                let block_hash = tree[block_index].hash;
1121
0
                let scale_encoded_header = tree[block_index].scale_encoded_header.clone();
1122
0
                let is_new_best = block.is_new_best;
1123
0
1124
0
                let (block_number, state_trie_root_hash) = {
1125
0
                    let decoded = header::decode(
1126
0
                        &scale_encoded_header,
1127
0
                        background.sync_service.block_number_bytes(),
1128
0
                    )
1129
0
                    .unwrap();
1130
0
                    (decoded.number, *decoded.state_root)
1131
0
                };
1132
0
1133
0
                let parent_runtime = tree
1134
0
                    .parent(block_index)
1135
0
                    .map_or(tree.output_finalized_async_user_data().clone(), |idx| {
1136
0
                        tree.block_async_user_data(idx).unwrap().clone()
1137
0
                    });
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sa_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sa_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sa_0B8_
1138
0
1139
0
                log!(
1140
0
                    &background.platform,
1141
0
                    Trace,
1142
0
                    &background.log_target,
1143
0
                    "output-chain-new-block",
1144
0
                    block_hash = HashDisplay(&tree[block_index].hash),
1145
0
                    is_new_best,
1146
0
                    num_subscribers = all_blocks_subscriptions.len()
1147
0
                );
1148
1149
0
                let notif = Notification::Block(BlockNotification {
1150
0
                    parent_hash: tree
1151
0
                        .parent(block_index)
1152
0
                        .map_or(finalized_block.hash, |idx| tree[idx].hash),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sb_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sb_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sb_0B8_
1153
0
                    is_new_best,
1154
0
                    scale_encoded_header,
1155
0
                    new_runtime: if !Arc::ptr_eq(&parent_runtime, &block_runtime) {
1156
0
                        Some(
1157
0
                            block_runtime
1158
0
                                .runtime
1159
0
                                .as_ref()
1160
0
                                .map(|rt| rt.runtime_version().clone())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sc_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sc_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sc_0B8_
1161
0
                                .map_err(|err| err.clone()),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sd_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sd_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sd_0B8_
1162
0
                        )
1163
                    } else {
1164
0
                        None
1165
                    },
1166
                });
1167
1168
0
                let mut to_remove = Vec::new();
1169
0
                for (subscription_id, (sender, _)) in all_blocks_subscriptions.iter_mut() {
1170
0
                    if sender.try_send(notif.clone()).is_ok() {
1171
0
                        let _prev_value = pinned_blocks.insert(
1172
0
                            (*subscription_id, block_hash),
1173
0
                            PinnedBlock {
1174
0
                                runtime: block_runtime.clone(),
1175
0
                                state_trie_root_hash,
1176
0
                                block_number,
1177
0
                                block_ignores_limit: true,
1178
0
                            },
1179
0
                        );
1180
0
                        debug_assert!(_prev_value.is_none());
1181
0
                    } else {
1182
0
                        to_remove.push(*subscription_id);
1183
0
                    }
1184
                }
1185
0
                for to_remove in to_remove {
1186
0
                    all_blocks_subscriptions.remove(&to_remove);
1187
0
                    let pinned_blocks_to_remove = pinned_blocks
1188
0
                        .range((to_remove, [0; 32])..=(to_remove, [0xff; 32]))
1189
0
                        .map(|((_, h), _)| *h)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0se_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0se_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0se_0B8_
1190
0
                        .collect::<Vec<_>>();
1191
0
                    for block in pinned_blocks_to_remove {
1192
0
                        pinned_blocks.remove(&(to_remove, block));
1193
0
                    }
1194
                }
1195
            }
1196
1197
            WakeUpReason::TreeAdvanceFinalizedKnown(
1198
0
                async_tree::OutputUpdate::BestBlockChanged { best_block_index },
1199
            ) => {
1200
                let Tree::FinalizedBlockRuntimeKnown {
1201
0
                    tree,
1202
0
                    finalized_block,
1203
0
                    all_blocks_subscriptions,
1204
0
                    pinned_blocks,
1205
0
                } = &mut background.tree
1206
                else {
1207
0
                    unreachable!()
1208
                };
1209
1210
0
                let hash = best_block_index
1211
0
                    .map_or(&*finalized_block, |idx| &tree[idx])
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sf_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sf_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sf_0B8_
1212
0
                    .hash;
1213
0
1214
0
                log!(
1215
0
                    &background.platform,
1216
0
                    Trace,
1217
0
                    &background.log_target,
1218
0
                    "output-chain-best-block-update",
1219
0
                    block_hash = HashDisplay(&hash),
1220
0
                    num_subscribers = all_blocks_subscriptions.len()
1221
0
                );
1222
0
1223
0
                let notif = Notification::BestBlockChanged { hash };
1224
0
1225
0
                let mut to_remove = Vec::new();
1226
0
                for (subscription_id, (sender, _)) in all_blocks_subscriptions.iter_mut() {
1227
0
                    if sender.try_send(notif.clone()).is_err() {
1228
0
                        to_remove.push(*subscription_id);
1229
0
                    }
1230
                }
1231
0
                for to_remove in to_remove {
1232
0
                    all_blocks_subscriptions.remove(&to_remove);
1233
0
                    let pinned_blocks_to_remove = pinned_blocks
1234
0
                        .range((to_remove, [0; 32])..=(to_remove, [0xff; 32]))
1235
0
                        .map(|((_, h), _)| *h)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sg_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sg_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sg_0B8_
1236
0
                        .collect::<Vec<_>>();
1237
0
                    for block in pinned_blocks_to_remove {
1238
0
                        pinned_blocks.remove(&(to_remove, block));
1239
0
                    }
1240
                }
1241
            }
1242
1243
            WakeUpReason::TreeAdvanceFinalizedUnknown(async_tree::OutputUpdate::Block(_))
1244
            | WakeUpReason::TreeAdvanceFinalizedUnknown(
1245
                async_tree::OutputUpdate::BestBlockChanged { .. },
1246
            ) => {
1247
                // Nothing to do.
1248
0
                continue;
1249
            }
1250
1251
            WakeUpReason::TreeAdvanceFinalizedUnknown(async_tree::OutputUpdate::Finalized {
1252
0
                user_data: new_finalized,
1253
0
                former_finalized_async_op_user_data,
1254
0
                best_output_block_updated,
1255
                ..
1256
            }) => {
1257
0
                let Tree::FinalizedBlockRuntimeUnknown { tree, .. } = &mut background.tree else {
1258
0
                    unreachable!()
1259
                };
1260
1261
                // Make sure that this is the first finalized block whose runtime is
1262
                // known, otherwise there's a pretty big bug somewhere.
1263
0
                debug_assert!(former_finalized_async_op_user_data.is_none());
1264
1265
0
                let best_block_hash_if_changed = if best_output_block_updated {
1266
0
                    Some(
1267
0
                        tree.output_best_block_index()
1268
0
                            .map_or(new_finalized.hash, |(idx, _)| tree[idx].hash),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sh_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sh_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sh_0B8_
1269
0
                    )
1270
                } else {
1271
0
                    None
1272
                };
1273
0
                log!(
1274
0
                    &background.platform,
1275
0
                    Trace,
1276
0
                    &background.log_target,
1277
0
                    "output-chain-initialized",
1278
0
                    finalized_block_hash = HashDisplay(&new_finalized.hash),
1279
0
                    best_block_hash = if let Some(best_block_hash) = best_block_hash_if_changed {
1280
0
                        Cow::Owned(HashDisplay(&best_block_hash).to_string())
1281
                    } else {
1282
0
                        Cow::Borrowed("<unchanged>")
1283
                    },
1284
                );
1285
1286
                // Substitute `tree` with a dummy empty tree just in order to extract
1287
                // the value. The `tree` only contains "async op user datas" equal
1288
                // to `Some` (they're inserted manually when a download finishes)
1289
                // except for the finalized block which has now just been extracted.
1290
                // We can safely unwrap() all these user datas.
1291
0
                let new_tree = mem::replace(
1292
0
                    tree,
1293
0
                    async_tree::AsyncTree::new(async_tree::Config {
1294
0
                        finalized_async_user_data: None,
1295
0
                        retry_after_failed: Duration::new(0, 0),
1296
0
                        blocks_capacity: 0,
1297
0
                    }),
1298
0
                )
1299
0
                .map_async_op_user_data(|runtime_index| runtime_index.unwrap());
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0si_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0si_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0si_0B8_
1300
0
1301
0
                // Change the state of `Background` to the "finalized runtime known" state.
1302
0
                background.tree = Tree::FinalizedBlockRuntimeKnown {
1303
0
                    all_blocks_subscriptions: hashbrown::HashMap::with_capacity_and_hasher(
1304
0
                        32,
1305
0
                        Default::default(),
1306
0
                    ), // TODO: capacity?
1307
0
                    pinned_blocks: BTreeMap::new(),
1308
0
                    tree: new_tree,
1309
0
                    finalized_block: new_finalized,
1310
0
                };
1311
            }
1312
1313
            WakeUpReason::MustSubscribe => {
1314
                // Subscription to the sync service must be recreated.
1315
1316
                // The buffer size should be large enough so that, if the CPU is busy, it
1317
                // doesn't become full before the execution of the runtime service resumes.
1318
                // Note that this `await` freezes the entire runtime service background task,
1319
                // but the sync service guarantees that `subscribe_all` returns very quickly.
1320
0
                let subscription = background.sync_service.subscribe_all(32, true).await;
1321
1322
0
                log!(
1323
0
                    &background.platform,
1324
0
                    Trace,
1325
0
                    &background.log_target,
1326
0
                    "sync-service-subscribed",
1327
0
                    finalized_block_hash = HashDisplay(&header::hash_from_scale_encoded_header(
1328
0
                        &subscription.finalized_block_scale_encoded_header
1329
0
                    )),
1330
0
                    finalized_block_runtime_known = ?subscription.finalized_block_runtime.is_some()
1331
0
                );
1332
0
1333
0
                // Update the state of `Background` with what we just grabbed.
1334
0
                //
1335
0
                // Note that the content of `Background` is reset unconditionally.
1336
0
                // It might seem like a good idea to only reset the content of `Background` if the new
1337
0
                // subscription has a different finalized block than currently. However, there is
1338
0
                // absolutely no guarantee for the non-finalized blocks currently in the tree to be a
1339
0
                // subset or superset of the non-finalized blocks in the new subscription.
1340
0
                // Using the new subscription but keeping the existing tree could therefore result in
1341
0
                // state inconsistencies.
1342
0
                //
1343
0
                // Additionally, the situation where a subscription is killed but the finalized block
1344
0
                // didn't change should be extremely rare anyway.
1345
0
                {
1346
0
                    background.runtimes = slab::Slab::with_capacity(2); // TODO: hardcoded capacity
1347
1348
                    // TODO: DRY below
1349
0
                    if let Some(finalized_block_runtime) = subscription.finalized_block_runtime {
1350
0
                        let finalized_block_hash = header::hash_from_scale_encoded_header(
1351
0
                            &subscription.finalized_block_scale_encoded_header,
1352
0
                        );
1353
0
                        let finalized_block_height = header::decode(
1354
0
                            &subscription.finalized_block_scale_encoded_header,
1355
0
                            background.sync_service.block_number_bytes(),
1356
0
                        )
1357
0
                        .unwrap()
1358
0
                        .number; // TODO: consider feeding the information from the sync service?
1359
0
1360
0
                        let storage_code_len = u64::try_from(
1361
0
                            finalized_block_runtime
1362
0
                                .storage_code
1363
0
                                .as_ref()
1364
0
                                .map_or(0, |v| v.len()),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sj_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sj_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sj_0B8_
1365
0
                        )
1366
0
                        .unwrap();
1367
0
1368
0
                        let runtime = Arc::new(Runtime {
1369
0
                            runtime_code: finalized_block_runtime.storage_code,
1370
0
                            heap_pages: finalized_block_runtime.storage_heap_pages,
1371
0
                            code_merkle_value: finalized_block_runtime.code_merkle_value,
1372
0
                            closest_ancestor_excluding: finalized_block_runtime
1373
0
                                .closest_ancestor_excluding,
1374
0
                            runtime: Ok(finalized_block_runtime.virtual_machine),
1375
0
                        });
1376
0
1377
0
                        match &runtime.runtime {
1378
0
                            Ok(runtime) => {
1379
0
                                log!(
1380
0
                                    &background.platform,
1381
0
                                    Info,
1382
0
                                    &background.log_target,
1383
0
                                    format!(
1384
0
                                        "Finalized block runtime ready. Spec version: {}. \
1385
0
                                        Size of `:code`: {}.",
1386
0
                                        runtime.runtime_version().decode().spec_version,
1387
0
                                        BytesDisplay(storage_code_len)
1388
0
                                    )
1389
0
                                );
1390
0
                            }
1391
0
                            Err(error) => {
1392
0
                                log!(
1393
0
                                    &background.platform,
1394
0
                                    Warn,
1395
0
                                    &background.log_target,
1396
0
                                    format!(
1397
0
                                        "Erronenous finalized block runtime. Size of \
1398
0
                                        `:code`: {}.\nError: {}\nThis indicates an incompatibility \
1399
0
                                        between smoldot and the chain.",
1400
0
                                        BytesDisplay(storage_code_len),
1401
0
                                        error
1402
0
                                    )
1403
0
                                );
1404
0
                            }
1405
                        }
1406
1407
0
                        background.tree = Tree::FinalizedBlockRuntimeKnown {
1408
0
                            all_blocks_subscriptions: hashbrown::HashMap::with_capacity_and_hasher(
1409
0
                                32,
1410
0
                                Default::default(),
1411
0
                            ), // TODO: capacity?
1412
0
                            pinned_blocks: BTreeMap::new(),
1413
0
                            finalized_block: Block {
1414
0
                                hash: finalized_block_hash,
1415
0
                                height: finalized_block_height,
1416
0
                                scale_encoded_header: subscription
1417
0
                                    .finalized_block_scale_encoded_header,
1418
0
                            },
1419
0
                            tree: {
1420
0
                                let mut tree =
1421
0
                                    async_tree::AsyncTree::<_, Block, _>::new(async_tree::Config {
1422
0
                                        finalized_async_user_data: runtime,
1423
0
                                        retry_after_failed: Duration::from_secs(10), // TODO: hardcoded
1424
0
                                        blocks_capacity: 32,
1425
0
                                    });
1426
1427
0
                                for block in subscription.non_finalized_blocks_ancestry_order {
1428
0
                                    let parent_index = if block.parent_hash == finalized_block_hash
1429
                                    {
1430
0
                                        None
1431
                                    } else {
1432
0
                                        Some(
1433
0
                                            tree.input_output_iter_unordered()
1434
0
                                                .find(|b| b.user_data.hash == block.parent_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sk_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sk_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sk_0B8_
1435
0
                                                .unwrap()
1436
0
                                                .id,
1437
0
                                        )
1438
                                    };
1439
1440
0
                                    let same_runtime_as_parent = same_runtime_as_parent(
1441
0
                                        &block.scale_encoded_header,
1442
0
                                        background.sync_service.block_number_bytes(),
1443
0
                                    );
1444
0
                                    let _ = tree.input_insert_block(
1445
0
                                        Block {
1446
0
                                            hash: header::hash_from_scale_encoded_header(
1447
0
                                                &block.scale_encoded_header,
1448
0
                                            ),
1449
0
                                            height: header::decode(
1450
0
                                                &block.scale_encoded_header,
1451
0
                                                background.sync_service.block_number_bytes(),
1452
0
                                            )
1453
0
                                            .unwrap()
1454
0
                                            .number, // TODO: consider feeding the information from the sync service?
1455
0
                                            scale_encoded_header: block.scale_encoded_header,
1456
0
                                        },
1457
0
                                        parent_index,
1458
0
                                        same_runtime_as_parent,
1459
0
                                        block.is_new_best,
1460
0
                                    );
1461
                                }
1462
1463
0
                                tree
1464
                            },
1465
                        };
1466
0
                    } else {
1467
0
                        background.tree = Tree::FinalizedBlockRuntimeUnknown {
1468
                            tree: {
1469
0
                                let mut tree = async_tree::AsyncTree::new(async_tree::Config {
1470
0
                                    finalized_async_user_data: None,
1471
0
                                    retry_after_failed: Duration::from_secs(10), // TODO: hardcoded
1472
0
                                    blocks_capacity: 32,
1473
0
                                });
1474
0
                                let node_index = tree.input_insert_block(
1475
0
                                    Block {
1476
0
                                        hash: header::hash_from_scale_encoded_header(
1477
0
                                            &subscription.finalized_block_scale_encoded_header,
1478
0
                                        ),
1479
0
                                        height: header::decode(
1480
0
                                            &subscription.finalized_block_scale_encoded_header,
1481
0
                                            background.sync_service.block_number_bytes(),
1482
0
                                        )
1483
0
                                        .unwrap()
1484
0
                                        .number, // TODO: consider feeding the information from the sync service?
1485
0
                                        scale_encoded_header: subscription
1486
0
                                            .finalized_block_scale_encoded_header,
1487
0
                                    },
1488
0
                                    None,
1489
0
                                    false,
1490
0
                                    true,
1491
0
                                );
1492
0
                                tree.input_finalize(node_index);
1493
1494
0
                                for block in subscription.non_finalized_blocks_ancestry_order {
1495
0
                                    // TODO: O(n)
1496
0
                                    let parent_index = tree
1497
0
                                        .input_output_iter_unordered()
1498
0
                                        .find(|b| b.user_data.hash == block.parent_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sl_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sl_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sl_0B8_
1499
0
                                        .unwrap()
1500
0
                                        .id;
1501
0
1502
0
                                    let same_runtime_as_parent = same_runtime_as_parent(
1503
0
                                        &block.scale_encoded_header,
1504
0
                                        background.sync_service.block_number_bytes(),
1505
0
                                    );
1506
0
                                    let _ = tree.input_insert_block(
1507
0
                                        Block {
1508
0
                                            hash: header::hash_from_scale_encoded_header(
1509
0
                                                &block.scale_encoded_header,
1510
0
                                            ),
1511
0
                                            height: header::decode(
1512
0
                                                &block.scale_encoded_header,
1513
0
                                                background.sync_service.block_number_bytes(),
1514
0
                                            )
1515
0
                                            .unwrap()
1516
0
                                            .number, // TODO: consider feeding the information from the sync service?
1517
0
                                            scale_encoded_header: block.scale_encoded_header,
1518
0
                                        },
1519
0
                                        Some(parent_index),
1520
0
                                        same_runtime_as_parent,
1521
0
                                        block.is_new_best,
1522
0
                                    );
1523
0
                                }
1524
1525
0
                                tree
1526
                            },
1527
                        };
1528
                    }
1529
                }
1530
1531
0
                background.blocks_stream = Some(Box::pin(subscription.new_blocks));
1532
0
                background.runtime_downloads = stream::FuturesUnordered::new();
1533
            }
1534
1535
0
            WakeUpReason::StartPendingSubscribeAll(pending_subscription) => {
1536
                // A subscription is waiting to be started.
1537
1538
                // Extract the components of the `FinalizedBlockRuntimeKnown`.
1539
0
                let (tree, finalized_block, pinned_blocks, all_blocks_subscriptions) =
1540
0
                    match &mut background.tree {
1541
                        Tree::FinalizedBlockRuntimeKnown {
1542
0
                            tree,
1543
0
                            finalized_block,
1544
0
                            pinned_blocks,
1545
0
                            all_blocks_subscriptions,
1546
0
                        } => (
1547
0
                            tree,
1548
0
                            finalized_block,
1549
0
                            pinned_blocks,
1550
0
                            all_blocks_subscriptions,
1551
0
                        ),
1552
0
                        _ => unreachable!(),
1553
                    };
1554
1555
0
                let (tx, new_blocks_channel) =
1556
0
                    async_channel::bounded(pending_subscription.buffer_size);
1557
0
                let subscription_id = background.next_subscription_id;
1558
0
                debug_assert_eq!(
1559
0
                    pinned_blocks
1560
0
                        .range((subscription_id, [0; 32])..=(subscription_id, [0xff; 32]))
1561
0
                        .count(),
1562
                    0
1563
                );
1564
0
                background.next_subscription_id += 1;
1565
0
1566
0
                log!(
1567
0
                    &background.platform,
1568
0
                    Trace,
1569
0
                    &background.log_target,
1570
0
                    "pending-runtime-service-subscriptions-process",
1571
0
                    subscription_id
1572
0
                );
1573
0
1574
0
                let decoded_finalized_block = header::decode(
1575
0
                    &finalized_block.scale_encoded_header,
1576
0
                    background.sync_service.block_number_bytes(),
1577
0
                )
1578
0
                .unwrap();
1579
0
1580
0
                let _prev_value = pinned_blocks.insert(
1581
0
                    (subscription_id, finalized_block.hash),
1582
0
                    PinnedBlock {
1583
0
                        runtime: tree.output_finalized_async_user_data().clone(),
1584
0
                        state_trie_root_hash: *decoded_finalized_block.state_root,
1585
0
                        block_number: decoded_finalized_block.number,
1586
0
                        block_ignores_limit: false,
1587
0
                    },
1588
0
                );
1589
0
                debug_assert!(_prev_value.is_none());
1590
1591
0
                let mut non_finalized_blocks_ancestry_order =
1592
0
                    Vec::with_capacity(tree.num_input_non_finalized_blocks());
1593
0
                for block in tree.input_output_iter_ancestry_order() {
1594
0
                    let runtime = match block.async_op_user_data {
1595
0
                        Some(rt) => rt.clone(),
1596
0
                        None => continue, // Runtime of that block not known yet, so it shouldn't be reported.
1597
                    };
1598
1599
0
                    let block_hash = block.user_data.hash;
1600
0
                    let parent_runtime = tree.parent(block.id).map_or(
1601
0
                        tree.output_finalized_async_user_data().clone(),
1602
0
                        |parent_idx| tree.block_async_user_data(parent_idx).unwrap().clone(),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sm_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sm_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sm_0B8_
1603
0
                    );
1604
0
1605
0
                    let parent_hash = *header::decode(
1606
0
                        &block.user_data.scale_encoded_header,
1607
0
                        background.sync_service.block_number_bytes(),
1608
0
                    )
1609
0
                    .unwrap()
1610
0
                    .parent_hash; // TODO: correct? if yes, document
1611
0
                    debug_assert!(
1612
0
                        parent_hash == finalized_block.hash
1613
0
                            || tree
1614
0
                                .input_output_iter_ancestry_order()
1615
0
                                .any(|b| parent_hash == b.user_data.hash
1616
0
                                    && b.async_op_user_data.is_some())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sL_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sL_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sL_0B8_
1617
                    );
1618
1619
0
                    let decoded_header = header::decode(
1620
0
                        &block.user_data.scale_encoded_header,
1621
0
                        background.sync_service.block_number_bytes(),
1622
0
                    )
1623
0
                    .unwrap();
1624
0
1625
0
                    let _prev_value = pinned_blocks.insert(
1626
0
                        (subscription_id, block_hash),
1627
0
                        PinnedBlock {
1628
0
                            runtime: runtime.clone(),
1629
0
                            state_trie_root_hash: *decoded_header.state_root,
1630
0
                            block_number: decoded_header.number,
1631
0
                            block_ignores_limit: true,
1632
0
                        },
1633
0
                    );
1634
0
                    debug_assert!(_prev_value.is_none());
1635
1636
0
                    non_finalized_blocks_ancestry_order.push(BlockNotification {
1637
0
                        is_new_best: block.is_output_best,
1638
0
                        parent_hash,
1639
0
                        scale_encoded_header: block.user_data.scale_encoded_header.clone(),
1640
0
                        new_runtime: if !Arc::ptr_eq(&runtime, &parent_runtime) {
1641
0
                            Some(
1642
0
                                runtime
1643
0
                                    .runtime
1644
0
                                    .as_ref()
1645
0
                                    .map(|rt| rt.runtime_version().clone())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sn_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sn_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sn_0B8_
1646
0
                                    .map_err(|err| err.clone()),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0so_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0so_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0so_0B8_
1647
0
                            )
1648
                        } else {
1649
0
                            None
1650
                        },
1651
                    });
1652
                }
1653
1654
0
                debug_assert!(matches!(
1655
0
                    non_finalized_blocks_ancestry_order
1656
0
                        .iter()
1657
0
                        .filter(|b| b.is_new_best)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sM_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sM_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sM_0B8_
1658
0
                        .count(),
1659
                    0 | 1
1660
                ));
1661
1662
0
                all_blocks_subscriptions.insert(
1663
0
                    subscription_id,
1664
0
                    (tx, pending_subscription.max_pinned_blocks.get() - 1),
1665
0
                );
1666
0
1667
0
                let _ = pending_subscription.result_tx.send(SubscribeAll {
1668
0
                    finalized_block_scale_encoded_header: finalized_block
1669
0
                        .scale_encoded_header
1670
0
                        .clone(),
1671
0
                    finalized_block_runtime: tree
1672
0
                        .output_finalized_async_user_data()
1673
0
                        .runtime
1674
0
                        .as_ref()
1675
0
                        .map(|rt| rt.runtime_version().clone())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sp_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sp_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sp_0B8_
1676
0
                        .map_err(|err| err.clone()),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sq_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sq_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sq_0B8_
1677
0
                    non_finalized_blocks_ancestry_order,
1678
0
                    new_blocks: Subscription {
1679
0
                        subscription_id,
1680
0
                        channel: Box::pin(new_blocks_channel),
1681
0
                        to_background: background.to_background_tx.upgrade().unwrap(),
1682
0
                    },
1683
0
                });
1684
            }
1685
1686
0
            WakeUpReason::SyncServiceSubscriptionReset => {
1687
0
                // The sync service subscription has been or must be reset.
1688
0
                log!(
1689
0
                    &background.platform,
1690
0
                    Trace,
1691
0
                    &background.log_target,
1692
0
                    "sync-subscription-reset"
1693
0
                );
1694
0
                background.blocks_stream = None;
1695
0
            }
1696
1697
            WakeUpReason::ForegroundClosed => {
1698
                // Frontend and all subscriptions have shut down.
1699
0
                log!(
1700
0
                    &background.platform,
1701
0
                    Debug,
1702
0
                    &background.log_target,
1703
0
                    "graceful-shutdown"
1704
0
                );
1705
0
                return;
1706
            }
1707
1708
0
            WakeUpReason::ToBackground(ToBackground::SubscribeAll(msg)) => {
1709
0
                // Foreground wants to subscribe.
1710
0
1711
0
                log!(
1712
0
                    &background.platform,
1713
0
                    Trace,
1714
0
                    &background.log_target,
1715
0
                    "runtime-service-subscription-requested"
1716
0
                );
1717
0
1718
0
                // In order to avoid potentially growing `pending_subscriptions` forever, we
1719
0
                // remove senders that are closed. This is `O(n)`, but we expect this list to
1720
0
                // be rather small.
1721
0
                background
1722
0
                    .pending_subscriptions
1723
0
                    .retain(|s| !s.result_tx.is_canceled());
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sr_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sr_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sr_0B8_
1724
0
                background.pending_subscriptions.push_back(msg);
1725
0
            }
1726
1727
            WakeUpReason::ToBackground(ToBackground::CompileAndPinRuntime {
1728
0
                result_tx,
1729
0
                storage_code,
1730
0
                storage_heap_pages,
1731
0
                code_merkle_value,
1732
0
                closest_ancestor_excluding,
1733
0
            }) => {
1734
0
                // Foreground wants to compile the given runtime.
1735
0
1736
0
                // Try to find an existing identical runtime.
1737
0
                let existing_runtime = background
1738
0
                    .runtimes
1739
0
                    .iter()
1740
0
                    .filter_map(|(_, rt)| rt.upgrade())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0ss_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0ss_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0ss_0B8_
1741
0
                    .find(|rt| {
1742
0
                        rt.runtime_code == storage_code && rt.heap_pages == storage_heap_pages
1743
0
                    });
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0st_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0st_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0st_0B8_
1744
1745
0
                let runtime = if let Some(existing_runtime) = existing_runtime {
1746
0
                    log!(
1747
0
                        &background.platform,
1748
0
                        Trace,
1749
0
                        &background.log_target,
1750
0
                        "foreground-compile-and-pin-runtime-cache-hit"
1751
0
                    );
1752
0
                    existing_runtime
1753
                } else {
1754
                    // No identical runtime was found. Try compiling the new runtime.
1755
0
                    let before_compilation = background.platform.now();
1756
0
                    let runtime = compile_runtime(
1757
0
                        &background.platform,
1758
0
                        &background.log_target,
1759
0
                        &storage_code,
1760
0
                        &storage_heap_pages,
1761
0
                    );
1762
0
                    let compilation_duration = background.platform.now() - before_compilation;
1763
0
                    log!(
1764
0
                        &background.platform,
1765
0
                        Debug,
1766
0
                        &background.log_target,
1767
0
                        "foreground-compile-and-pin-runtime-cache-miss",
1768
0
                        ?compilation_duration,
1769
0
                        compilation_success = runtime.is_ok()
1770
0
                    );
1771
0
                    let runtime = Arc::new(Runtime {
1772
0
                        heap_pages: storage_heap_pages,
1773
0
                        runtime_code: storage_code,
1774
0
                        code_merkle_value,
1775
0
                        closest_ancestor_excluding,
1776
0
                        runtime,
1777
0
                    });
1778
0
                    background.runtimes.insert(Arc::downgrade(&runtime));
1779
0
                    runtime
1780
                };
1781
1782
0
                let _ = result_tx.send(runtime);
1783
            }
1784
1785
            WakeUpReason::ToBackground(ToBackground::FinalizedRuntimeStorageMerkleValues {
1786
0
                result_tx,
1787
0
            }) => {
1788
0
                // Foreground wants the finalized runtime storage Merkle values.
1789
0
1790
0
                log!(
1791
0
                    &background.platform,
1792
0
                    Trace,
1793
0
                    &background.log_target,
1794
0
                    "foreground-finalized-runtime-storage-merkle-values"
1795
0
                );
1796
0
1797
0
                let _ = result_tx.send(
1798
0
                    if let Tree::FinalizedBlockRuntimeKnown { tree, .. } = &background.tree {
1799
0
                        let runtime = &tree.output_finalized_async_user_data();
1800
0
                        Some((
1801
0
                            runtime.runtime_code.clone(),
1802
0
                            runtime.code_merkle_value.clone(),
1803
0
                            runtime.closest_ancestor_excluding.clone(),
1804
0
                        ))
1805
                    } else {
1806
0
                        None
1807
                    },
1808
                );
1809
            }
1810
1811
0
            WakeUpReason::ToBackground(ToBackground::IsNearHeadOfChainHeuristic { result_tx }) => {
1812
0
                // Foreground wants to query whether we are at the head of the chain.
1813
0
1814
0
                log!(
1815
0
                    &background.platform,
1816
0
                    Trace,
1817
0
                    &background.log_target,
1818
0
                    "foreground-is-near-head-of-chain-heuristic"
1819
0
                );
1820
0
1821
0
                // If we aren't subscribed to the sync service yet, we notify that we are not
1822
0
                // near the head of the chain.
1823
0
                if background.blocks_stream.is_none() {
1824
0
                    let _ = result_tx.send(false);
1825
0
                    continue;
1826
0
                }
1827
1828
                // Check whether any runtime has been downloaded yet. If not, we notify that
1829
                // we're not near the head of the chain.
1830
                let Tree::FinalizedBlockRuntimeKnown {
1831
0
                    tree,
1832
0
                    finalized_block,
1833
                    ..
1834
0
                } = &background.tree
1835
                else {
1836
0
                    let _ = result_tx.send(false);
1837
0
                    continue;
1838
                };
1839
1840
                // The runtime service head might be close to the sync service head, but if the
1841
                // sync service is far away from the head of the chain, then the runtime service
1842
                // is necessarily also far away.
1843
0
                if !background
1844
0
                    .sync_service
1845
0
                    .is_near_head_of_chain_heuristic()
1846
0
                    .await
1847
                {
1848
0
                    let _ = result_tx.send(false);
1849
0
                    continue;
1850
0
                }
1851
1852
                // If the input best block (i.e. what the sync service feeds us) is equal to
1853
                // output finalized block (i.e. what the runtime service has downloaded), we are
1854
                // at the very head of the chain.
1855
0
                let Some(input_best) = tree.input_best_block_index() else {
1856
0
                    let _ = result_tx.send(true);
1857
0
                    continue;
1858
                };
1859
1860
                // We consider ourselves as being at the head of the chain if the
1861
                // distance between the output tree best (i.e. whose runtime has
1862
                // been downloaded) and the input tree best (i.e. what the sync service
1863
                // feeds us) is smaller than a certain number of blocks.
1864
                // Note that the input best can have a smaller block height than the
1865
                // output, for example in case of reorg.
1866
0
                let is_near = tree[input_best].height.saturating_sub(
1867
0
                    tree.output_best_block_index()
1868
0
                        .map_or(finalized_block.height, |(idx, _)| tree[idx].height),
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0su_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0su_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0su_0B8_
1869
0
                ) <= 12;
1870
0
                let _ = result_tx.send(is_near);
1871
            }
1872
1873
            WakeUpReason::ToBackground(ToBackground::UnpinBlock {
1874
0
                result_tx,
1875
0
                subscription_id,
1876
0
                block_hash,
1877
0
            }) => {
1878
0
                // Foreground wants a block unpinned.
1879
0
1880
0
                log!(
1881
0
                    &background.platform,
1882
0
                    Trace,
1883
0
                    &background.log_target,
1884
0
                    "foreground-unpin-block",
1885
0
                    subscription_id = subscription_id.0,
1886
0
                    block_hash = HashDisplay(&block_hash)
1887
0
                );
1888
1889
                if let Tree::FinalizedBlockRuntimeKnown {
1890
0
                    all_blocks_subscriptions,
1891
0
                    pinned_blocks,
1892
                    ..
1893
0
                } = &mut background.tree
1894
                {
1895
0
                    let block_ignores_limit = match pinned_blocks
1896
0
                        .remove(&(subscription_id.0, block_hash))
1897
                    {
1898
0
                        Some(b) => b.block_ignores_limit,
1899
                        None => {
1900
                            // Cold path.Ã’
1901
0
                            if let Some((_, _)) = all_blocks_subscriptions.get(&subscription_id.0) {
1902
0
                                let _ = result_tx.send(Err(()));
1903
0
                            } else {
1904
0
                                let _ = result_tx.send(Ok(()));
1905
0
                            }
1906
0
                            continue;
1907
                        }
1908
                    };
1909
1910
0
                    background.runtimes.retain(|_, rt| rt.strong_count() > 0);
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sv_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sv_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sv_0B8_
1911
0
1912
0
                    if !block_ignores_limit {
1913
0
                        let (_, finalized_pinned_remaining) = all_blocks_subscriptions
1914
0
                            .get_mut(&subscription_id.0)
1915
0
                            .unwrap();
1916
0
                        *finalized_pinned_remaining += 1;
1917
0
                    }
1918
0
                }
1919
1920
0
                let _ = result_tx.send(Ok(()));
1921
            }
1922
1923
            WakeUpReason::ToBackground(ToBackground::PinPinnedBlockRuntime {
1924
0
                result_tx,
1925
0
                subscription_id,
1926
0
                block_hash,
1927
0
            }) => {
1928
0
                // Foreground wants to pin the runtime of a pinned block.
1929
0
1930
0
                log!(
1931
0
                    &background.platform,
1932
0
                    Trace,
1933
0
                    &background.log_target,
1934
0
                    "foreground-pin-pinned-block-runtime",
1935
0
                    subscription_id = subscription_id.0,
1936
0
                    block_hash = HashDisplay(&block_hash)
1937
0
                );
1938
1939
0
                let pinned_block = {
1940
                    if let Tree::FinalizedBlockRuntimeKnown {
1941
0
                        all_blocks_subscriptions,
1942
0
                        pinned_blocks,
1943
                        ..
1944
0
                    } = &mut background.tree
1945
                    {
1946
0
                        match pinned_blocks.get(&(subscription_id.0, block_hash)) {
1947
0
                            Some(v) => v.clone(),
1948
                            None => {
1949
                                // Cold path.
1950
0
                                if let Some((_, _)) =
1951
0
                                    all_blocks_subscriptions.get(&subscription_id.0)
1952
0
                                {
1953
0
                                    let _ = result_tx
1954
0
                                        .send(Err(PinPinnedBlockRuntimeError::BlockNotPinned));
1955
0
                                } else {
1956
0
                                    let _ = result_tx.send(Err(
1957
0
                                        PinPinnedBlockRuntimeError::ObsoleteSubscription,
1958
0
                                    ));
1959
0
                                }
1960
0
                                continue;
1961
                            }
1962
                        }
1963
                    } else {
1964
                        let _ =
1965
0
                            result_tx.send(Err(PinPinnedBlockRuntimeError::ObsoleteSubscription));
1966
0
                        continue;
1967
                    }
1968
                };
1969
1970
0
                let _ = result_tx.send(Ok((
1971
0
                    pinned_block.runtime.clone(),
1972
0
                    pinned_block.state_trie_root_hash,
1973
0
                    pinned_block.block_number,
1974
0
                )));
1975
            }
1976
1977
            WakeUpReason::ToBackground(ToBackground::RuntimeCall {
1978
0
                result_tx,
1979
0
                pinned_runtime,
1980
0
                block_hash,
1981
0
                block_number,
1982
0
                block_state_trie_root_hash,
1983
0
                function_name,
1984
0
                required_api_version,
1985
0
                parameters_vectored,
1986
0
                total_attempts,
1987
0
                timeout_per_request,
1988
0
                _max_parallel: _, // TODO: unused /!\
1989
0
            }) => {
1990
0
                // Foreground wants to perform a runtime call.
1991
0
1992
0
                log!(
1993
0
                    &background.platform,
1994
0
                    Debug,
1995
0
                    &background.log_target,
1996
0
                    "foreground-runtime-call-start",
1997
0
                    block_hash = HashDisplay(&block_hash),
1998
0
                    block_number,
1999
0
                    block_state_trie_root_hash = HashDisplay(&block_state_trie_root_hash),
2000
0
                    function_name,
2001
0
                    ?required_api_version,
2002
0
                    parameters_vectored = HashDisplay(&parameters_vectored),
2003
0
                    total_attempts,
2004
0
                    ?timeout_per_request
2005
0
                );
2006
2007
0
                let runtime = match &pinned_runtime.runtime {
2008
0
                    Ok(rt) => rt.clone(),
2009
0
                    Err(error) => {
2010
0
                        // The runtime call can't succeed because smoldot was incapable of
2011
0
                        // compiling the runtime.
2012
0
                        log!(
2013
0
                            &background.platform,
2014
0
                            Trace,
2015
0
                            &background.log_target,
2016
0
                            "foreground-runtime-call-abort",
2017
0
                            block_hash = HashDisplay(&block_hash),
2018
0
                            error = "invalid-runtime"
2019
0
                        );
2020
0
                        let _ =
2021
0
                            result_tx.send(Err(RuntimeCallError::InvalidRuntime(error.clone())));
2022
0
                        continue;
2023
                    }
2024
                };
2025
2026
0
                let api_version =
2027
0
                    if let Some((api_name, api_version_required)) = required_api_version {
2028
0
                        let api_version_if_fulfilled = runtime
2029
0
                            .runtime_version()
2030
0
                            .decode()
2031
0
                            .apis
2032
0
                            .find_version(&api_name)
2033
0
                            .filter(|api_version| api_version_required.contains(&api_version));
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sw_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sw_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sw_0B8_
2034
2035
0
                        let Some(api_version) = api_version_if_fulfilled else {
2036
                            // API version required by caller isn't fulfilled.
2037
0
                            log!(
2038
0
                                &background.platform,
2039
0
                                Trace,
2040
0
                                &background.log_target,
2041
0
                                "foreground-runtime-call-abort",
2042
0
                                block_hash = HashDisplay(&block_hash),
2043
0
                                error = "api-version-requirement-unfulfilled"
2044
0
                            );
2045
0
                            let _ = result_tx
2046
0
                                .send(Err(RuntimeCallError::ApiVersionRequirementUnfulfilled));
2047
0
                            continue;
2048
                        };
2049
2050
0
                        Some(api_version)
2051
                    } else {
2052
0
                        None
2053
                    };
2054
2055
0
                background
2056
0
                    .progress_runtime_call_requests
2057
0
                    .push(Box::pin(async move {
2058
0
                        ProgressRuntimeCallRequest::Initialize(RuntimeCallRequest {
2059
0
                            block_hash,
2060
0
                            block_number,
2061
0
                            block_state_trie_root_hash,
2062
0
                            function_name,
2063
0
                            api_version,
2064
0
                            parameters_vectored,
2065
0
                            runtime,
2066
0
                            total_attempts,
2067
0
                            timeout_per_request,
2068
0
                            inaccessible_errors: Vec::with_capacity(cmp::min(
2069
0
                                16,
2070
0
                                usize::try_from(total_attempts).unwrap_or(usize::MAX),
2071
0
                            )),
2072
0
                            result_tx,
2073
0
                        })
2074
0
                    }));
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sx_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sx_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sx_0B8_
2075
            }
2076
2077
0
            WakeUpReason::ProgressRuntimeCallRequest(progress) => {
2078
0
                let (mut operation, call_proof_and_sender) = match progress {
2079
0
                    ProgressRuntimeCallRequest::Initialize(operation) => (operation, None),
2080
                    ProgressRuntimeCallRequest::CallProofRequestDone {
2081
0
                        result: Ok(proof),
2082
0
                        call_proof_sender,
2083
0
                        operation,
2084
0
                    } => (operation, Some((proof, call_proof_sender))),
2085
                    ProgressRuntimeCallRequest::CallProofRequestDone {
2086
0
                        result: Err(error),
2087
0
                        mut operation,
2088
0
                        call_proof_sender,
2089
0
                    } => {
2090
0
                        log!(
2091
0
                            &background.platform,
2092
0
                            Trace,
2093
0
                            &background.log_target,
2094
0
                            "foreground-runtime-call-progress-fail",
2095
0
                            block_hash = HashDisplay(&operation.block_hash),
2096
0
                            function_name = operation.function_name,
2097
0
                            parameters_vectored = HashDisplay(&operation.parameters_vectored),
2098
0
                            remaining_attempts = usize::try_from(operation.total_attempts).unwrap()
2099
0
                                - operation.inaccessible_errors.len()
2100
0
                                - 1,
2101
0
                            ?error
2102
0
                        );
2103
0
                        operation
2104
0
                            .inaccessible_errors
2105
0
                            .push(RuntimeCallInaccessibleError::Network(error));
2106
0
                        background
2107
0
                            .network_service
2108
0
                            .ban_and_disconnect(
2109
0
                                call_proof_sender,
2110
0
                                network_service::BanSeverity::Low,
2111
0
                                "call-proof-request-failed",
2112
0
                            )
2113
0
                            .await;
2114
0
                        (operation, None)
2115
                    }
2116
                };
2117
2118
                // If the foreground is no longer interested in the result, abort now in order to
2119
                // save resources.
2120
0
                if operation.result_tx.is_canceled() {
2121
0
                    continue;
2122
0
                }
2123
2124
                // Process the call proof.
2125
0
                if let Some((call_proof, call_proof_sender)) = call_proof_and_sender {
2126
0
                    match runtime_call_single_attempt(
2127
0
                        &background.platform,
2128
0
                        operation.runtime.clone(),
2129
0
                        &operation.function_name,
2130
0
                        &operation.parameters_vectored,
2131
0
                        &operation.block_state_trie_root_hash,
2132
0
                        call_proof.decode(),
2133
0
                    )
2134
0
                    .await
2135
                    {
2136
0
                        (timing, Ok(output)) => {
2137
0
                            // Execution finished successfully.
2138
0
                            // This is the happy path.
2139
0
                            log!(
2140
0
                                &background.platform,
2141
0
                                Debug,
2142
0
                                &background.log_target,
2143
0
                                "foreground-runtime-call-success",
2144
0
                                block_hash = HashDisplay(&operation.block_hash),
2145
0
                                function_name = operation.function_name,
2146
0
                                parameters_vectored = HashDisplay(&operation.parameters_vectored),
2147
0
                                output = HashDisplay(&output),
2148
0
                                virtual_machine_call_duration = ?timing.virtual_machine_call_duration,
2149
0
                                proof_access_duration = ?timing.proof_access_duration,
2150
0
                            );
2151
0
                            let _ = operation.result_tx.send(Ok(RuntimeCallSuccess {
2152
0
                                output,
2153
0
                                api_version: operation.api_version,
2154
0
                            }));
2155
0
                            continue;
2156
                        }
2157
0
                        (timing, Err(SingleRuntimeCallAttemptError::Execution(error))) => {
2158
0
                            log!(
2159
0
                                &background.platform,
2160
0
                                Debug,
2161
0
                                &background.log_target,
2162
0
                                "foreground-runtime-call-fail",
2163
0
                                block_hash = HashDisplay(&operation.block_hash),
2164
0
                                function_name = operation.function_name,
2165
0
                                parameters_vectored = HashDisplay(&operation.parameters_vectored),
2166
0
                                ?error,
2167
0
                                virtual_machine_call_duration = ?timing.virtual_machine_call_duration,
2168
0
                                proof_access_duration = ?timing.proof_access_duration,
2169
0
                            );
2170
0
                            let _ = operation
2171
0
                                .result_tx
2172
0
                                .send(Err(RuntimeCallError::Execution(error)));
2173
0
                            continue;
2174
                        }
2175
0
                        (timing, Err(SingleRuntimeCallAttemptError::Inaccessible(error))) => {
2176
0
                            // This path is reached only if the call proof was invalid.
2177
0
                            log!(
2178
0
                                &background.platform,
2179
0
                                Debug,
2180
0
                                &background.log_target,
2181
0
                                "foreground-runtime-call-progress-invalid-call-proof",
2182
0
                                block_hash = HashDisplay(&operation.block_hash),
2183
0
                                function_name = operation.function_name,
2184
0
                                parameters_vectored = HashDisplay(&operation.parameters_vectored),
2185
0
                                remaining_attempts = usize::try_from(operation.total_attempts)
2186
0
                                    .unwrap()
2187
0
                                    - operation.inaccessible_errors.len()
2188
0
                                    - 1,
2189
0
                                ?error,
2190
0
                                virtual_machine_call_duration = ?timing.virtual_machine_call_duration,
2191
0
                                proof_access_duration = ?timing.proof_access_duration,
2192
0
                            );
2193
0
                            operation.inaccessible_errors.push(error);
2194
0
                            background
2195
0
                                .network_service
2196
0
                                .ban_and_disconnect(
2197
0
                                    call_proof_sender,
2198
0
                                    network_service::BanSeverity::High,
2199
0
                                    "invalid-call-proof",
2200
0
                                )
2201
0
                                .await;
2202
                        }
2203
                    }
2204
0
                }
2205
2206
                // If we have failed to obtain a valid proof several times, abort the runtime
2207
                // call attempt altogether.
2208
0
                if u32::try_from(operation.inaccessible_errors.len()).unwrap_or(u32::MAX)
2209
0
                    >= operation.total_attempts
2210
                {
2211
                    // No log line is printed here because one is already printed earlier.
2212
0
                    let _ = operation.result_tx.send(Err(RuntimeCallError::Inaccessible(
2213
0
                        operation.inaccessible_errors,
2214
0
                    )));
2215
0
                    continue;
2216
0
                }
2217
2218
                // This can be reached if the call proof was invalid or absent. We must start a
2219
                // new call proof request.
2220
2221
                // Choose peer to query.
2222
                // TODO: better peer selection
2223
                // TODO: can there be a race condition where the sync service forgets that a peer has knowledge of a block? shouldn't we somehow cache the peers that know this block ahead of time or something?
2224
0
                let Some(call_proof_target) = background
2225
0
                    .sync_service
2226
0
                    .peers_assumed_know_blocks(operation.block_number, &operation.block_hash)
2227
0
                    .await
2228
0
                    .choose(&mut rand_chacha::ChaCha20Rng::from_seed({
2229
0
                        // TODO: hacky
2230
0
                        let mut seed = [0; 32];
2231
0
                        background.platform.fill_random_bytes(&mut seed);
2232
0
                        seed
2233
0
                    }))
2234
                else {
2235
                    // No peer knows this block. Returning with a failure.
2236
0
                    log!(
2237
0
                        &background.platform,
2238
0
                        Debug,
2239
0
                        &background.log_target,
2240
0
                        "foreground-runtime-call-request-fail",
2241
0
                        block_hash = HashDisplay(&operation.block_hash),
2242
0
                        function_name = operation.function_name,
2243
0
                        parameters_vectored = HashDisplay(&operation.parameters_vectored),
2244
0
                        error = "no-peer-for-call-request"
2245
0
                    );
2246
0
                    let _ = operation.result_tx.send(Err(RuntimeCallError::Inaccessible(
2247
0
                        operation.inaccessible_errors,
2248
0
                    )));
2249
0
                    continue;
2250
                };
2251
2252
0
                log!(
2253
0
                    &background.platform,
2254
0
                    Trace,
2255
0
                    &background.log_target,
2256
0
                    "foreground-runtime-call-request-start",
2257
0
                    block_hash = HashDisplay(&operation.block_hash),
2258
0
                    function_name = operation.function_name,
2259
0
                    parameters_vectored = HashDisplay(&operation.parameters_vectored),
2260
0
                    call_proof_target,
2261
0
                );
2262
0
2263
0
                // Start the request.
2264
0
                background.progress_runtime_call_requests.push(Box::pin({
2265
0
                    let call_proof_request_future =
2266
0
                        background.network_service.clone().call_proof_request(
2267
0
                            call_proof_target.clone(),
2268
0
                            network_service::CallProofRequestConfig {
2269
0
                                block_hash: operation.block_hash,
2270
0
                                method: Cow::Owned(operation.function_name.clone()), // TODO: overhead
2271
0
                                parameter_vectored: iter::once(
2272
0
                                    operation.parameters_vectored.clone(),
2273
0
                                ), // TODO: overhead
2274
0
                            },
2275
0
                            operation.timeout_per_request,
2276
0
                        );
2277
0
2278
0
                    async move {
2279
0
                        let result = call_proof_request_future.await;
2280
0
                        ProgressRuntimeCallRequest::CallProofRequestDone {
2281
0
                            result,
2282
0
                            operation,
2283
0
                            call_proof_sender: call_proof_target,
2284
0
                        }
2285
0
                    }
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sy_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sy_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sy_0B8_
2286
0
                }));
2287
            }
2288
2289
0
            WakeUpReason::Notification(sync_service::Notification::Block(new_block)) => {
2290
0
                // Sync service has reported a new block.
2291
0
2292
0
                let same_runtime_as_parent = same_runtime_as_parent(
2293
0
                    &new_block.scale_encoded_header,
2294
0
                    background.sync_service.block_number_bytes(),
2295
0
                );
2296
0
2297
0
                if same_runtime_as_parent {
2298
0
                    log!(
2299
0
                        &background.platform,
2300
0
                        Trace,
2301
0
                        &background.log_target,
2302
0
                        "input-chain-new-block",
2303
0
                        block_hash = HashDisplay(&header::hash_from_scale_encoded_header(
2304
0
                            &new_block.scale_encoded_header
2305
0
                        )),
2306
0
                        parent_block_hash = HashDisplay(&new_block.parent_hash),
2307
0
                        is_new_best = new_block.is_new_best,
2308
0
                        same_runtime_as_parent = true
2309
0
                    );
2310
0
                } else {
2311
0
                    log!(
2312
0
                        &background.platform,
2313
0
                        Debug,
2314
0
                        &background.log_target,
2315
0
                        "input-chain-new-block-runtime-upgrade",
2316
0
                        block_hash = HashDisplay(&header::hash_from_scale_encoded_header(
2317
0
                            &new_block.scale_encoded_header
2318
0
                        )),
2319
0
                        parent_block_hash = HashDisplay(&new_block.parent_hash),
2320
0
                        is_new_best = new_block.is_new_best
2321
0
                    );
2322
0
                }
2323
2324
0
                match &mut background.tree {
2325
                    Tree::FinalizedBlockRuntimeKnown {
2326
0
                        tree,
2327
0
                        finalized_block,
2328
                        ..
2329
0
                    } => {
2330
0
                        let parent_index = if new_block.parent_hash == finalized_block.hash {
2331
0
                            None
2332
                        } else {
2333
0
                            Some(
2334
0
                                // TODO: O(n)
2335
0
                                tree.input_output_iter_unordered()
2336
0
                                    .find(|block| block.user_data.hash == new_block.parent_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sz_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sz_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sz_0B8_
2337
0
                                    .unwrap()
2338
0
                                    .id,
2339
0
                            )
2340
                        };
2341
2342
0
                        tree.input_insert_block(
2343
0
                            Block {
2344
0
                                hash: header::hash_from_scale_encoded_header(
2345
0
                                    &new_block.scale_encoded_header,
2346
0
                                ),
2347
0
                                height: header::decode(
2348
0
                                    &new_block.scale_encoded_header,
2349
0
                                    background.sync_service.block_number_bytes(),
2350
0
                                )
2351
0
                                .unwrap()
2352
0
                                .number, // TODO: consider feeding the information from the sync service?
2353
0
                                scale_encoded_header: new_block.scale_encoded_header,
2354
0
                            },
2355
0
                            parent_index,
2356
0
                            same_runtime_as_parent,
2357
0
                            new_block.is_new_best,
2358
0
                        );
2359
                    }
2360
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2361
0
                        // TODO: O(n)
2362
0
                        let parent_index = tree
2363
0
                            .input_output_iter_unordered()
2364
0
                            .find(|block| block.user_data.hash == new_block.parent_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sA_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sA_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sA_0B8_
2365
0
                            .unwrap()
2366
0
                            .id;
2367
0
                        tree.input_insert_block(
2368
0
                            Block {
2369
0
                                hash: header::hash_from_scale_encoded_header(
2370
0
                                    &new_block.scale_encoded_header,
2371
0
                                ),
2372
0
                                height: header::decode(
2373
0
                                    &new_block.scale_encoded_header,
2374
0
                                    background.sync_service.block_number_bytes(),
2375
0
                                )
2376
0
                                .unwrap()
2377
0
                                .number, // TODO: consider feeding the information from the sync service?
2378
0
                                scale_encoded_header: new_block.scale_encoded_header,
2379
0
                            },
2380
0
                            Some(parent_index),
2381
0
                            same_runtime_as_parent,
2382
0
                            new_block.is_new_best,
2383
0
                        );
2384
0
                    }
2385
                }
2386
            }
2387
2388
            WakeUpReason::Notification(sync_service::Notification::Finalized {
2389
0
                hash,
2390
0
                best_block_hash_if_changed,
2391
0
                ..
2392
0
            }) => {
2393
0
                // Sync service has reported a finalized block.
2394
0
2395
0
                log!(
2396
0
                    &background.platform,
2397
0
                    Trace,
2398
0
                    &background.log_target,
2399
0
                    "input-chain-finalized",
2400
0
                    block_hash = HashDisplay(&hash),
2401
0
                    best_block_hash = if let Some(best_block_hash) = best_block_hash_if_changed {
2402
0
                        Cow::Owned(HashDisplay(&best_block_hash).to_string())
2403
                    } else {
2404
0
                        Cow::Borrowed("<unchanged>")
2405
                    }
2406
                );
2407
2408
0
                if let Some(best_block_hash) = best_block_hash_if_changed {
2409
0
                    match &mut background.tree {
2410
0
                        Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
2411
0
                            let new_best_block = tree
2412
0
                                .input_output_iter_unordered()
2413
0
                                .find(|block| block.user_data.hash == best_block_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sB_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sB_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sB_0B8_
2414
0
                                .unwrap()
2415
0
                                .id;
2416
0
                            tree.input_set_best_block(Some(new_best_block));
2417
0
                        }
2418
0
                        Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2419
0
                            let new_best_block = tree
2420
0
                                .input_output_iter_unordered()
2421
0
                                .find(|block| block.user_data.hash == best_block_hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sC_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sC_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sC_0B8_
2422
0
                                .unwrap()
2423
0
                                .id;
2424
0
                            tree.input_set_best_block(Some(new_best_block));
2425
0
                        }
2426
                    }
2427
0
                }
2428
2429
0
                match &mut background.tree {
2430
                    Tree::FinalizedBlockRuntimeKnown {
2431
0
                        tree,
2432
0
                        finalized_block,
2433
0
                        ..
2434
0
                    } => {
2435
0
                        debug_assert_ne!(finalized_block.hash, hash);
2436
0
                        let node_to_finalize = tree
2437
0
                            .input_output_iter_unordered()
2438
0
                            .find(|block| block.user_data.hash == hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sD_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sD_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sD_0B8_
2439
0
                            .unwrap()
2440
0
                            .id;
2441
0
                        tree.input_finalize(node_to_finalize);
2442
                    }
2443
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2444
0
                        let node_to_finalize = tree
2445
0
                            .input_output_iter_unordered()
2446
0
                            .find(|block| block.user_data.hash == hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sE_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sE_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sE_0B8_
2447
0
                            .unwrap()
2448
0
                            .id;
2449
0
                        tree.input_finalize(node_to_finalize);
2450
0
                    }
2451
                }
2452
            }
2453
2454
0
            WakeUpReason::Notification(sync_service::Notification::BestBlockChanged { hash }) => {
2455
0
                // Sync service has reported a change in the best block.
2456
0
2457
0
                log!(
2458
0
                    &background.platform,
2459
0
                    Trace,
2460
0
                    &background.log_target,
2461
0
                    "input-chain-best-block-update",
2462
0
                    block_hash = HashDisplay(&hash)
2463
0
                );
2464
0
2465
0
                match &mut background.tree {
2466
                    Tree::FinalizedBlockRuntimeKnown {
2467
0
                        finalized_block,
2468
0
                        tree,
2469
                        ..
2470
0
                    } => {
2471
0
                        let idx = if hash == finalized_block.hash {
2472
0
                            None
2473
                        } else {
2474
0
                            Some(
2475
0
                                tree.input_output_iter_unordered()
2476
0
                                    .find(|block| block.user_data.hash == hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sF_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sF_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sF_0B8_
2477
0
                                    .unwrap()
2478
0
                                    .id,
2479
0
                            )
2480
                        };
2481
0
                        tree.input_set_best_block(idx);
2482
                    }
2483
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2484
0
                        let idx = tree
2485
0
                            .input_output_iter_unordered()
2486
0
                            .find(|block| block.user_data.hash == hash)
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sG_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sG_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sG_0B8_
2487
0
                            .unwrap()
2488
0
                            .id;
2489
0
                        tree.input_set_best_block(Some(idx));
2490
0
                    }
2491
                }
2492
            }
2493
2494
            WakeUpReason::RuntimeDownloadFinished(
2495
0
                async_op_id,
2496
0
                Ok((
2497
0
                    storage_code,
2498
0
                    storage_heap_pages,
2499
0
                    code_merkle_value,
2500
0
                    closest_ancestor_excluding,
2501
                )),
2502
            ) => {
2503
                // A runtime has successfully finished downloading.
2504
2505
0
                let concerned_blocks = match &background.tree {
2506
0
                    Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
2507
0
                        either::Left(tree.async_op_blocks(async_op_id))
2508
                    }
2509
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2510
0
                        either::Right(tree.async_op_blocks(async_op_id))
2511
                    }
2512
                }
2513
0
                .format_with(", ", |block, fmt| fmt(&HashDisplay(&block.hash)))
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sH_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sH_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sH_0B8_
2514
0
                .to_string();
2515
0
2516
0
                // Try to find an existing runtime identical to the one that has just been
2517
0
                // downloaded. This loop is `O(n)`, but given that we expect this list to very
2518
0
                // small (at most 1 or 2 elements), this is not a problem.
2519
0
                let existing_runtime = background
2520
0
                    .runtimes
2521
0
                    .iter()
2522
0
                    .filter_map(|(_, rt)| rt.upgrade())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sI_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sI_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sI_0B8_
2523
0
                    .find(|rt| {
2524
0
                        rt.runtime_code == storage_code && rt.heap_pages == storage_heap_pages
2525
0
                    });
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sJ_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sJ_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sJ_0B8_
2526
2527
                // If no identical runtime was found, try compiling the runtime.
2528
0
                let runtime = if let Some(existing_runtime) = existing_runtime {
2529
0
                    log!(
2530
0
                        &background.platform,
2531
0
                        Debug,
2532
0
                        &background.log_target,
2533
0
                        "runtime-download-finish-compilation-cache-hit",
2534
0
                        block_hashes = concerned_blocks,
2535
0
                    );
2536
0
                    existing_runtime
2537
                } else {
2538
0
                    let before_compilation = background.platform.now();
2539
0
                    let runtime = compile_runtime(
2540
0
                        &background.platform,
2541
0
                        &background.log_target,
2542
0
                        &storage_code,
2543
0
                        &storage_heap_pages,
2544
0
                    );
2545
0
                    let compilation_duration = background.platform.now() - before_compilation;
2546
0
                    log!(
2547
0
                        &background.platform,
2548
0
                        Debug,
2549
0
                        &background.log_target,
2550
0
                        "runtime-download-finish-compilation-cache-miss",
2551
0
                        ?compilation_duration,
2552
0
                        compilation_success = runtime.is_ok(),
2553
0
                        block_hashes = concerned_blocks,
2554
0
                    );
2555
0
                    match &runtime {
2556
0
                        Ok(runtime) => {
2557
0
                            log!(
2558
0
                                &background.platform,
2559
0
                                Info,
2560
0
                                &background.log_target,
2561
0
                                format!(
2562
0
                                    "Successfully compiled runtime. Spec version: {}. \
2563
0
                                    Size of `:code`: {}.",
2564
0
                                    runtime.runtime_version().decode().spec_version,
2565
0
                                    BytesDisplay(
2566
0
                                        u64::try_from(storage_code.as_ref().map_or(0, |v| v.len()))
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sN_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sN_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sN_0B8_
2567
0
                                            .unwrap()
2568
0
                                    )
2569
0
                                )
2570
0
                            );
2571
0
                        }
2572
0
                        Err(error) => {
2573
0
                            log!(
2574
0
                                &background.platform,
2575
0
                                Warn,
2576
0
                                &background.log_target,
2577
0
                                format!(
2578
0
                                    "Failed to compile runtime. Size of `:code`: {}.\nError: {}\n\
2579
0
                                    This indicates an incompatibility between smoldot and \
2580
0
                                    the chain.",
2581
0
                                    BytesDisplay(
2582
0
                                        u64::try_from(storage_code.as_ref().map_or(0, |v| v.len()))
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sO_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sO_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sO_0B8_
2583
0
                                            .unwrap()
2584
0
                                    ),
2585
0
                                    error
2586
0
                                )
2587
0
                            );
2588
0
                        }
2589
                    }
2590
2591
0
                    let runtime = Arc::new(Runtime {
2592
0
                        heap_pages: storage_heap_pages,
2593
0
                        runtime_code: storage_code,
2594
0
                        runtime,
2595
0
                        code_merkle_value,
2596
0
                        closest_ancestor_excluding,
2597
0
                    });
2598
0
2599
0
                    background.runtimes.insert(Arc::downgrade(&runtime));
2600
0
                    runtime
2601
                };
2602
2603
                // Insert the runtime into the tree.
2604
0
                match &mut background.tree {
2605
0
                    Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
2606
0
                        tree.async_op_finished(async_op_id, runtime);
2607
0
                    }
2608
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2609
0
                        tree.async_op_finished(async_op_id, Some(runtime));
2610
0
                    }
2611
                }
2612
            }
2613
2614
0
            WakeUpReason::RuntimeDownloadFinished(async_op_id, Err(error)) => {
2615
                // A runtime download has failed.
2616
2617
0
                let concerned_blocks = match &background.tree {
2618
0
                    Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
2619
0
                        either::Left(tree.async_op_blocks(async_op_id))
2620
                    }
2621
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2622
0
                        either::Right(tree.async_op_blocks(async_op_id))
2623
                    }
2624
                }
2625
0
                .format_with(", ", |block, fmt| fmt(&HashDisplay(&block.hash)))
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0sK_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0sK_0B1c_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0sK_0B8_
2626
0
                .to_string();
2627
0
2628
0
                log!(
2629
0
                    &background.platform,
2630
0
                    Debug,
2631
0
                    &background.log_target,
2632
0
                    "runtime-download-error",
2633
0
                    block_hashes = concerned_blocks,
2634
0
                    ?error
2635
0
                );
2636
0
                if !error.is_network_problem() {
2637
0
                    log!(
2638
0
                        &background.platform,
2639
0
                        Warn,
2640
0
                        &background.log_target,
2641
0
                        format!(
2642
0
                            "Failed to download :code and :heappages of blocks {}: {}",
2643
0
                            concerned_blocks, error
2644
0
                        )
2645
0
                    );
2646
0
                }
2647
2648
0
                match &mut background.tree {
2649
0
                    Tree::FinalizedBlockRuntimeKnown { tree, .. } => {
2650
0
                        tree.async_op_failure(async_op_id, &background.platform.now());
2651
0
                    }
2652
0
                    Tree::FinalizedBlockRuntimeUnknown { tree, .. } => {
2653
0
                        tree.async_op_failure(async_op_id, &background.platform.now());
2654
0
                    }
2655
                }
2656
            }
2657
        }
2658
    }
2659
0
}
Unexecuted instantiation: _RNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service14run_backgroundpE0B6_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0B1a_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service14run_backgroundpE0B6_
2660
2661
0
#[derive(Debug, Clone, derive_more::Display)]
Unexecuted instantiation: _RNvXsG_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_20RuntimeDownloadErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsG_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_20RuntimeDownloadErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
2662
enum RuntimeDownloadError {
2663
    #[display(fmt = "{_0}")]
2664
    StorageQuery(sync_service::StorageQueryError),
2665
    #[display(fmt = "Couldn't decode header: {_0}")]
2666
    InvalidHeader(header::Error),
2667
}
2668
2669
impl RuntimeDownloadError {
2670
    /// Returns `true` if this is caused by networking issues, as opposed to a consensus-related
2671
    /// issue.
2672
0
    fn is_network_problem(&self) -> bool {
2673
0
        match self {
2674
0
            RuntimeDownloadError::StorageQuery(err) => err.is_network_problem(),
2675
0
            RuntimeDownloadError::InvalidHeader(_) => false,
2676
        }
2677
0
    }
Unexecuted instantiation: _RNvMs0_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_20RuntimeDownloadError18is_network_problem
Unexecuted instantiation: _RNvMs0_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_20RuntimeDownloadError18is_network_problem
2678
}
2679
2680
struct Background<TPlat: PlatformRef> {
2681
    /// Target to use for all the logs of this service.
2682
    log_target: String,
2683
2684
    /// See [`Config::platform`].
2685
    platform: TPlat,
2686
2687
    /// See [`Config::sync_service`].
2688
    sync_service: Arc<sync_service::SyncService<TPlat>>,
2689
2690
    /// See [`Config::network_service`].
2691
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
2692
2693
    /// Receiver for messages to the background task.
2694
    to_background: Pin<Box<async_channel::Receiver<ToBackground<TPlat>>>>,
2695
2696
    /// Sending side of [`Background::to_background`].
2697
    to_background_tx: async_channel::WeakSender<ToBackground<TPlat>>,
2698
2699
    /// Identifier of the next subscription for
2700
    /// [`Tree::FinalizedBlockRuntimeKnown::all_blocks_subscriptions`].
2701
    ///
2702
    /// To avoid race conditions, subscription IDs are never used, even if we switch back to
2703
    /// [`Tree::FinalizedBlockRuntimeUnknown`].
2704
    next_subscription_id: u64,
2705
2706
    /// List of runtimes referenced by the tree in [`Tree`] and by
2707
    /// [`Tree::FinalizedBlockRuntimeKnown::pinned_blocks`].
2708
    ///
2709
    /// Might contains obsolete values (i.e. stale `Weak`s) and thus must be cleaned from time to
2710
    /// time.
2711
    ///
2712
    /// Because this list shouldn't contain many entries, it is acceptable to iterate over all
2713
    /// the elements.
2714
    runtimes: slab::Slab<Weak<Runtime>>,
2715
2716
    /// Tree of blocks received from the sync service. Keeps track of which block has been
2717
    /// reported to the outer API.
2718
    tree: Tree<TPlat>,
2719
2720
    /// List of subscription attempts started with
2721
    /// [`Tree::FinalizedBlockRuntimeKnown::all_blocks_subscriptions`].
2722
    ///
2723
    /// When in the [`Tree::FinalizedBlockRuntimeKnown`] state, a [`SubscribeAll`] is constructed
2724
    /// and sent back for each of these senders.
2725
    /// When in the [`Tree::FinalizedBlockRuntimeUnknown`] state, the senders patiently wait here.
2726
    pending_subscriptions: VecDeque<ToBackgroundSubscribeAll<TPlat>>,
2727
2728
    /// Stream of notifications coming from the sync service. `None` if not subscribed yet.
2729
    blocks_stream: Option<Pin<Box<dyn Stream<Item = sync_service::Notification> + Send>>>,
2730
2731
    /// List of runtimes currently being downloaded from the network.
2732
    /// For each item, the download id, storage value of `:code`, storage value of `:heappages`,
2733
    /// and Merkle value and closest ancestor of `:code`.
2734
    // TODO: use struct
2735
    runtime_downloads: stream::FuturesUnordered<
2736
        future::BoxFuture<
2737
            'static,
2738
            (
2739
                async_tree::AsyncOpId,
2740
                Result<
2741
                    (
2742
                        Option<Vec<u8>>,
2743
                        Option<Vec<u8>>,
2744
                        Option<Vec<u8>>,
2745
                        Option<Vec<Nibble>>,
2746
                    ),
2747
                    RuntimeDownloadError,
2748
                >,
2749
            ),
2750
        >,
2751
    >,
2752
2753
    /// List of actions to perform to progress runtime calls requested by the frontend.
2754
    progress_runtime_call_requests:
2755
        stream::FuturesUnordered<future::BoxFuture<'static, ProgressRuntimeCallRequest>>,
2756
}
2757
2758
enum Tree<TPlat: PlatformRef> {
2759
    FinalizedBlockRuntimeKnown {
2760
        /// Tree of blocks. Holds the state of the download of everything. Always `Some` when the
2761
        /// `Mutex` is being locked. Temporarily switched to `None` during some operations.
2762
        ///
2763
        /// The asynchronous operation user data is a `usize` corresponding to the index within
2764
        /// [`Background::runtimes`].
2765
        tree: async_tree::AsyncTree<TPlat::Instant, Block, Arc<Runtime>>,
2766
2767
        /// Finalized block. Outside of the tree.
2768
        finalized_block: Block,
2769
2770
        /// List of senders that get notified when new blocks arrive.
2771
        /// See [`RuntimeService::subscribe_all`]. Alongside with each sender, the number of pinned
2772
        /// finalized or non-canonical blocks remaining for this subscription.
2773
        ///
2774
        /// Keys are assigned from [`Background::next_subscription_id`].
2775
        all_blocks_subscriptions: hashbrown::HashMap<
2776
            u64,
2777
            (async_channel::Sender<Notification>, usize),
2778
            fnv::FnvBuildHasher,
2779
        >,
2780
2781
        /// List of pinned blocks.
2782
        ///
2783
        /// Every time a block is reported to the API user, it is inserted in this map. The block
2784
        /// is inserted after it has been pushed in the channel, but before it is pulled.
2785
        /// Therefore, if the channel is closed it is the background that needs to purge all
2786
        /// blocks from this container that are no longer relevant.
2787
        ///
2788
        /// Keys are `(subscription_id, block_hash)`. Values are indices within
2789
        /// [`Background::runtimes`], state trie root hashes, block numbers, and whether the block
2790
        /// is non-finalized and part of the canonical chain.
2791
        pinned_blocks: BTreeMap<(u64, [u8; 32]), PinnedBlock>,
2792
    },
2793
    FinalizedBlockRuntimeUnknown {
2794
        /// Tree of blocks. Holds the state of the download of everything. Always `Some` when the
2795
        /// `Mutex` is being locked. Temporarily switched to `None` during some operations.
2796
        ///
2797
        /// The finalized block according to the [`async_tree::AsyncTree`] is actually a dummy.
2798
        /// The "real" finalized block is a non-finalized block within this tree.
2799
        ///
2800
        /// The asynchronous operation user data is a `usize` corresponding to the index within
2801
        /// [`Background::runtimes`]. The asynchronous operation user data is `None` for the dummy
2802
        /// finalized block.
2803
        // TODO: explain better
2804
        tree: async_tree::AsyncTree<TPlat::Instant, Block, Option<Arc<Runtime>>>,
2805
    },
2806
}
2807
2808
/// See [`Background::progress_runtime_call_requests`].
2809
enum ProgressRuntimeCallRequest {
2810
    /// Must start the first call proof request.
2811
    Initialize(RuntimeCallRequest),
2812
    /// A call proof request has finished and the runtime call can be advanced.
2813
    CallProofRequestDone {
2814
        /// Outcome of the latest call proof request.
2815
        result: Result<network_service::EncodedMerkleProof, network_service::CallProofRequestError>,
2816
        /// Identity of the peer the call proof request was made against.
2817
        call_proof_sender: network_service::PeerId,
2818
        operation: RuntimeCallRequest,
2819
    },
2820
}
2821
2822
/// See [`ProgressRuntimeCallRequest`].
2823
struct RuntimeCallRequest {
2824
    block_hash: [u8; 32],
2825
    block_number: u64,
2826
    block_state_trie_root_hash: [u8; 32],
2827
    function_name: String,
2828
    /// Version of the API that was found. `Some` if and only if an API requirement was passed.
2829
    api_version: Option<u32>,
2830
    parameters_vectored: Vec<u8>,
2831
    runtime: executor::host::HostVmPrototype,
2832
    total_attempts: u32,
2833
    timeout_per_request: Duration,
2834
    inaccessible_errors: Vec<RuntimeCallInaccessibleError>,
2835
    result_tx: oneshot::Sender<Result<RuntimeCallSuccess, RuntimeCallError>>,
2836
}
2837
2838
struct Runtime {
2839
    /// Successfully-compiled runtime and all its information. Can contain an error if an error
2840
    /// happened, including a problem when obtaining the runtime specs.
2841
    runtime: Result<executor::host::HostVmPrototype, RuntimeError>,
2842
2843
    /// Merkle value of the `:code` trie node.
2844
    ///
2845
    /// Can be `None` if the storage is empty, in which case the runtime will have failed to
2846
    /// build.
2847
    code_merkle_value: Option<Vec<u8>>,
2848
2849
    /// Closest ancestor of the `:code` key except for `:code` itself.
2850
    closest_ancestor_excluding: Option<Vec<Nibble>>,
2851
2852
    /// Undecoded storage value of `:code` corresponding to the [`Runtime::runtime`]
2853
    /// field.
2854
    ///
2855
    /// Can be `None` if the storage is empty, in which case the runtime will have failed to
2856
    /// build.
2857
    // TODO: consider storing hash instead
2858
    runtime_code: Option<Vec<u8>>,
2859
2860
    /// Undecoded storage value of `:heappages` corresponding to the
2861
    /// [`Runtime::runtime`] field.
2862
    ///
2863
    /// Can be `None` if the storage is empty, in which case the runtime will have failed to
2864
    /// build.
2865
    // TODO: consider storing hash instead
2866
    heap_pages: Option<Vec<u8>>,
2867
}
2868
2869
0
fn compile_runtime<TPlat: PlatformRef>(
2870
0
    platform: &TPlat,
2871
0
    log_target: &str,
2872
0
    code: &Option<Vec<u8>>,
2873
0
    heap_pages: &Option<Vec<u8>>,
2874
0
) -> Result<executor::host::HostVmPrototype, RuntimeError> {
2875
    // Parameters for `HostVmPrototype::new`.
2876
0
    let module = code.as_ref().ok_or(RuntimeError::CodeNotFound)?;
2877
0
    let heap_pages = executor::storage_heap_pages_to_value(heap_pages.as_deref())
2878
0
        .map_err(RuntimeError::InvalidHeapPages)?;
2879
0
    let exec_hint = executor::vm::ExecHint::CompileWithNonDeterministicValidation;
2880
0
2881
0
    // We try once with `allow_unresolved_imports: false`. If this fails due to unresolved
2882
0
    // import, we try again but with `allowed_unresolved_imports: true`.
2883
0
    // Having unresolved imports might cause errors later on, for example when validating
2884
0
    // transactions or getting the parachain heads, but for now we continue the execution
2885
0
    // and print a warning.
2886
0
    match executor::host::HostVmPrototype::new(executor::host::Config {
2887
0
        module,
2888
0
        heap_pages,
2889
0
        exec_hint,
2890
0
        allow_unresolved_imports: false,
2891
0
    }) {
2892
0
        Ok(vm) => return Ok(vm),
2893
        Err(executor::host::NewErr::VirtualMachine(
2894
            executor::vm::NewErr::UnresolvedFunctionImport {
2895
0
                function,
2896
0
                module_name,
2897
0
            },
2898
0
        )) => {
2899
0
            match executor::host::HostVmPrototype::new(executor::host::Config {
2900
0
                module,
2901
0
                heap_pages,
2902
0
                exec_hint,
2903
0
                allow_unresolved_imports: true,
2904
0
            }) {
2905
0
                Ok(vm) => {
2906
0
                    log!(
2907
0
                        platform,
2908
0
                        Warn,
2909
0
                        log_target,
2910
0
                        format!(
2911
0
                            "Unresolved host function in runtime: `{}`:`{}`. Smoldot might \
2912
0
                            encounter errors later on. Please report this issue in \
2913
0
                            https://github.com/smol-dot/smoldot",
2914
0
                            module_name, function
2915
0
                        )
2916
0
                    );
2917
0
2918
0
                    Ok(vm)
2919
                }
2920
                Err(executor::host::NewErr::VirtualMachine(
2921
                    executor::vm::NewErr::UnresolvedFunctionImport { .. },
2922
0
                )) => unreachable!(),
2923
0
                Err(error) => {
2924
0
                    // It's still possible that errors other than an unresolved host
2925
0
                    // function happen.
2926
0
                    Err(RuntimeError::Build(error))
2927
                }
2928
            }
2929
        }
2930
0
        Err(error) => Err(RuntimeError::Build(error)),
2931
    }
2932
0
}
Unexecuted instantiation: _RINvNtCsiGub1lfKphe_13smoldot_light15runtime_service15compile_runtimepEB4_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service15compile_runtimeNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefEB19_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service15compile_runtimepEB4_
2933
2934
/// Returns `true` if the block can be assumed to have the same runtime as its parent.
2935
0
fn same_runtime_as_parent(header: &[u8], block_number_bytes: usize) -> bool {
2936
0
    match header::decode(header, block_number_bytes) {
2937
0
        Ok(h) => !h.digest.has_runtime_environment_updated(),
2938
0
        Err(_) => false,
2939
    }
2940
0
}
Unexecuted instantiation: _RNvNtCsiGub1lfKphe_13smoldot_light15runtime_service22same_runtime_as_parent
Unexecuted instantiation: _RNvNtCsih6EgvAwZF2_13smoldot_light15runtime_service22same_runtime_as_parent
2941
2942
0
fn download_runtime<TPlat: PlatformRef>(
2943
0
    sync_service: Arc<sync_service::SyncService<TPlat>>,
2944
0
    block_hash: [u8; 32],
2945
0
    scale_encoded_header: &[u8],
2946
0
) -> impl future::Future<
2947
0
    Output = Result<
2948
0
        (
2949
0
            Option<Vec<u8>>,
2950
0
            Option<Vec<u8>>,
2951
0
            Option<Vec<u8>>,
2952
0
            Option<Vec<Nibble>>,
2953
0
        ),
2954
0
        RuntimeDownloadError,
2955
0
    >,
2956
0
> {
2957
    // In order to perform the download, we need to known the state root hash of the
2958
    // block in question, which requires decoding the block. If the decoding fails,
2959
    // we report that the asynchronous operation has failed with the hope that this
2960
    // block gets pruned in the future.
2961
0
    let block_info = match header::decode(scale_encoded_header, sync_service.block_number_bytes()) {
2962
0
        Ok(decoded_header) => Ok((*decoded_header.state_root, decoded_header.number)),
2963
0
        Err(error) => Err(RuntimeDownloadError::InvalidHeader(error)),
2964
    };
2965
2966
0
    async move {
2967
0
        let (state_root, block_number) = block_info?;
2968
2969
0
        let mut storage_code = None;
2970
0
        let mut storage_heap_pages = None;
2971
0
        let mut code_merkle_value = None;
2972
0
        let mut code_closest_ancestor_excluding = None;
2973
2974
0
        let mut query = sync_service
2975
0
            .clone()
2976
0
            .storage_query(
2977
0
                block_number,
2978
0
                block_hash,
2979
0
                state_root,
2980
0
                [
2981
0
                    sync_service::StorageRequestItem {
2982
0
                        key: b":code".to_vec(),
2983
0
                        ty: sync_service::StorageRequestItemTy::ClosestDescendantMerkleValue,
2984
0
                    },
2985
0
                    sync_service::StorageRequestItem {
2986
0
                        key: b":code".to_vec(),
2987
0
                        ty: sync_service::StorageRequestItemTy::Value,
2988
0
                    },
2989
0
                    sync_service::StorageRequestItem {
2990
0
                        key: b":heappages".to_vec(),
2991
0
                        ty: sync_service::StorageRequestItemTy::Value,
2992
0
                    },
2993
0
                ]
2994
0
                .into_iter(),
2995
0
                3,
2996
0
                Duration::from_secs(20),
2997
0
                NonZeroU32::new(3).unwrap(),
2998
0
            )
2999
0
            .advance()
3000
0
            .await;
3001
3002
        loop {
3003
0
            match query {
3004
                sync_service::StorageQueryProgress::Finished => {
3005
0
                    break Ok((
3006
0
                        storage_code,
3007
0
                        storage_heap_pages,
3008
0
                        code_merkle_value,
3009
0
                        code_closest_ancestor_excluding,
3010
0
                    ))
3011
                }
3012
                sync_service::StorageQueryProgress::Progress {
3013
                    request_index: 0,
3014
                    item:
3015
                        sync_service::StorageResultItem::ClosestDescendantMerkleValue {
3016
0
                            closest_descendant_merkle_value,
3017
0
                            found_closest_ancestor_excluding,
3018
0
                            ..
3019
0
                        },
3020
0
                    query: next,
3021
0
                } => {
3022
0
                    code_merkle_value = closest_descendant_merkle_value;
3023
0
                    code_closest_ancestor_excluding = found_closest_ancestor_excluding;
3024
0
                    query = next.advance().await;
3025
                }
3026
                sync_service::StorageQueryProgress::Progress {
3027
                    request_index: 1,
3028
0
                    item: sync_service::StorageResultItem::Value { value, .. },
3029
0
                    query: next,
3030
0
                } => {
3031
0
                    storage_code = value;
3032
0
                    query = next.advance().await;
3033
                }
3034
                sync_service::StorageQueryProgress::Progress {
3035
                    request_index: 2,
3036
0
                    item: sync_service::StorageResultItem::Value { value, .. },
3037
0
                    query: next,
3038
0
                } => {
3039
0
                    storage_heap_pages = value;
3040
0
                    query = next.advance().await;
3041
                }
3042
0
                sync_service::StorageQueryProgress::Progress { .. } => unreachable!(),
3043
0
                sync_service::StorageQueryProgress::Error(error) => {
3044
0
                    break Err(RuntimeDownloadError::StorageQuery(error))
3045
                }
3046
            }
3047
        }
3048
0
    }
Unexecuted instantiation: _RNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service16download_runtimepE0B6_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service16download_runtimeNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0B1c_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service16download_runtimepE0B6_
3049
0
}
Unexecuted instantiation: _RINvNtCsiGub1lfKphe_13smoldot_light15runtime_service16download_runtimepEB4_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service16download_runtimeNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefEB1a_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service16download_runtimepEB4_
3050
3051
/// Tries to perform a runtime call using the given call proof.
3052
///
3053
/// This function can have three possible outcomes: success, failure because the call proof is
3054
/// invalid/incomplete, or failure because the execution fails.
3055
///
3056
/// This function is async in order to periodically yield during the execution.
3057
0
async fn runtime_call_single_attempt<TPlat: PlatformRef>(
3058
0
    platform: &TPlat,
3059
0
    runtime: executor::host::HostVmPrototype,
3060
0
    function_name: &str,
3061
0
    parameters_vectored: &[u8],
3062
0
    block_state_trie_root_hash: &[u8; 32],
3063
0
    call_proof: &[u8],
3064
0
) -> (
3065
0
    SingleRuntimeCallTiming,
3066
0
    Result<Vec<u8>, SingleRuntimeCallAttemptError>,
3067
0
) {
Unexecuted instantiation: _RINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpEB4_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefEB1l_
Unexecuted instantiation: _RINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpEB4_
3068
0
    // Try to decode the proof. Succeed just means that the proof has the correct
3069
0
    // encoding, and doesn't guarantee that the proof has all the necessary
3070
0
    // entries.
3071
0
    let call_proof = trie::proof_decode::decode_and_verify_proof(trie::proof_decode::Config {
3072
0
        proof: call_proof,
3073
0
    });
3074
0
3075
0
    // Keep track of the total time taken by the runtime call attempt.
3076
0
    let mut timing = SingleRuntimeCallTiming {
3077
0
        virtual_machine_call_duration: Duration::new(0, 0),
3078
0
        proof_access_duration: Duration::new(0, 0),
3079
0
    };
3080
0
3081
0
    // Attempt the runtime call.
3082
0
    // If the call succeed, we interrupt the flow and `continue`.
3083
0
    let runtime_call_duration_before = platform.now();
3084
0
    let mut call = match executor::runtime_call::run(executor::runtime_call::Config {
3085
0
        virtual_machine: runtime,
3086
0
        function_to_call: function_name,
3087
0
        parameter: iter::once(parameters_vectored),
3088
0
        storage_proof_size_behavior:
3089
0
            executor::runtime_call::StorageProofSizeBehavior::proof_recording_disabled(),
3090
0
        storage_main_trie_changes: Default::default(),
3091
0
        max_log_level: 0,
3092
0
        calculate_trie_changes: false,
3093
0
    }) {
3094
0
        Ok(call) => call,
3095
0
        Err((error, _)) => {
3096
0
            // If starting the execution triggers an error, then the runtime call cannot
3097
0
            // possibly succeed.
3098
0
            // This can happen for example because the requested function doesn't exist.
3099
0
            return (
3100
0
                timing,
3101
0
                Err(SingleRuntimeCallAttemptError::Execution(
3102
0
                    RuntimeCallExecutionError::Start(error),
3103
0
                )),
3104
0
            );
3105
        }
3106
    };
3107
0
    timing.virtual_machine_call_duration += platform.now() - runtime_call_duration_before;
3108
3109
    loop {
3110
0
        let call_proof = match &call_proof {
3111
0
            Ok(p) => p,
3112
0
            Err(error) => {
3113
0
                return (
3114
0
                    timing,
3115
0
                    Err(SingleRuntimeCallAttemptError::Inaccessible(
3116
0
                        RuntimeCallInaccessibleError::InvalidCallProof(error.clone()),
3117
0
                    )),
3118
0
                );
3119
            }
3120
        };
3121
3122
        // Yield once at every iteration. This avoids monopolizing the CPU for
3123
        // too long.
3124
0
        futures_lite::future::yield_now().await;
3125
3126
0
        let child_trie = match call {
3127
0
            executor::runtime_call::RuntimeCall::Finished(Ok(finished)) => {
3128
0
                // Execution finished successfully.
3129
0
                // This is the happy path.
3130
0
                let output = finished.virtual_machine.value().as_ref().to_owned();
3131
0
                return (timing, Ok(output));
3132
            }
3133
0
            executor::runtime_call::RuntimeCall::Finished(Err(error)) => {
3134
0
                // Execution finished with an error.
3135
0
                return (
3136
0
                    timing,
3137
0
                    Err(SingleRuntimeCallAttemptError::Execution(
3138
0
                        RuntimeCallExecutionError::Execution(error.detail),
3139
0
                    )),
3140
0
                );
3141
            }
3142
0
            executor::runtime_call::RuntimeCall::StorageGet(ref get) => {
3143
0
                get.child_trie().map(|c| c.as_ref().to_owned()) // TODO: overhead
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpE00B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE00B1p_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpE00B8_
3144
            }
3145
0
            executor::runtime_call::RuntimeCall::ClosestDescendantMerkleValue(ref mv) => {
3146
0
                mv.child_trie().map(|c| c.as_ref().to_owned())
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s_0B1p_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s_0B8_
3147
            } // TODO: overhead
3148
0
            executor::runtime_call::RuntimeCall::NextKey(ref nk) => {
3149
0
                nk.child_trie().map(|c| c.as_ref().to_owned()) // TODO: overhead
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s0_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s0_0B1p_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s0_0B8_
3150
            }
3151
0
            executor::runtime_call::RuntimeCall::SignatureVerification(r) => {
3152
0
                let runtime_call_duration_before = platform.now();
3153
0
                call = r.verify_and_resume();
3154
0
                timing.virtual_machine_call_duration +=
3155
0
                    platform.now() - runtime_call_duration_before;
3156
0
                continue;
3157
            }
3158
0
            executor::runtime_call::RuntimeCall::LogEmit(r) => {
3159
0
                // Logs are ignored.
3160
0
                let runtime_call_duration_before = platform.now();
3161
0
                call = r.resume();
3162
0
                timing.virtual_machine_call_duration +=
3163
0
                    platform.now() - runtime_call_duration_before;
3164
0
                continue;
3165
            }
3166
            executor::runtime_call::RuntimeCall::Offchain(_) => {
3167
                // Forbidden host function called.
3168
0
                return (
3169
0
                    timing,
3170
0
                    Err(SingleRuntimeCallAttemptError::Execution(
3171
0
                        RuntimeCallExecutionError::ForbiddenHostFunction,
3172
0
                    )),
3173
0
                );
3174
            }
3175
0
            executor::runtime_call::RuntimeCall::OffchainStorageSet(r) => {
3176
0
                // Ignore offchain storage writes.
3177
0
                let runtime_call_duration_before = platform.now();
3178
0
                call = r.resume();
3179
0
                timing.virtual_machine_call_duration +=
3180
0
                    platform.now() - runtime_call_duration_before;
3181
0
                continue;
3182
            }
3183
        };
3184
3185
0
        let proof_access_duration_before = platform.now();
3186
0
        let trie_root = if let Some(child_trie) = child_trie {
3187
            // TODO: allocation here, but probably not problematic
3188
            const PREFIX: &[u8] = b":child_storage:default:";
3189
0
            let mut key = Vec::with_capacity(PREFIX.len() + child_trie.len());
3190
0
            key.extend_from_slice(PREFIX);
3191
0
            key.extend_from_slice(child_trie.as_ref());
3192
0
            match call_proof.storage_value(&block_state_trie_root_hash, &key) {
3193
                Err(_) => {
3194
0
                    return (
3195
0
                        timing,
3196
0
                        Err(SingleRuntimeCallAttemptError::Inaccessible(
3197
0
                            RuntimeCallInaccessibleError::MissingProofEntry,
3198
0
                        )),
3199
0
                    )
3200
                }
3201
0
                Ok(None) => None,
3202
0
                Ok(Some((value, _))) => match <&[u8; 32]>::try_from(value) {
3203
0
                    Ok(hash) => Some(hash),
3204
                    Err(_) => {
3205
0
                        return (
3206
0
                            timing,
3207
0
                            Err(SingleRuntimeCallAttemptError::Inaccessible(
3208
0
                                RuntimeCallInaccessibleError::MissingProofEntry,
3209
0
                            )),
3210
0
                        )
3211
                    }
3212
                },
3213
            }
3214
        } else {
3215
0
            Some(block_state_trie_root_hash)
3216
        };
3217
3218
0
        match call {
3219
0
            executor::runtime_call::RuntimeCall::StorageGet(get) => {
3220
0
                let storage_value = if let Some(trie_root) = trie_root {
3221
0
                    call_proof.storage_value(&trie_root, get.key().as_ref())
3222
                } else {
3223
0
                    Ok(None)
3224
                };
3225
0
                let Ok(storage_value) = storage_value else {
3226
0
                    return (
3227
0
                        timing,
3228
0
                        Err(SingleRuntimeCallAttemptError::Inaccessible(
3229
0
                            RuntimeCallInaccessibleError::MissingProofEntry,
3230
0
                        )),
3231
0
                    );
3232
                };
3233
0
                timing.proof_access_duration += platform.now() - proof_access_duration_before;
3234
0
3235
0
                let runtime_call_duration_before = platform.now();
3236
0
                call = get.inject_value(storage_value.map(|(val, vers)| (iter::once(val), vers)));
Unexecuted instantiation: _RNCNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s1_0B8_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0s1_0B1p_
Unexecuted instantiation: _RNCNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpE0s1_0B8_
3237
0
                timing.virtual_machine_call_duration +=
3238
0
                    platform.now() - runtime_call_duration_before;
3239
            }
3240
0
            executor::runtime_call::RuntimeCall::ClosestDescendantMerkleValue(mv) => {
3241
0
                let merkle_value = if let Some(trie_root) = trie_root {
3242
0
                    call_proof.closest_descendant_merkle_value(&trie_root, mv.key())
3243
                } else {
3244
0
                    Ok(None)
3245
                };
3246
0
                let Ok(merkle_value) = merkle_value else {
3247
0
                    return (
3248
0
                        timing,
3249
0
                        Err(SingleRuntimeCallAttemptError::Inaccessible(
3250
0
                            RuntimeCallInaccessibleError::MissingProofEntry,
3251
0
                        )),
3252
0
                    );
3253
                };
3254
0
                timing.proof_access_duration += platform.now() - proof_access_duration_before;
3255
0
3256
0
                let runtime_call_duration_before = platform.now();
3257
0
                call = mv.inject_merkle_value(merkle_value);
3258
0
                timing.virtual_machine_call_duration +=
3259
0
                    platform.now() - runtime_call_duration_before;
3260
            }
3261
0
            executor::runtime_call::RuntimeCall::NextKey(nk) => {
3262
0
                let next_key = if let Some(trie_root) = trie_root {
3263
0
                    call_proof.next_key(
3264
0
                        &trie_root,
3265
0
                        nk.key(),
3266
0
                        nk.or_equal(),
3267
0
                        nk.prefix(),
3268
0
                        nk.branch_nodes(),
3269
0
                    )
3270
                } else {
3271
0
                    Ok(None)
3272
                };
3273
0
                let Ok(next_key) = next_key else {
3274
0
                    return (
3275
0
                        timing,
3276
0
                        Err(SingleRuntimeCallAttemptError::Inaccessible(
3277
0
                            RuntimeCallInaccessibleError::MissingProofEntry,
3278
0
                        )),
3279
0
                    );
3280
                };
3281
0
                timing.proof_access_duration += platform.now() - proof_access_duration_before;
3282
0
3283
0
                let runtime_call_duration_before = platform.now();
3284
0
                call = nk.inject_key(next_key);
3285
0
                timing.virtual_machine_call_duration +=
3286
0
                    platform.now() - runtime_call_duration_before;
3287
            }
3288
0
            _ => unreachable!(),
3289
        }
3290
    }
3291
0
}
Unexecuted instantiation: _RNCINvNtCsiGub1lfKphe_13smoldot_light15runtime_service27runtime_call_single_attemptpE0B6_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0B1n_
Unexecuted instantiation: _RNCINvNtCsih6EgvAwZF2_13smoldot_light15runtime_service27runtime_call_single_attemptpE0B6_
3292
3293
/// See [`runtime_call_single_attempt`].
3294
#[derive(Debug, Clone)]
3295
struct SingleRuntimeCallTiming {
3296
    /// Time spent execution the virtual machine.
3297
    virtual_machine_call_duration: Duration,
3298
    /// Time spent accessing the call proof.
3299
    proof_access_duration: Duration,
3300
}
3301
3302
/// See [`runtime_call_single_attempt`].
3303
0
#[derive(Debug, derive_more::Display, Clone)]
Unexecuted instantiation: _RNvXsK_NtCsiGub1lfKphe_13smoldot_light15runtime_serviceNtB5_29SingleRuntimeCallAttemptErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
Unexecuted instantiation: _RNvXsK_NtCsih6EgvAwZF2_13smoldot_light15runtime_serviceNtB5_29SingleRuntimeCallAttemptErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt
3304
enum SingleRuntimeCallAttemptError {
3305
    /// Error during the execution of the runtime.
3306
    ///
3307
    /// There is no point in trying the same call again, as it would result in the same error.
3308
    #[display(fmt = "Error during the execution of the runtime: {_0}")]
3309
    Execution(RuntimeCallExecutionError),
3310
3311
    /// Error trying to access the storage required for the runtime call.
3312
    ///
3313
    /// Trying the same call again might succeed.
3314
    #[display(fmt = "Error trying to access the storage required for the runtime call: {_0}")]
3315
    Inaccessible(RuntimeCallInaccessibleError),
3316
}