Coverage Report

Created: 2025-07-01 09:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/light-base/src/sync_service/parachain.rs
Line
Count
Source
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
use super::ToBackground;
19
use crate::{log, network_service, platform::PlatformRef, runtime_service, util};
20
21
use alloc::{borrow::ToOwned as _, boxed::Box, format, string::String, sync::Arc, vec::Vec};
22
use core::{mem, num::NonZero, pin::Pin, time::Duration};
23
use futures_lite::FutureExt as _;
24
use futures_util::{StreamExt as _, future, stream};
25
use hashbrown::HashMap;
26
use itertools::Itertools as _;
27
use smoldot::{
28
    chain::async_tree, header, informant::HashDisplay, libp2p::PeerId, network::codec, sync::para,
29
};
30
31
/// Starts a sync service background task to synchronize a parachain.
32
0
pub(super) async fn start_parachain<TPlat: PlatformRef>(
33
0
    log_target: String,
34
0
    platform: TPlat,
35
0
    finalized_block_header: Vec<u8>,
36
0
    block_number_bytes: usize,
37
0
    relay_chain_sync: Arc<runtime_service::RuntimeService<TPlat>>,
38
0
    parachain_id: u32,
39
0
    from_foreground: Pin<Box<async_channel::Receiver<ToBackground>>>,
40
0
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
41
0
) {
Unexecuted instantiation: _RINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain15start_parachainpEB6_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEB1i_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainpEB6_
42
    ParachainBackgroundTask {
43
0
        log_target,
44
0
        from_foreground,
45
0
        block_number_bytes,
46
0
        parachain_id,
47
0
        from_network_service: None,
48
0
        network_service,
49
0
        obsolete_finalized_parahead: finalized_block_header,
50
0
        sync_sources: HashMap::with_capacity_and_hasher(
51
            0,
52
0
            util::SipHasherBuild::new({
53
0
                let mut seed = [0; 16];
54
0
                platform.fill_random_bytes(&mut seed);
55
0
                seed
56
            }),
57
        ),
58
        subscription_state: ParachainBackgroundState::NotSubscribed {
59
0
            all_subscriptions: Vec::new(),
60
            subscribe_future: {
61
0
                let relay_chain_sync = relay_chain_sync.clone();
62
0
                Box::pin(async move {
63
0
                    relay_chain_sync
64
0
                        .subscribe_all(32, NonZero::<usize>::new(usize::MAX).unwrap())
65
0
                        .await
66
0
                })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain15start_parachainpE00Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE00B1m_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainpE00Ba_
67
            },
68
        },
69
0
        relay_chain_sync,
70
0
        platform,
71
    }
72
0
    .run()
73
0
    .await;
74
0
}
Unexecuted instantiation: _RNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain15start_parachainpE0B8_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0B1k_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain15start_parachainpE0B8_
75
76
/// Task that is running in the background.
77
struct ParachainBackgroundTask<TPlat: PlatformRef> {
78
    /// Target to use for all logs.
79
    log_target: String,
80
81
    /// Access to the platform's capabilities.
82
    platform: TPlat,
83
84
    /// Channel receiving message from the sync service frontend.
85
    from_foreground: Pin<Box<async_channel::Receiver<ToBackground>>>,
86
87
    /// Number of bytes to use to encode the parachain block numbers in headers.
88
    block_number_bytes: usize,
89
90
    /// Id of the parachain registered within the relay chain. Chosen by the user.
91
    parachain_id: u32,
92
93
    /// Networking service connected to the peer-to-peer network of the parachain.
94
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
95
96
    /// Events coming from the networking service. `None` if not subscribed yet.
97
    from_network_service: Option<Pin<Box<async_channel::Receiver<network_service::Event>>>>,
98
99
    /// Runtime service of the relay chain.
100
    relay_chain_sync: Arc<runtime_service::RuntimeService<TPlat>>,
101
102
    /// Last-known finalized parachain header. Can be very old and obsolete.
103
    /// Updated after we successfully fetch the parachain head of a relay chain finalized block,
104
    /// and left untouched if the fetch fails.
105
    /// Initialized to the parachain genesis block header.
106
    obsolete_finalized_parahead: Vec<u8>,
107
108
    /// List of parachain network sources.
109
    ///
110
    /// Values are their role, and self-reported best block when we connected to them. This best
111
    /// block is never updated.
112
    ///
113
    /// > **Note**: In the past, smoldot used to track exactly which peer knows which block
114
    /// >           based on block announces. This, however, caused issues due to the fact that
115
    /// >           there's a disconnect between the parachain best block on the relay chain
116
    /// >           and the parachain best block on the network. We currently simply assume that
117
    /// >           all parachain nodes know about all parachain blocks from the relay chain.
118
    sync_sources: HashMap<PeerId, (codec::Role, u64, [u8; 32]), util::SipHasherBuild>,
119
120
    /// Extra fields that are set after the subscription to the runtime service events has
121
    /// succeeded.
122
    subscription_state: ParachainBackgroundState<TPlat>,
123
}
124
125
enum ParachainBackgroundState<TPlat: PlatformRef> {
126
    /// Currently subscribing to the relay chain runtime service.
127
    NotSubscribed {
128
        /// List of senders that will get notified when the tree of blocks is modified.
129
        ///
130
        /// These subscriptions are pending and no notification should be sent to them until the
131
        /// subscription to the relay chain runtime service is finished.
132
        all_subscriptions: Vec<async_channel::Sender<super::Notification>>,
133
134
        /// Future when the subscription has finished.
135
        subscribe_future: future::BoxFuture<'static, runtime_service::SubscribeAll<TPlat>>,
136
    },
137
138
    /// Subscribed to the relay chain runtime service.
139
    Subscribed(ParachainBackgroundTaskAfterSubscription<TPlat>),
140
}
141
142
struct ParachainBackgroundTaskAfterSubscription<TPlat: PlatformRef> {
143
    /// List of senders that get notified when the tree of blocks is modified.
144
    all_subscriptions: Vec<async_channel::Sender<super::Notification>>,
145
146
    /// Stream of blocks of the relay chain this parachain is registered on.
147
    /// The buffer size should be large enough so that, if the CPU is busy, it doesn't become full
148
    /// before the execution of the sync service resumes.
149
    /// The maximum number of pinned block is ignored, as this maximum is a way to avoid malicious
150
    /// behaviors. This code is by definition not considered malicious.
151
    relay_chain_subscribe_all: runtime_service::Subscription<TPlat>,
152
153
    /// Hash of the best parachain that has been reported to the subscriptions.
154
    /// `None` if and only if no finalized parachain head is known yet.
155
    reported_best_parahead_hash: Option<[u8; 32]>,
156
157
    /// Tree of relay chain blocks. Blocks are inserted when received from the relay chain
158
    /// sync service. Once inside, their corresponding parachain head is fetched. Once the
159
    /// parachain head is fetched, this parachain head is reported to our subscriptions.
160
    ///
161
    /// The root of the tree is a "virtual" block. It can be thought as the parent of the relay
162
    /// chain finalized block, but is there even if the relay chain finalized block is block 0.
163
    ///
164
    /// All block in the tree has an associated parachain head behind an `Option`. This `Option`
165
    /// always contains `Some`, except for the "virtual" root block for which it is `None`.
166
    ///
167
    /// If the output finalized block has a parachain head equal to `None`, it therefore means
168
    /// that no finalized parachain head is known yet.
169
    /// Note that, when it is the case, `SubscribeAll` messages from the frontend are still
170
    /// answered with a single finalized block set to `obsolete_finalized_parahead`. Once a
171
    /// finalized parachain head is known, it is important to reset all subscriptions.
172
    ///
173
    /// The set of blocks in this tree whose parachain block hasn't been fetched yet is the same
174
    /// as the set of blocks that is maintained pinned on the runtime service. Blocks are unpinned
175
    /// when their parachain head fetching succeeds or when they are removed from the tree.
176
    async_tree: async_tree::AsyncTree<TPlat::Instant, [u8; 32], Option<Vec<u8>>>,
177
178
    /// If `true`, [`ParachainBackgroundTaskAfterSubscription::async_tree`] might need to
179
    /// be advanced.
180
    must_process_sync_tree: bool,
181
182
    /// List of in-progress parachain head fetching operations.
183
    ///
184
    /// The operations require some blocks to be pinned within the relay chain runtime service,
185
    /// which is guaranteed by the fact that `relay_chain_subscribe_all.new_blocks` stays
186
    /// alive for longer than this container, and by the fact that we unpin block after a
187
    /// fetching operation has finished and that we never fetch twice for the same block.
188
    in_progress_paraheads: stream::FuturesUnordered<
189
        future::BoxFuture<'static, (async_tree::AsyncOpId, Result<Vec<u8>, ParaheadError>)>,
190
    >,
191
192
    /// Future that is ready when we need to start a new parachain head fetch operation.
193
    next_start_parahead_fetch: Pin<Box<dyn Future<Output = ()> + Send>>,
194
}
195
196
impl<TPlat: PlatformRef> ParachainBackgroundTask<TPlat> {
197
0
    async fn run(mut self) {
Unexecuted instantiation: _RNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB2_23ParachainBackgroundTaskpE3runB6_
Unexecuted instantiation: _RNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB2_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3runB1w_
Unexecuted instantiation: _RNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB2_23ParachainBackgroundTaskpE3runB6_
198
        loop {
199
            // Yield at every loop in order to provide better tasks granularity.
200
0
            futures_lite::future::yield_now().await;
201
202
            // Wait until something interesting happens.
203
            enum WakeUpReason<TPlat: PlatformRef> {
204
                ForegroundClosed,
205
                ForegroundMessage(ToBackground),
206
                NewSubscription(runtime_service::SubscribeAll<TPlat>),
207
                StartParaheadFetch,
208
                ParaheadFetchFinished {
209
                    async_op_id: async_tree::AsyncOpId,
210
                    parahead_result: Result<Vec<u8>, ParaheadError>,
211
                },
212
                Notification(runtime_service::Notification),
213
                SubscriptionDead,
214
                MustSubscribeNetworkEvents,
215
                NetworkEvent(network_service::Event),
216
                AdvanceSyncTree,
217
            }
218
219
0
            let wake_up_reason: WakeUpReason<_> = {
220
                let (
221
0
                    subscribe_future,
222
0
                    next_start_parahead_fetch,
223
0
                    relay_chain_subscribe_all,
224
0
                    in_progress_paraheads,
225
0
                    must_process_sync_tree,
226
0
                    is_relaychain_subscribed,
227
0
                ) = match &mut self.subscription_state {
228
                    ParachainBackgroundState::NotSubscribed {
229
0
                        subscribe_future, ..
230
0
                    } => (Some(subscribe_future), None, None, None, None, false),
231
0
                    ParachainBackgroundState::Subscribed(runtime_subscription) => (
232
0
                        None,
233
0
                        Some(&mut runtime_subscription.next_start_parahead_fetch),
234
0
                        Some(&mut runtime_subscription.relay_chain_subscribe_all),
235
0
                        Some(&mut runtime_subscription.in_progress_paraheads),
236
0
                        Some(&mut runtime_subscription.must_process_sync_tree),
237
0
                        true,
238
0
                    ),
239
                };
240
241
0
                async {
242
0
                    if let Some(subscribe_future) = subscribe_future {
243
0
                        WakeUpReason::NewSubscription(subscribe_future.await)
244
                    } else {
245
0
                        future::pending().await
246
                    }
247
0
                }
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run00Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run00B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run00Ba_
248
0
                .or(async {
249
0
                    match self.from_foreground.next().await {
250
0
                        Some(msg) => WakeUpReason::ForegroundMessage(msg),
251
0
                        None => WakeUpReason::ForegroundClosed,
252
                    }
253
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s_0Ba_
254
0
                .or(async {
255
0
                    if let Some(relay_chain_subscribe_all) = relay_chain_subscribe_all {
256
0
                        match relay_chain_subscribe_all.next().await {
257
0
                            Some(notif) => WakeUpReason::Notification(notif),
258
0
                            None => WakeUpReason::SubscriptionDead,
259
                        }
260
                    } else {
261
0
                        future::pending().await
262
                    }
263
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s0_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s0_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s0_0Ba_
264
0
                .or(async {
265
0
                    if is_relaychain_subscribed {
266
0
                        if let Some(from_network_service) = self.from_network_service.as_mut() {
267
0
                            match from_network_service.next().await {
268
0
                                Some(ev) => WakeUpReason::NetworkEvent(ev),
269
                                None => {
270
0
                                    self.from_network_service = None;
271
0
                                    WakeUpReason::MustSubscribeNetworkEvents
272
                                }
273
                            }
274
                        } else {
275
0
                            WakeUpReason::MustSubscribeNetworkEvents
276
                        }
277
                    } else {
278
0
                        future::pending().await
279
                    }
280
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s1_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s1_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s1_0Ba_
281
0
                .or(async {
282
0
                    if let Some(next_start_parahead_fetch) = next_start_parahead_fetch {
283
0
                        next_start_parahead_fetch.as_mut().await;
284
0
                        *next_start_parahead_fetch = Box::pin(future::pending());
285
0
                        WakeUpReason::StartParaheadFetch
286
                    } else {
287
0
                        future::pending().await
288
                    }
289
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s2_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s2_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s2_0Ba_
290
0
                .or(async {
291
0
                    if let Some(in_progress_paraheads) = in_progress_paraheads {
292
0
                        if !in_progress_paraheads.is_empty() {
293
0
                            let (async_op_id, parahead_result) =
294
0
                                in_progress_paraheads.next().await.unwrap();
295
0
                            WakeUpReason::ParaheadFetchFinished {
296
0
                                async_op_id,
297
0
                                parahead_result,
298
0
                            }
299
                        } else {
300
0
                            future::pending().await
301
                        }
302
                    } else {
303
0
                        future::pending().await
304
                    }
305
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s3_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s3_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s3_0Ba_
306
0
                .or(async {
307
0
                    if let Some(must_process_sync_tree) = must_process_sync_tree {
308
0
                        if *must_process_sync_tree {
309
0
                            *must_process_sync_tree = false;
310
0
                            WakeUpReason::AdvanceSyncTree
311
                        } else {
312
0
                            future::pending().await
313
                        }
314
                    } else {
315
0
                        future::pending().await
316
                    }
317
0
                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s4_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s4_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s4_0Ba_
318
0
                .await
319
            };
320
321
0
            match (wake_up_reason, &mut self.subscription_state) {
322
                (WakeUpReason::ForegroundClosed, _) => {
323
                    // Terminate the background task.
324
0
                    return;
325
                }
326
327
0
                (WakeUpReason::NewSubscription(relay_chain_subscribe_all), _) => {
328
                    // Subscription to the relay chain has finished.
329
0
                    log!(
330
0
                        &self.platform,
331
                        Debug,
332
0
                        &self.log_target,
333
                        "relay-chain-new-subscription",
334
0
                        finalized_hash = HashDisplay(&header::hash_from_scale_encoded_header(
335
0
                            &relay_chain_subscribe_all.finalized_block_scale_encoded_header
336
0
                        )),
337
0
                        subscription_id = ?relay_chain_subscribe_all.new_blocks.id(),
338
                    );
339
0
                    log!(
340
0
                        &self.platform,
341
                        Debug,
342
0
                        &self.log_target,
343
                        "parahead-fetch-operations-cleared"
344
                    );
345
346
0
                    let async_tree = {
347
0
                        let mut async_tree =
348
0
                            async_tree::AsyncTree::<TPlat::Instant, [u8; 32], _>::new(
349
0
                                async_tree::Config {
350
0
                                    finalized_async_user_data: None,
351
0
                                    retry_after_failed: Duration::from_secs(5),
352
0
                                    blocks_capacity: 32,
353
0
                                },
354
                            );
355
0
                        let finalized_hash = header::hash_from_scale_encoded_header(
356
0
                            &relay_chain_subscribe_all.finalized_block_scale_encoded_header,
357
                        );
358
0
                        let finalized_index =
359
0
                            async_tree.input_insert_block(finalized_hash, None, false, true);
360
0
                        async_tree.input_finalize(finalized_index);
361
0
                        for block in relay_chain_subscribe_all.non_finalized_blocks_ancestry_order {
362
0
                            let hash =
363
0
                                header::hash_from_scale_encoded_header(&block.scale_encoded_header);
364
0
                            let parent = async_tree
365
0
                                .input_output_iter_unordered()
366
0
                                .find(|b| *b.user_data == block.parent_hash)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s5_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s5_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s5_0Ba_
367
0
                                .map(|b| b.id)
368
0
                                .unwrap_or(finalized_index);
369
0
                            async_tree.input_insert_block(
370
0
                                hash,
371
0
                                Some(parent),
372
                                false,
373
0
                                block.is_new_best,
374
                            );
375
                        }
376
0
                        async_tree
377
                    };
378
379
0
                    self.subscription_state = ParachainBackgroundState::Subscribed(
380
                        ParachainBackgroundTaskAfterSubscription {
381
0
                            all_subscriptions: match &mut self.subscription_state {
382
                                ParachainBackgroundState::NotSubscribed {
383
0
                                    all_subscriptions,
384
                                    ..
385
0
                                } => mem::take(all_subscriptions),
386
0
                                _ => unreachable!(),
387
                            },
388
0
                            relay_chain_subscribe_all: relay_chain_subscribe_all.new_blocks,
389
0
                            reported_best_parahead_hash: None,
390
0
                            async_tree,
391
                            must_process_sync_tree: false,
392
0
                            in_progress_paraheads: stream::FuturesUnordered::new(),
393
0
                            next_start_parahead_fetch: Box::pin(future::ready(())),
394
                        },
395
                    );
396
                }
397
398
                (
399
                    WakeUpReason::AdvanceSyncTree,
400
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
401
                ) => {
402
0
                    if let Some(update) = runtime_subscription.async_tree.try_advance_output() {
403
                        // Make sure to process any notification that comes after.
404
0
                        runtime_subscription.must_process_sync_tree = true;
405
406
0
                        match update {
407
                            async_tree::OutputUpdate::Finalized {
408
0
                                former_finalized_async_op_user_data: former_finalized_parahead,
409
0
                                pruned_blocks,
410
0
                                best_output_block_updated,
411
                                ..
412
0
                            } if *runtime_subscription
413
0
                                .async_tree
414
0
                                .output_finalized_async_user_data()
415
0
                                != former_finalized_parahead =>
416
                            {
417
0
                                let new_finalized_parahead = runtime_subscription
418
0
                                    .async_tree
419
0
                                    .output_finalized_async_user_data();
420
0
                                debug_assert!(new_finalized_parahead.is_some());
421
422
                                // If this is the first time a finalized parahead is known, any
423
                                // `SubscribeAll` message that has been answered beforehand was
424
                                // answered in a dummy way with a potentially obsolete finalized
425
                                // header.
426
                                // For this reason, we reset all subscriptions to force all
427
                                // subscribers to re-subscribe.
428
0
                                if former_finalized_parahead.is_none() {
429
0
                                    runtime_subscription.all_subscriptions.clear();
430
0
                                }
431
432
0
                                let hash = header::hash_from_scale_encoded_header(
433
0
                                    new_finalized_parahead.as_ref().unwrap(),
434
                                );
435
436
0
                                self.obsolete_finalized_parahead =
437
0
                                    new_finalized_parahead.clone().unwrap();
438
439
                                // Must unpin the pruned blocks if they haven't already been unpinned.
440
0
                                let mut pruned_blocks_hashes =
441
0
                                    Vec::with_capacity(pruned_blocks.len());
442
0
                                for (_, hash, pruned_block_parahead) in pruned_blocks {
443
0
                                    if pruned_block_parahead.is_none() {
444
0
                                        runtime_subscription
445
0
                                            .relay_chain_subscribe_all
446
0
                                            .unpin_block(hash)
447
0
                                            .await;
448
0
                                    }
449
0
                                    pruned_blocks_hashes.push(hash);
450
                                }
451
452
0
                                log!(
453
0
                                    &self.platform,
454
                                    Debug,
455
0
                                    &self.log_target,
456
                                    "subscriptions-notify-parablock-finalized",
457
0
                                    hash = HashDisplay(&hash)
458
                                );
459
460
0
                                let best_block_hash = runtime_subscription
461
0
                                    .async_tree
462
0
                                    .output_best_block_index()
463
0
                                    .map(|(_, parahead)| {
464
0
                                        header::hash_from_scale_encoded_header(
465
0
                                            parahead.as_ref().unwrap(),
466
                                        )
467
0
                                    })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s7_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s7_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s7_0Ba_
468
0
                                    .unwrap_or(hash);
469
0
                                runtime_subscription.reported_best_parahead_hash =
470
0
                                    Some(best_block_hash);
471
472
                                // Elements in `all_subscriptions` are removed one by one and
473
                                // inserted back if the channel is still open.
474
0
                                for index in (0..runtime_subscription.all_subscriptions.len()).rev()
475
                                {
476
0
                                    let sender =
477
0
                                        runtime_subscription.all_subscriptions.swap_remove(index);
478
0
                                    let notif = super::Notification::Finalized {
479
0
                                        hash,
480
0
                                        best_block_hash_if_changed: if best_output_block_updated {
481
0
                                            Some(best_block_hash)
482
                                        } else {
483
0
                                            None
484
                                        },
485
0
                                        pruned_blocks: pruned_blocks_hashes.clone(),
486
                                    };
487
0
                                    if sender.try_send(notif).is_ok() {
488
0
                                        runtime_subscription.all_subscriptions.push(sender);
489
0
                                    }
490
                                }
491
                            }
492
493
                            async_tree::OutputUpdate::Finalized { .. }
494
                            | async_tree::OutputUpdate::BestBlockChanged { .. } => {
495
                                // Do not report anything to subscriptions if no finalized parahead is
496
                                // known yet.
497
0
                                let finalized_parahead = match runtime_subscription
498
0
                                    .async_tree
499
0
                                    .output_finalized_async_user_data()
500
                                {
501
0
                                    Some(p) => p,
502
0
                                    None => continue,
503
                                };
504
505
                                // Calculate hash of the parablock corresponding to the new best relay
506
                                // chain block.
507
0
                                let parahash = header::hash_from_scale_encoded_header(
508
0
                                    runtime_subscription
509
0
                                        .async_tree
510
0
                                        .output_best_block_index()
511
0
                                        .map(|(_, b)| b.as_ref().unwrap())
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s8_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s8_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s8_0Ba_
512
0
                                        .unwrap_or(finalized_parahead),
513
                                );
514
515
0
                                if runtime_subscription.reported_best_parahead_hash.as_ref()
516
0
                                    != Some(&parahash)
517
                                {
518
0
                                    runtime_subscription.reported_best_parahead_hash =
519
0
                                        Some(parahash);
520
521
                                    // The networking service needs to be kept up to date with what the local
522
                                    // node considers as the best block.
523
0
                                    if let Ok(header) =
524
0
                                        header::decode(finalized_parahead, self.block_number_bytes)
525
                                    {
526
0
                                        self.network_service
527
0
                                            .set_local_best_block(parahash, header.number)
528
0
                                            .await;
529
0
                                    }
530
531
0
                                    log!(
532
0
                                        &self.platform,
533
                                        Debug,
534
0
                                        &self.log_target,
535
                                        "subscriptions-notify-best-block-changed",
536
0
                                        hash = HashDisplay(&parahash)
537
                                    );
538
539
                                    // Elements in `all_subscriptions` are removed one by one and
540
                                    // inserted back if the channel is still open.
541
0
                                    for index in
542
0
                                        (0..runtime_subscription.all_subscriptions.len()).rev()
543
                                    {
544
0
                                        let sender = runtime_subscription
545
0
                                            .all_subscriptions
546
0
                                            .swap_remove(index);
547
0
                                        let notif = super::Notification::BestBlockChanged {
548
0
                                            hash: parahash,
549
0
                                        };
550
0
                                        if sender.try_send(notif).is_ok() {
551
0
                                            runtime_subscription.all_subscriptions.push(sender);
552
0
                                        }
553
                                    }
554
0
                                }
555
                            }
556
557
0
                            async_tree::OutputUpdate::Block(block) => {
558
                                // `block` borrows `async_tree`. We need to mutably access `async_tree`
559
                                // below, so deconstruct `block` beforehand.
560
0
                                let is_new_best = block.is_new_best;
561
0
                                let block_index = block.index;
562
0
                                let scale_encoded_header: Vec<u8> = runtime_subscription
563
0
                                    .async_tree
564
0
                                    .block_async_user_data(block.index)
565
0
                                    .unwrap()
566
0
                                    .clone()
567
0
                                    .unwrap();
568
0
                                let parahash =
569
0
                                    header::hash_from_scale_encoded_header(&scale_encoded_header);
570
571
                                // Do not report anything to subscriptions if no finalized parahead is
572
                                // known yet.
573
0
                                let finalized_parahead = match runtime_subscription
574
0
                                    .async_tree
575
0
                                    .output_finalized_async_user_data()
576
                                {
577
0
                                    Some(p) => p,
578
0
                                    None => continue,
579
                                };
580
581
                                // Do not report the new block if it has already been reported in the
582
                                // past. This covers situations where the parahead is identical to the
583
                                // relay chain's parent's parahead, but also situations where multiple
584
                                // sibling relay chain blocks have the same parahead.
585
0
                                if *finalized_parahead == scale_encoded_header
586
0
                                    || runtime_subscription
587
0
                                        .async_tree
588
0
                                        .input_output_iter_unordered()
589
0
                                        .filter(|item| item.id != block_index)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s9_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0s9_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0s9_0Ba_
590
0
                                        .filter_map(|item| item.async_op_user_data)
591
0
                                        .any(|item| item.as_ref() == Some(&scale_encoded_header))
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sb_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sb_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sb_0Ba_
592
                                {
593
                                    // While the parablock has already been reported, it is possible that
594
                                    // it becomes the new best block while it wasn't before, in which
595
                                    // case we should send a notification.
596
0
                                    if is_new_best
597
0
                                        && runtime_subscription.reported_best_parahead_hash.as_ref()
598
0
                                            != Some(&parahash)
599
                                    {
600
0
                                        runtime_subscription.reported_best_parahead_hash =
601
0
                                            Some(parahash);
602
603
                                        // The networking service needs to be kept up to date with what the
604
                                        // local node considers as the best block.
605
0
                                        if let Ok(header) = header::decode(
606
0
                                            finalized_parahead,
607
0
                                            self.block_number_bytes,
608
0
                                        ) {
609
0
                                            self.network_service
610
0
                                                .set_local_best_block(parahash, header.number)
611
0
                                                .await;
612
0
                                        }
613
614
0
                                        log!(
615
0
                                            &self.platform,
616
                                            Debug,
617
0
                                            &self.log_target,
618
                                            "subscriptions-notify-best-block-changed",
619
0
                                            hash = HashDisplay(&parahash)
620
                                        );
621
622
                                        // Elements in `all_subscriptions` are removed one by one and
623
                                        // inserted back if the channel is still open.
624
0
                                        for index in
625
0
                                            (0..runtime_subscription.all_subscriptions.len()).rev()
626
                                        {
627
0
                                            let sender = runtime_subscription
628
0
                                                .all_subscriptions
629
0
                                                .swap_remove(index);
630
0
                                            let notif = super::Notification::BestBlockChanged {
631
0
                                                hash: parahash,
632
0
                                            };
633
0
                                            if sender.try_send(notif).is_ok() {
634
0
                                                runtime_subscription.all_subscriptions.push(sender);
635
0
                                            }
636
                                        }
637
0
                                    }
638
639
0
                                    continue;
640
0
                                }
641
642
0
                                if is_new_best {
643
0
                                    runtime_subscription.reported_best_parahead_hash =
644
0
                                        Some(parahash);
645
0
                                }
646
647
0
                                let parent_hash = header::hash_from_scale_encoded_header(
648
0
                                    runtime_subscription
649
0
                                        .async_tree
650
0
                                        .parent(block_index)
651
0
                                        .map(|idx| {
652
0
                                            runtime_subscription
653
0
                                                .async_tree
654
0
                                                .block_async_user_data(idx)
655
0
                                                .unwrap()
656
0
                                                .as_ref()
657
0
                                                .unwrap()
658
0
                                        })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sc_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sc_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sc_0Ba_
659
0
                                        .unwrap_or(finalized_parahead),
660
                                );
661
662
0
                                log!(
663
0
                                    &self.platform,
664
                                    Debug,
665
0
                                    &self.log_target,
666
                                    "subscriptions-notify-new-parablock",
667
0
                                    hash = HashDisplay(&parahash),
668
0
                                    parent_hash = HashDisplay(&parent_hash),
669
                                    ?is_new_best
670
                                );
671
672
                                // Elements in `all_subscriptions` are removed one by one and
673
                                // inserted back if the channel is still open.
674
0
                                for index in (0..runtime_subscription.all_subscriptions.len()).rev()
675
                                {
676
0
                                    let sender =
677
0
                                        runtime_subscription.all_subscriptions.swap_remove(index);
678
0
                                    let notif =
679
0
                                        super::Notification::Block(super::BlockNotification {
680
0
                                            is_new_best,
681
0
                                            parent_hash,
682
0
                                            scale_encoded_header: scale_encoded_header.clone(),
683
0
                                        });
684
0
                                    if sender.try_send(notif).is_ok() {
685
0
                                        runtime_subscription.all_subscriptions.push(sender);
686
0
                                    }
687
                                }
688
                            }
689
                        }
690
0
                    }
691
                }
692
693
                (
694
                    WakeUpReason::StartParaheadFetch,
695
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
696
                ) => {
697
                    // Must start downloading a parahead.
698
699
                    // Internal state check.
700
0
                    debug_assert_eq!(
701
0
                        runtime_subscription.reported_best_parahead_hash.is_some(),
702
0
                        runtime_subscription
703
0
                            .async_tree
704
0
                            .output_finalized_async_user_data()
705
0
                            .is_some()
706
                    );
707
708
                    // Limit the maximum number of simultaneous downloads.
709
0
                    if runtime_subscription.in_progress_paraheads.len() >= 4 {
710
0
                        continue;
711
0
                    }
712
713
0
                    match runtime_subscription
714
0
                        .async_tree
715
0
                        .next_necessary_async_op(&self.platform.now())
716
                    {
717
0
                        async_tree::NextNecessaryAsyncOp::NotReady { when: Some(when) } => {
718
0
                            runtime_subscription.next_start_parahead_fetch =
719
0
                                Box::pin(self.platform.sleep_until(when));
720
0
                        }
721
0
                        async_tree::NextNecessaryAsyncOp::NotReady { when: None } => {
722
0
                            runtime_subscription.next_start_parahead_fetch =
723
0
                                Box::pin(future::pending());
724
0
                        }
725
0
                        async_tree::NextNecessaryAsyncOp::Ready(op) => {
726
0
                            log!(
727
0
                                &self.platform,
728
                                Debug,
729
0
                                &self.log_target,
730
                                "parahead-fetch-operation-started",
731
                                relay_block_hash =
732
0
                                    HashDisplay(&runtime_subscription.async_tree[op.block_index]),
733
                            );
734
735
0
                            runtime_subscription.in_progress_paraheads.push({
736
0
                                let relay_chain_sync = self.relay_chain_sync.clone();
737
0
                                let subscription_id =
738
0
                                    runtime_subscription.relay_chain_subscribe_all.id();
739
0
                                let block_hash = runtime_subscription.async_tree[op.block_index];
740
0
                                let async_op_id = op.id;
741
0
                                let parachain_id = self.parachain_id;
742
0
                                Box::pin(async move {
743
                                    (
744
0
                                        async_op_id,
745
0
                                        fetch_parahead(
746
0
                                            &relay_chain_sync,
747
0
                                            subscription_id,
748
0
                                            parachain_id,
749
0
                                            &block_hash,
750
0
                                        )
751
0
                                        .await,
752
                                    )
753
0
                                })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sd_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sd_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sd_0Ba_
754
                            });
755
756
                            // There might be more downloads to start.
757
0
                            runtime_subscription.next_start_parahead_fetch =
758
0
                                Box::pin(future::ready(()));
759
                        }
760
                    }
761
                }
762
763
                (
764
                    WakeUpReason::Notification(runtime_service::Notification::Finalized {
765
0
                        hash,
766
0
                        best_block_hash_if_changed,
767
                        ..
768
                    }),
769
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
770
                ) => {
771
                    // Relay chain has a new finalized block.
772
0
                    log!(
773
0
                        &self.platform,
774
                        Debug,
775
0
                        &self.log_target,
776
                        "relay-chain-block-finalized",
777
0
                        hash = HashDisplay(&hash)
778
                    );
779
780
0
                    if let Some(best_block_hash_if_changed) = best_block_hash_if_changed {
781
0
                        let best = runtime_subscription
782
0
                            .async_tree
783
0
                            .input_output_iter_unordered()
784
0
                            .find(|b| *b.user_data == best_block_hash_if_changed)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0se_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0se_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0se_0Ba_
785
0
                            .unwrap()
786
                            .id;
787
0
                        runtime_subscription
788
0
                            .async_tree
789
0
                            .input_set_best_block(Some(best));
790
0
                    }
791
792
0
                    let finalized = runtime_subscription
793
0
                        .async_tree
794
0
                        .input_output_iter_unordered()
795
0
                        .find(|b| *b.user_data == hash)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sf_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sf_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sf_0Ba_
796
0
                        .unwrap()
797
                        .id;
798
0
                    runtime_subscription.async_tree.input_finalize(finalized);
799
0
                    runtime_subscription.must_process_sync_tree = true;
800
                }
801
802
                (
803
0
                    WakeUpReason::Notification(runtime_service::Notification::Block(block)),
804
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
805
                ) => {
806
                    // Relay chain has a new block.
807
0
                    let hash = header::hash_from_scale_encoded_header(&block.scale_encoded_header);
808
809
0
                    log!(
810
0
                        &self.platform,
811
                        Debug,
812
0
                        &self.log_target,
813
                        "relay-chain-new-block",
814
0
                        hash = HashDisplay(&hash),
815
0
                        parent_hash = HashDisplay(&block.parent_hash)
816
                    );
817
818
0
                    let parent = runtime_subscription
819
0
                        .async_tree
820
0
                        .input_output_iter_unordered()
821
0
                        .find(|b| *b.user_data == block.parent_hash)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sg_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sg_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sg_0Ba_
822
0
                        .map(|b| b.id); // TODO: check if finalized
823
0
                    runtime_subscription.async_tree.input_insert_block(
824
0
                        hash,
825
0
                        parent,
826
                        false,
827
0
                        block.is_new_best,
828
                    );
829
0
                    runtime_subscription.must_process_sync_tree = true;
830
831
0
                    runtime_subscription.next_start_parahead_fetch = Box::pin(future::ready(()));
832
                }
833
834
                (
835
                    WakeUpReason::Notification(runtime_service::Notification::BestBlockChanged {
836
0
                        hash,
837
                    }),
838
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
839
                ) => {
840
                    // Relay chain has a new best block.
841
0
                    log!(
842
0
                        &self.platform,
843
                        Debug,
844
0
                        &self.log_target,
845
                        "relay-chain-best-block-changed",
846
0
                        hash = HashDisplay(&hash)
847
                    );
848
849
                    // If the block isn't found in `async_tree`, assume that it is equal to the
850
                    // finalized block (that has left the tree already).
851
0
                    let node_idx = runtime_subscription
852
0
                        .async_tree
853
0
                        .input_output_iter_unordered()
854
0
                        .find(|b| *b.user_data == hash)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0si_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0si_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0si_0Ba_
855
0
                        .map(|b| b.id);
856
0
                    runtime_subscription
857
0
                        .async_tree
858
0
                        .input_set_best_block(node_idx);
859
860
0
                    runtime_subscription.must_process_sync_tree = true;
861
                }
862
863
                (WakeUpReason::SubscriptionDead, _) => {
864
                    // Recreate the channel.
865
0
                    log!(
866
0
                        &self.platform,
867
                        Debug,
868
0
                        &self.log_target,
869
                        "relay-chain-subscription-reset"
870
                    );
871
0
                    self.subscription_state = ParachainBackgroundState::NotSubscribed {
872
0
                        all_subscriptions: Vec::new(),
873
                        subscribe_future: {
874
0
                            let relay_chain_sync = self.relay_chain_sync.clone();
875
0
                            Box::pin(async move {
876
0
                                relay_chain_sync
877
0
                                    .subscribe_all(32, NonZero::<usize>::new(usize::MAX).unwrap())
878
0
                                    .await
879
0
                            })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sk_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sk_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sk_0Ba_
880
                        },
881
                    };
882
                }
883
884
                (
885
                    WakeUpReason::ParaheadFetchFinished {
886
0
                        async_op_id,
887
0
                        parahead_result: Ok(parahead),
888
                    },
889
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
890
                ) => {
891
                    // A parahead fetching operation is successful.
892
0
                    log!(
893
0
                        &self.platform,
894
                        Debug,
895
0
                        &self.log_target,
896
                        "parahead-fetch-operation-success",
897
0
                        parahead_hash = HashDisplay(
898
0
                            blake2_rfc::blake2b::blake2b(32, b"", &parahead).as_bytes()
899
0
                        ),
900
0
                        relay_blocks = runtime_subscription
901
0
                            .async_tree
902
0
                            .async_op_blocks(async_op_id)
903
0
                            .map(|b| HashDisplay(b))
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sr_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sr_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sr_0Ba_
904
0
                            .join(",")
905
                    );
906
907
                    // Unpin the relay blocks whose parahead is now known.
908
0
                    for block in runtime_subscription
909
0
                        .async_tree
910
0
                        .async_op_finished(async_op_id, Some(parahead))
911
                    {
912
0
                        let hash = &runtime_subscription.async_tree[block];
913
0
                        runtime_subscription
914
0
                            .relay_chain_subscribe_all
915
0
                            .unpin_block(*hash)
916
0
                            .await;
917
                    }
918
919
0
                    runtime_subscription.must_process_sync_tree = true;
920
921
0
                    runtime_subscription.next_start_parahead_fetch = Box::pin(future::ready(()));
922
                }
923
924
                (
925
                    WakeUpReason::ParaheadFetchFinished {
926
                        parahead_result:
927
                            Err(ParaheadError::PinRuntimeError(
928
                                runtime_service::PinPinnedBlockRuntimeError::ObsoleteSubscription,
929
                            )),
930
                        ..
931
                    },
932
                    _,
933
                ) => {
934
                    // The relay chain runtime service has some kind of gap or issue and has
935
                    // discarded the runtime.
936
                    // Destroy the subscription and recreate the channels.
937
0
                    log!(
938
0
                        &self.platform,
939
                        Debug,
940
0
                        &self.log_target,
941
                        "relay-chain-subscription-reset"
942
                    );
943
0
                    self.subscription_state = ParachainBackgroundState::NotSubscribed {
944
0
                        all_subscriptions: Vec::new(),
945
                        subscribe_future: {
946
0
                            let relay_chain_sync = self.relay_chain_sync.clone();
947
0
                            Box::pin(async move {
948
0
                                relay_chain_sync
949
0
                                    .subscribe_all(32, NonZero::<usize>::new(usize::MAX).unwrap())
950
0
                                    .await
951
0
                            })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sl_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sl_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sl_0Ba_
952
                        },
953
                    };
954
                }
955
956
                (
957
                    WakeUpReason::ParaheadFetchFinished {
958
0
                        async_op_id,
959
0
                        parahead_result: Err(error),
960
                    },
961
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
962
                ) => {
963
                    // Failed fetching a parahead.
964
965
                    // Several relay chains initially didn't support parachains, and have later
966
                    // been upgraded to support them. Similarly, the parachain might not have had a
967
                    // core on the relay chain until recently. For these reasons, errors when the
968
                    // relay chain is not near head of the chain are most likely normal and do
969
                    // not warrant logging an error.
970
                    // Note that `is_near_head_of_chain_heuristic` is normally not acceptable to
971
                    // use due to being too vague, but since this is just about whether to print a
972
                    // log message, it's completely fine.
973
0
                    if self
974
0
                        .relay_chain_sync
975
0
                        .is_near_head_of_chain_heuristic()
976
0
                        .await
977
0
                        && !error.is_network_problem()
978
                    {
979
0
                        log!(
980
0
                            &self.platform,
981
                            Error,
982
0
                            &self.log_target,
983
0
                            format!(
984
0
                                "Failed to fetch the parachain head from relay chain blocks {}: {}",
985
0
                                runtime_subscription
986
0
                                    .async_tree
987
0
                                    .async_op_blocks(async_op_id)
988
0
                                    .map(|b| HashDisplay(b))
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0ss_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0ss_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0ss_0Ba_
989
0
                                    .join(", "),
990
                                error
991
                            )
992
                        );
993
0
                    }
994
995
0
                    log!(
996
0
                        &self.platform,
997
                        Debug,
998
0
                        &self.log_target,
999
                        "parahead-fetch-operation-error",
1000
0
                        relay_blocks = runtime_subscription
1001
0
                            .async_tree
1002
0
                            .async_op_blocks(async_op_id)
1003
0
                            .map(|b| HashDisplay(b))
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0st_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0st_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0st_0Ba_
1004
0
                            .join(","),
1005
                        ?error
1006
                    );
1007
1008
0
                    runtime_subscription
1009
0
                        .async_tree
1010
0
                        .async_op_failure(async_op_id, &self.platform.now());
1011
1012
0
                    runtime_subscription.next_start_parahead_fetch = Box::pin(future::ready(()));
1013
                }
1014
1015
                (
1016
                    WakeUpReason::ForegroundMessage(ToBackground::IsNearHeadOfChainHeuristic {
1017
0
                        send_back,
1018
                    }),
1019
0
                    ParachainBackgroundState::Subscribed(sub),
1020
0
                ) if sub.async_tree.output_finalized_async_user_data().is_some() => {
1021
                    // Since there is a mapping between relay chain blocks and parachain blocks,
1022
                    // whether a parachain is at the head of the chain is the same thing as whether
1023
                    // its relay chain is at the head of the chain.
1024
                    // Note that there is no ordering guarantee of any kind w.r.t. block
1025
                    // subscriptions notifications.
1026
0
                    let val = self
1027
0
                        .relay_chain_sync
1028
0
                        .is_near_head_of_chain_heuristic()
1029
0
                        .await;
1030
0
                    let _ = send_back.send(val);
1031
                }
1032
1033
                (
1034
                    WakeUpReason::ForegroundMessage(ToBackground::IsNearHeadOfChainHeuristic {
1035
0
                        send_back,
1036
                    }),
1037
                    _,
1038
0
                ) => {
1039
0
                    // If no finalized parahead is known yet, we might be very close to the head
1040
0
                    // but also maybe very very far away. We lean on the cautious side and always
1041
0
                    // return `false`.
1042
0
                    let _ = send_back.send(false);
1043
0
                }
1044
1045
                (
1046
                    WakeUpReason::ForegroundMessage(ToBackground::SubscribeAll {
1047
0
                        send_back,
1048
0
                        buffer_size,
1049
                        ..
1050
                    }),
1051
                    ParachainBackgroundState::NotSubscribed {
1052
0
                        all_subscriptions, ..
1053
                    },
1054
0
                ) => {
1055
0
                    let (tx, new_blocks) = async_channel::bounded(buffer_size.saturating_sub(1));
1056
0
1057
0
                    // No known finalized parahead.
1058
0
                    let _ = send_back.send(super::SubscribeAll {
1059
0
                        finalized_block_scale_encoded_header: self
1060
0
                            .obsolete_finalized_parahead
1061
0
                            .clone(),
1062
0
                        finalized_block_runtime: None,
1063
0
                        non_finalized_blocks_ancestry_order: Vec::new(),
1064
0
                        new_blocks,
1065
0
                    });
1066
0
1067
0
                    all_subscriptions.push(tx);
1068
0
                }
1069
1070
                (
1071
                    WakeUpReason::ForegroundMessage(ToBackground::SubscribeAll {
1072
0
                        send_back,
1073
0
                        buffer_size,
1074
                        ..
1075
                    }),
1076
0
                    ParachainBackgroundState::Subscribed(runtime_subscription),
1077
                ) => {
1078
0
                    let (tx, new_blocks) = async_channel::bounded(buffer_size.saturating_sub(1));
1079
1080
                    // There are two possibilities here: either we know of any recent finalized
1081
                    // parahead, or we don't. In case where we don't know of any finalized parahead
1082
                    // yet, we report a single obsolete finalized parahead, which is
1083
                    // `obsolete_finalized_parahead`. The rest of this module makes sure that no
1084
                    // other block is reported to subscriptions as long as this is the case, and
1085
                    // that subscriptions are reset once the first known finalized parahead
1086
                    // is known.
1087
0
                    if let Some(finalized_parahead) = runtime_subscription
1088
0
                        .async_tree
1089
0
                        .output_finalized_async_user_data()
1090
                    {
1091
                        // Finalized parahead is known.
1092
0
                        let finalized_parahash =
1093
0
                            header::hash_from_scale_encoded_header(finalized_parahead);
1094
0
                        let _ = send_back.send(super::SubscribeAll {
1095
0
                            finalized_block_scale_encoded_header: finalized_parahead.clone(),
1096
0
                            finalized_block_runtime: None,
1097
                            non_finalized_blocks_ancestry_order: {
1098
0
                                let mut list =
1099
0
                                    Vec::<([u8; 32], super::BlockNotification)>::with_capacity(
1100
0
                                        runtime_subscription
1101
0
                                            .async_tree
1102
0
                                            .num_input_non_finalized_blocks(),
1103
                                    );
1104
1105
0
                                for relay_block in runtime_subscription
1106
0
                                    .async_tree
1107
0
                                    .input_output_iter_ancestry_order()
1108
                                {
1109
0
                                    let parablock = match relay_block.async_op_user_data {
1110
0
                                        Some(b) => b.as_ref().unwrap(),
1111
0
                                        None => continue,
1112
                                    };
1113
1114
0
                                    let parablock_hash =
1115
0
                                        header::hash_from_scale_encoded_header(parablock);
1116
1117
                                    // TODO: O(n)
1118
0
                                    if let Some((_, entry)) =
1119
0
                                        list.iter_mut().find(|(h, _)| *h == parablock_hash)
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sm_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sm_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sm_0Ba_
1120
                                    {
1121
                                        // Block is already in the list. Don't add it a second time.
1122
0
                                        if relay_block.is_output_best {
1123
0
                                            entry.is_new_best = true;
1124
0
                                        }
1125
0
                                        continue;
1126
0
                                    }
1127
1128
                                    // Find the parent of the parablock. This is done by going through
1129
                                    // the ancestors of the corresponding relay chain block (until and
1130
                                    // including the finalized relay chain block) until we find one
1131
                                    // whose parablock is different from the parablock in question.
1132
                                    // If none is found, the parablock is the same as the finalized
1133
                                    // parablock.
1134
0
                                    let parent_hash = runtime_subscription
1135
0
                                        .async_tree
1136
0
                                        .ancestors(relay_block.id)
1137
0
                                        .find_map(|idx| {
1138
0
                                            let hash = header::hash_from_scale_encoded_header(
1139
0
                                                runtime_subscription
1140
0
                                                    .async_tree
1141
0
                                                    .block_async_user_data(idx)
1142
0
                                                    .unwrap()
1143
0
                                                    .as_ref()
1144
0
                                                    .unwrap(),
1145
                                            );
1146
0
                                            if hash != parablock_hash {
1147
0
                                                Some(hash)
1148
                                            } else {
1149
0
                                                None
1150
                                            }
1151
0
                                        })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sn_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sn_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sn_0Ba_
1152
0
                                        .or_else(|| {
1153
0
                                            if finalized_parahash != parablock_hash {
1154
0
                                                Some(finalized_parahash)
1155
                                            } else {
1156
0
                                                None
1157
                                            }
1158
0
                                        });
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0so_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0so_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0so_0Ba_
1159
1160
                                    // `parent_hash` is `None` if the parablock is
1161
                                    // the same as the finalized parablock, in which case we
1162
                                    // don't add it to the list.
1163
0
                                    if let Some(parent_hash) = parent_hash {
1164
0
                                        debug_assert!(
1165
0
                                            list.iter().filter(|(h, _)| *h == parent_hash).count()
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0su_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0su_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0su_0Ba_
1166
                                                == 1
1167
0
                                                || parent_hash == finalized_parahash
1168
                                        );
1169
0
                                        list.push((
1170
0
                                            parablock_hash,
1171
0
                                            super::BlockNotification {
1172
0
                                                is_new_best: relay_block.is_output_best,
1173
0
                                                scale_encoded_header: parablock.clone(),
1174
0
                                                parent_hash,
1175
0
                                            },
1176
0
                                        ));
1177
0
                                    }
1178
                                }
1179
1180
0
                                list.into_iter().map(|(_, v)| v).collect()
1181
                            },
1182
0
                            new_blocks,
1183
                        });
1184
0
                    } else {
1185
0
                        // No known finalized parahead.
1186
0
                        let _ = send_back.send(super::SubscribeAll {
1187
0
                            finalized_block_scale_encoded_header: self
1188
0
                                .obsolete_finalized_parahead
1189
0
                                .clone(),
1190
0
                            finalized_block_runtime: None,
1191
0
                            non_finalized_blocks_ancestry_order: Vec::new(),
1192
0
                            new_blocks,
1193
0
                        });
1194
0
                    }
1195
1196
0
                    runtime_subscription.all_subscriptions.push(tx);
1197
                }
1198
1199
                (
1200
                    WakeUpReason::ForegroundMessage(ToBackground::PeersAssumedKnowBlock {
1201
0
                        send_back,
1202
                        ..
1203
                    }),
1204
                    _,
1205
0
                ) => {
1206
0
                    // Simply assume that all peers know about all blocks.
1207
0
                    //
1208
0
                    // We could in principle check whether the block is higher than the current
1209
0
                    // finalized block, and if not if it is in the list of paraheads found in the
1210
0
                    // relay chain. But because parachain blocks might not be decodable, we can't
1211
0
                    // know their number, and thus we can't know if the requested block is a
1212
0
                    // descendant of the finalized block.
1213
0
                    // Assuming that all peers know all blocks is the only sane way of
1214
0
                    // implementing this.
1215
0
                    let _ = send_back.send(self.sync_sources.keys().cloned().collect());
1216
0
                }
1217
1218
0
                (WakeUpReason::ForegroundMessage(ToBackground::SyncingPeers { send_back }), _) => {
1219
0
                    let _ = send_back.send(
1220
0
                        self.sync_sources
1221
0
                            .iter()
1222
0
                            .map(|(peer_id, (role, best_height, best_hash))| {
1223
                                //let (height, hash) = self.sync_sources.best_block(local_id);
1224
0
                                (peer_id.clone(), *role, *best_height, *best_hash)
1225
0
                            })
Unexecuted instantiation: _RNCNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sq_0Ba_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0sq_0B1A_
Unexecuted instantiation: _RNCNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB6_23ParachainBackgroundTaskpE3run0sq_0Ba_
1226
0
                            .collect(),
1227
                    );
1228
                }
1229
1230
                (
1231
                    WakeUpReason::ForegroundMessage(ToBackground::SerializeChainInformation {
1232
0
                        send_back,
1233
                    }),
1234
                    _,
1235
0
                ) => {
1236
0
                    let _ = send_back.send(None);
1237
0
                }
1238
1239
                (WakeUpReason::MustSubscribeNetworkEvents, _) => {
1240
0
                    debug_assert!(self.from_network_service.is_none());
1241
0
                    self.sync_sources.clear();
1242
0
                    self.from_network_service = Some(Box::pin(
1243
                        // As documented, `subscribe().await` is expected to return quickly.
1244
0
                        self.network_service.subscribe().await,
1245
                    ));
1246
                }
1247
1248
                (
1249
                    WakeUpReason::NetworkEvent(network_service::Event::Connected {
1250
0
                        peer_id,
1251
0
                        role,
1252
0
                        best_block_number,
1253
0
                        best_block_hash,
1254
                    }),
1255
                    _,
1256
                ) => {
1257
0
                    let _former_value = self
1258
0
                        .sync_sources
1259
0
                        .insert(peer_id, (role, best_block_number, best_block_hash));
1260
0
                    debug_assert!(_former_value.is_none());
1261
                }
1262
1263
                (
1264
0
                    WakeUpReason::NetworkEvent(network_service::Event::Disconnected { peer_id }),
1265
                    _,
1266
                ) => {
1267
0
                    let _role = self.sync_sources.remove(&peer_id);
1268
0
                    debug_assert!(_role.is_some());
1269
                }
1270
1271
                (
1272
                    WakeUpReason::NetworkEvent(network_service::Event::BlockAnnounce {
1273
0
                        peer_id: _peer_id,
1274
                        ..
1275
                    }),
1276
                    _,
1277
                ) => {
1278
0
                    debug_assert!(self.sync_sources.contains_key(&_peer_id));
1279
                }
1280
1281
0
                (WakeUpReason::NetworkEvent(_), _) => {
1282
0
                    // Uninteresting message.
1283
0
                }
1284
1285
                (
1286
                    WakeUpReason::ParaheadFetchFinished { .. }
1287
                    | WakeUpReason::AdvanceSyncTree
1288
                    | WakeUpReason::Notification(_)
1289
                    | WakeUpReason::StartParaheadFetch,
1290
                    ParachainBackgroundState::NotSubscribed { .. },
1291
                ) => {
1292
                    // These paths are unreachable.
1293
0
                    debug_assert!(false);
1294
                }
1295
            }
1296
        }
1297
0
    }
Unexecuted instantiation: _RNCNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainINtB4_23ParachainBackgroundTaskpE3run0B8_
Unexecuted instantiation: _RNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB4_23ParachainBackgroundTaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE3run0B1y_
Unexecuted instantiation: _RNCNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainINtB4_23ParachainBackgroundTaskpE3run0B8_
1298
}
1299
1300
0
async fn fetch_parahead<TPlat: PlatformRef>(
1301
0
    relay_chain_sync: &Arc<runtime_service::RuntimeService<TPlat>>,
1302
0
    subscription_id: runtime_service::SubscriptionId,
1303
0
    parachain_id: u32,
1304
0
    block_hash: &[u8; 32],
1305
0
) -> Result<Vec<u8>, ParaheadError> {
Unexecuted instantiation: _RINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain14fetch_paraheadpEB6_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEB1h_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadpEB6_
1306
    // Call `ParachainHost_persisted_validation_data` in order to know where the parachain is.
1307
0
    let (pinned_runtime, block_state_trie_root, block_number) = relay_chain_sync
1308
0
        .pin_pinned_block_runtime(subscription_id, *block_hash)
1309
0
        .await
1310
0
        .map_err(ParaheadError::PinRuntimeError)?;
1311
0
    let success = relay_chain_sync
1312
0
        .runtime_call(
1313
0
            pinned_runtime,
1314
0
            *block_hash,
1315
0
            block_number,
1316
0
            block_state_trie_root,
1317
0
            para::PERSISTED_VALIDATION_FUNCTION_NAME.to_owned(),
1318
0
            None, // TODO: /!\
1319
0
            para::persisted_validation_data_parameters(
1320
0
                parachain_id,
1321
0
                para::OccupiedCoreAssumption::TimedOut,
1322
            )
1323
0
            .fold(Vec::new(), |mut a, b| {
1324
0
                a.extend_from_slice(b.as_ref());
1325
0
                a
1326
0
            }),
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain14fetch_paraheadpE00Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE00B1l_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadpE00Ba_
1327
            6,
1328
0
            Duration::from_secs(10),
1329
0
            NonZero::<u32>::new(2).unwrap(),
1330
        )
1331
0
        .await
1332
0
        .map_err(ParaheadError::RuntimeCall)?;
1333
1334
    // Try decode the result of the runtime call.
1335
    // If this fails, it indicates an incompatibility between smoldot and the relay chain.
1336
0
    match para::decode_persisted_validation_data_return_value(
1337
0
        &success.output,
1338
0
        relay_chain_sync.block_number_bytes(),
1339
    ) {
1340
0
        Ok(Some(pvd)) => Ok(pvd.parent_head.to_vec()),
1341
0
        Ok(None) => Err(ParaheadError::NoCore),
1342
0
        Err(error) => Err(ParaheadError::InvalidRuntimeOutput(error)),
1343
    }
1344
0
}
Unexecuted instantiation: _RNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachain14fetch_paraheadpE0B8_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0B1j_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachain14fetch_paraheadpE0B8_
1345
1346
/// Error that can happen when fetching the parachain head corresponding to a relay chain block.
1347
#[derive(Debug, derive_more::Display, derive_more::Error)]
1348
enum ParaheadError {
1349
    /// Error while performing call request over the network.
1350
    #[display("Error while performing call request over the network: {_0}")]
1351
    RuntimeCall(runtime_service::RuntimeCallError),
1352
    /// Error pinning the runtime of the block.
1353
    PinRuntimeError(runtime_service::PinPinnedBlockRuntimeError),
1354
    /// Parachain doesn't have a core in the relay chain.
1355
    NoCore,
1356
    /// Error while decoding the output of the call.
1357
    ///
1358
    /// This indicates some kind of incompatibility between smoldot and the relay chain.
1359
    #[display("Error while decoding the output of the call: {_0}")]
1360
    InvalidRuntimeOutput(para::Error),
1361
}
1362
1363
impl ParaheadError {
1364
    /// Returns `true` if this is caused by networking issues, as opposed to a consensus-related
1365
    /// issue.
1366
0
    fn is_network_problem(&self) -> bool {
1367
0
        match self {
1368
0
            ParaheadError::RuntimeCall(runtime_service::RuntimeCallError::Inaccessible(_)) => true,
1369
            ParaheadError::RuntimeCall(
1370
                runtime_service::RuntimeCallError::Execution(_)
1371
                | runtime_service::RuntimeCallError::Crash
1372
                | runtime_service::RuntimeCallError::InvalidRuntime(_)
1373
                | runtime_service::RuntimeCallError::ApiVersionRequirementUnfulfilled,
1374
0
            ) => false,
1375
0
            ParaheadError::PinRuntimeError(_) => false,
1376
0
            ParaheadError::NoCore => false,
1377
0
            ParaheadError::InvalidRuntimeOutput(_) => false,
1378
        }
1379
0
    }
Unexecuted instantiation: _RNvMs_NtNtCsgnEOxJmACC4_13smoldot_light12sync_service9parachainNtB4_13ParaheadError18is_network_problem
Unexecuted instantiation: _RNvMs_NtNtCs508CmrSPkZh_13smoldot_light12sync_service9parachainNtB4_13ParaheadError18is_network_problem
1380
}