Coverage Report

Created: 2024-05-16 12:16

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