Coverage Report

Created: 2025-07-01 09:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/light-base/src/sync_service/standalone.rs
Line
Count
Source
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
use super::{
19
    BlockNotification, ConfigRelayChainRuntimeCodeHint, FinalizedBlockRuntime, Notification,
20
    SubscribeAll, ToBackground,
21
};
22
use crate::{log, network_service, platform::PlatformRef, util};
23
24
use alloc::{
25
    borrow::{Cow, ToOwned as _},
26
    boxed::Box,
27
    format,
28
    string::String,
29
    sync::Arc,
30
    vec::Vec,
31
};
32
use core::{cmp, iter, num::NonZero, pin::Pin, time::Duration};
33
use futures_lite::FutureExt as _;
34
use futures_util::{FutureExt as _, StreamExt as _, future, stream};
35
use hashbrown::HashMap;
36
use smoldot::{
37
    chain, header,
38
    informant::HashDisplay,
39
    libp2p,
40
    network::{self, codec},
41
    sync::all,
42
};
43
44
/// Starts a sync service background task to synchronize a standalone chain (relay chain or not).
45
0
pub(super) async fn start_standalone_chain<TPlat: PlatformRef>(
46
0
    log_target: String,
47
0
    platform: TPlat,
48
0
    chain_information: chain::chain_information::ValidChainInformation,
49
0
    block_number_bytes: usize,
50
0
    runtime_code_hint: Option<ConfigRelayChainRuntimeCodeHint>,
51
0
    mut from_foreground: Pin<Box<async_channel::Receiver<ToBackground>>>,
52
0
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
53
0
) {
Unexecuted instantiation: _RINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpEB6_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEB1r_
Unexecuted instantiation: _RINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpEB6_
54
0
    let mut task = Task {
55
0
        sync: Some(all::AllSync::new(all::Config {
56
0
            chain_information,
57
0
            block_number_bytes,
58
            // Since this module doesn't verify block bodies, any block (even invalid) is accepted
59
            // as long as it comes from a legitimate validator. Consequently, validators could
60
            // perform attacks by sending completely invalid blocks. Passing `false` to this
61
            // option would tighten the definition of what a "legitimate" validator is, and thus
62
            // reduce the feasibility of attacks, but not in a significant way. Passing `true`,
63
            // on the other hand, allows supporting chains that use custom consensus engines,
64
            // which is considered worth the trade-off.
65
            allow_unknown_consensus_engines: true,
66
            sources_capacity: 32,
67
            blocks_capacity: {
68
                // This is the maximum number of blocks between two consecutive justifications.
69
0
                1024
70
            },
71
            max_disjoint_headers: 1024,
72
0
            max_requests_per_block: NonZero::<u32>::new(3).unwrap(),
73
            download_ahead_blocks: {
74
                // Verifying a block mostly consists in:
75
                //
76
                // - Verifying a sr25519 signature for each block, plus a VRF output when the
77
                // block is claiming a primary BABE slot.
78
                // - Verifying one ed25519 signature per authority for every justification.
79
                //
80
                // At the time of writing, the speed of these operations hasn't been benchmarked.
81
                // It is likely that it varies quite a bit between the various environments (the
82
                // different browser engines, and NodeJS).
83
                //
84
                // Assuming a maximum verification speed of 5k blocks/sec and a 95% latency of one
85
                // second, the number of blocks to download ahead of time in order to not block
86
                // is 5k.
87
0
                NonZero::<u32>::new(5000).unwrap()
88
            },
89
            download_bodies: false,
90
            download_all_chain_information_storage_proofs: false,
91
0
            code_trie_node_hint: runtime_code_hint.map(|hint| all::ConfigCodeTrieNodeHint {
92
0
                merkle_value: hint.merkle_value,
93
0
                storage_value: hint.storage_value,
94
0
                closest_ancestor_excluding: hint.closest_ancestor_excluding,
95
0
            }),
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE00Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE00B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE00Ba_
96
        })),
97
        network_up_to_date_best: true,
98
        network_up_to_date_finalized: true,
99
0
        known_finalized_runtime: None,
100
0
        pending_requests: stream::FuturesUnordered::new(),
101
0
        warp_sync_taking_long_time_warning: future::Either::Left(Box::pin(
102
0
            platform.sleep(Duration::from_secs(10)),
103
0
        ))
104
0
        .fuse(),
105
0
        all_notifications: Vec::<async_channel::Sender<Notification>>::new(),
106
0
        log_target,
107
0
        from_network_service: None,
108
0
        network_service,
109
0
        peers_source_id_map: HashMap::with_capacity_and_hasher(
110
            0,
111
0
            util::SipHasherBuild::new({
112
0
                let mut seed = [0; 16];
113
0
                platform.fill_random_bytes(&mut seed);
114
0
                seed
115
            }),
116
        ),
117
0
        platform,
118
    };
119
120
    // Main loop of the syncing logic.
121
    //
122
    // This loop contains some CPU-heavy operations (e.g. verifying finality proofs and warp sync
123
    // proofs) but also responding to messages sent by the foreground sync service. In order to
124
    // avoid long delays in responding to foreground messages, the CPU-heavy operations are split
125
    // into small chunks, and each iteration of the loop processes at most one of these chunks and
126
    // processes one foreground message.
127
    loop {
128
        // Yield at every loop in order to provide better tasks granularity.
129
0
        futures_lite::future::yield_now().await;
130
131
        // Now waiting for some event to happen: a network event, a request from the frontend
132
        // of the sync service, or a request being finished.
133
        enum WakeUpReason {
134
            SyncProcess(all::ProcessOne<future::AbortHandle, (libp2p::PeerId, codec::Role), ()>),
135
            MustUpdateNetworkWithBestBlock,
136
            MustUpdateNetworkWithFinalizedBlock,
137
            MustSubscribeNetworkEvents,
138
            NetworkEvent(network_service::Event),
139
            ForegroundMessage(ToBackground),
140
            ForegroundClosed,
141
            StartRequest(all::SourceId, all::DesiredRequest),
142
            ObsoleteRequest(all::RequestId),
143
            RequestFinished(all::RequestId, Result<RequestOutcome, future::Aborted>),
144
            WarpSyncTakingLongTimeWarning,
145
        }
146
147
0
        let wake_up_reason = {
148
0
            async {
149
0
                if let Some(from_network_service) = task.from_network_service.as_mut() {
150
0
                    match from_network_service.next().await {
151
0
                        Some(ev) => WakeUpReason::NetworkEvent(ev),
152
                        None => {
153
0
                            task.from_network_service = None;
154
0
                            WakeUpReason::MustSubscribeNetworkEvents
155
                        }
156
                    }
157
                } else {
158
0
                    WakeUpReason::MustSubscribeNetworkEvents
159
                }
160
0
            }
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s_0Ba_
161
0
            .or(async {
162
0
                from_foreground.next().await.map_or(
163
0
                    WakeUpReason::ForegroundClosed,
164
                    WakeUpReason::ForegroundMessage,
165
                )
166
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s0_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s0_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s0_0Ba_
167
0
            .or(async {
168
0
                if task.pending_requests.is_empty() {
169
0
                    future::pending::<()>().await
170
0
                }
171
0
                let (request_id, result) = task.pending_requests.select_next_some().await;
172
0
                WakeUpReason::RequestFinished(request_id, result)
173
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s1_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s1_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s1_0Ba_
174
0
            .or(async {
175
0
                if !task.network_up_to_date_finalized {
176
0
                    WakeUpReason::MustUpdateNetworkWithFinalizedBlock
177
                } else {
178
0
                    future::pending().await
179
                }
180
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s2_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s2_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s2_0Ba_
181
0
            .or(async {
182
0
                if !task.network_up_to_date_best {
183
0
                    WakeUpReason::MustUpdateNetworkWithBestBlock
184
                } else {
185
0
                    future::pending().await
186
                }
187
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s3_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s3_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s3_0Ba_
188
0
            .or(async {
189
0
                (&mut task.warp_sync_taking_long_time_warning).await;
190
0
                task.warp_sync_taking_long_time_warning =
191
0
                    future::Either::Left(Box::pin(task.platform.sleep(Duration::from_secs(10))))
192
0
                        .fuse();
193
0
                WakeUpReason::WarpSyncTakingLongTimeWarning
194
0
            })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s4_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s4_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s4_0Ba_
195
0
            .or({
196
0
                let sync = &mut task.sync;
197
0
                async move {
198
                    // `desired_requests()` returns, in decreasing order of priority, the requests
199
                    // that should be started in order for the syncing to proceed. The fact that
200
                    // multiple requests are returned could be used to filter out undesired one. We
201
                    // use this filtering to enforce a maximum of one ongoing request per source.
202
0
                    let Some(s) = &sync else { unreachable!() };
203
0
                    if let Some((source_id, _, request_detail)) = s
204
0
                        .desired_requests()
205
0
                        .find(|(source_id, _, _)| s.source_num_ongoing_requests(*source_id) == 0)
Unexecuted instantiation: _RNCNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s5_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s5_00B1x_
Unexecuted instantiation: _RNCNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s5_00Bc_
206
                    {
207
0
                        return WakeUpReason::StartRequest(source_id, request_detail);
208
0
                    }
209
210
                    // There might be requests that are no longer necessary for a reason or
211
                    // another.
212
0
                    if let Some(request_id) = s.obsolete_requests().next() {
213
0
                        return WakeUpReason::ObsoleteRequest(request_id);
214
0
                    }
215
216
                    // TODO: eventually, process_one() shouldn't take ownership of the AllForks
217
0
                    match sync.take().unwrap_or_else(|| unreachable!()).process_one() {
218
0
                        all::ProcessOne::AllSync(idle) => {
219
0
                            *sync = Some(idle);
220
0
                            future::pending().await
221
                        }
222
0
                        other => WakeUpReason::SyncProcess(other),
223
                    }
224
0
                }
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s5_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s5_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s5_0Ba_
225
            })
226
0
            .await
227
        };
228
229
0
        match wake_up_reason {
230
            WakeUpReason::SyncProcess(all::ProcessOne::AllSync(_)) => {
231
                // Shouldn't be reachable.
232
0
                unreachable!()
233
            }
234
235
0
            WakeUpReason::SyncProcess(all::ProcessOne::WarpSyncBuildRuntime(req)) => {
236
                // Warp syncing compiles the runtime. The compiled runtime will later be yielded
237
                // in the `WarpSyncFinished` variant, which is then provided as an event.
238
0
                let before_instant = task.platform.now();
239
                // Because the runtime being compiled has been validated by 2/3rds of the
240
                // validators of the chain, we can assume that it is valid. Doing so significantly
241
                // increases the compilation speed.
242
0
                let (new_sync, error) =
243
0
                    req.build(all::ExecHint::CompileWithNonDeterministicValidation, true);
244
0
                let elapsed = task.platform.now() - before_instant;
245
0
                match error {
246
0
                    Ok(()) => {
247
0
                        log!(
248
0
                            &task.platform,
249
0
                            Debug,
250
0
                            &task.log_target,
251
0
                            "warp-sync-runtime-build-success",
252
0
                            success = ?true,
253
0
                            duration = ?elapsed
254
0
                        );
255
0
                    }
256
0
                    Err(error) => {
257
0
                        log!(
258
0
                            &task.platform,
259
                            Debug,
260
0
                            &task.log_target,
261
                            "warp-sync-runtime-build-error",
262
                            ?error
263
                        );
264
0
                        if !matches!(error, all::WarpSyncBuildRuntimeError::SourceMisbehavior(_)) {
265
0
                            log!(
266
0
                                &task.platform,
267
0
                                Debug,
268
0
                                &task.log_target,
269
0
                                format!(
270
0
                                    "Failed to compile runtime during warp syncing process: {}",
271
0
                                    error
272
0
                                )
273
0
                            );
274
0
                        }
275
                    }
276
                };
277
0
                task.sync = Some(new_sync);
278
            }
279
280
0
            WakeUpReason::SyncProcess(all::ProcessOne::WarpSyncBuildChainInformation(req)) => {
281
0
                let (new_sync, error) = req.build();
282
0
                match error {
283
0
                    Ok(()) => {
284
0
                        log!(
285
0
                            &task.platform,
286
0
                            Debug,
287
0
                            &task.log_target,
288
0
                            "warp-sync-chain-information-build-success"
289
0
                        );
290
0
                    }
291
0
                    Err(error) => {
292
0
                        log!(
293
0
                            &task.platform,
294
                            Debug,
295
0
                            &task.log_target,
296
                            "warp-sync-chain-information-build-error",
297
                            ?error
298
                        );
299
0
                        if !matches!(
300
0
                            error,
301
                            all::WarpSyncBuildChainInformationError::SourceMisbehavior(_)
302
0
                        ) {
303
0
                            log!(
304
0
                                &task.platform,
305
0
                                Warn,
306
0
                                &task.log_target,
307
0
                                format!(
308
0
                                    "Failed to build the chain information during warp syncing process: {}",
309
0
                                    error
310
0
                                )
311
0
                            );
312
0
                        }
313
                    }
314
                };
315
0
                task.sync = Some(new_sync);
316
            }
317
318
            WakeUpReason::SyncProcess(all::ProcessOne::WarpSyncFinished {
319
0
                sync,
320
0
                finalized_block_runtime,
321
0
                finalized_storage_code,
322
0
                finalized_storage_code_closest_ancestor_excluding,
323
0
                finalized_storage_heap_pages,
324
0
                finalized_storage_code_merkle_value,
325
                finalized_body: _,
326
0
            }) => {
327
0
                log!(
328
0
                    &task.platform,
329
0
                    Debug,
330
0
                    &task.log_target,
331
0
                    format!(
332
0
                        "GrandPa warp sync finished to #{} ({})",
333
0
                        sync.finalized_block_number(),
334
0
                        HashDisplay(sync.finalized_block_hash())
335
0
                    )
336
0
                );
337
0
338
0
                task.sync = Some(sync);
339
0
340
0
                task.warp_sync_taking_long_time_warning =
341
0
                    future::Either::Right(future::pending()).fuse();
342
0
343
0
                task.known_finalized_runtime = Some(FinalizedBlockRuntime {
344
0
                    virtual_machine: finalized_block_runtime,
345
0
                    storage_code: finalized_storage_code,
346
0
                    storage_heap_pages: finalized_storage_heap_pages,
347
0
                    code_merkle_value: finalized_storage_code_merkle_value,
348
0
                    closest_ancestor_excluding: finalized_storage_code_closest_ancestor_excluding,
349
0
                });
350
0
351
0
                task.network_up_to_date_finalized = false;
352
0
                task.network_up_to_date_best = false;
353
0
                // Since there is a gap in the blocks, all active notifications to all blocks
354
0
                // must be cleared.
355
0
                task.all_notifications.clear();
356
0
            }
357
358
0
            WakeUpReason::SyncProcess(all::ProcessOne::VerifyWarpSyncFragment(verify)) => {
359
                // Grandpa warp sync fragment to verify.
360
0
                let sender_if_still_connected = verify
361
0
                    .proof_sender()
362
0
                    .map(|(_, (peer_id, _))| peer_id.clone());
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s6_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s6_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s6_0Ba_
363
364
0
                let (sync, result) = verify.perform({
365
0
                    let mut seed = [0; 32];
366
0
                    task.platform.fill_random_bytes(&mut seed);
367
0
                    seed
368
0
                });
369
0
                task.sync = Some(sync);
370
371
0
                match result {
372
0
                    Ok((fragment_hash, fragment_number)) => {
373
                        // TODO: must call `set_local_grandpa_state` and `set_local_best_block` so that other peers notify us of neighbor packets
374
0
                        log!(
375
0
                            &task.platform,
376
                            Debug,
377
0
                            &task.log_target,
378
                            "warp-sync-fragment-verify-success",
379
0
                            sender = sender_if_still_connected
380
0
                                .as_ref()
381
0
                                .map(|p| Cow::Owned(p.to_base58()))
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sy_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sy_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sy_0Ba_
382
0
                                .unwrap_or(Cow::Borrowed("<disconnected>")),
383
0
                            verified_hash = HashDisplay(&fragment_hash),
384
                            verified_height = fragment_number
385
                        );
386
                    }
387
0
                    Err(err) => {
388
0
                        log!(
389
0
                            &task.platform,
390
                            Debug,
391
0
                            &task.log_target,
392
0
                            format!(
393
0
                                "Failed to verify warp sync fragment from {}: {}{}",
394
0
                                sender_if_still_connected
395
0
                                    .as_ref()
396
0
                                    .map(|p| Cow::Owned(p.to_base58()))
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sz_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sz_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sz_0Ba_
397
0
                                    .unwrap_or(Cow::Borrowed("<disconnected>")),
398
                                err,
399
0
                                if matches!(err, all::VerifyFragmentError::JustificationVerify(_)) {
400
0
                                    ". This might be caused by a forced GrandPa authorities change having \
401
0
                                been enacted on the chain. If this is the case, please update the \
402
0
                                chain specification with a checkpoint past this forced change."
403
                                } else {
404
0
                                    ""
405
                                }
406
                            )
407
                        );
408
0
                        if let Some(sender_if_still_connected) = sender_if_still_connected {
409
0
                            task.network_service
410
0
                                .ban_and_disconnect(
411
0
                                    sender_if_still_connected,
412
0
                                    network_service::BanSeverity::High,
413
0
                                    "bad-warp-sync-fragment",
414
0
                                )
415
0
                                .await;
416
0
                        }
417
                    }
418
                }
419
            }
420
421
0
            WakeUpReason::SyncProcess(all::ProcessOne::VerifyBlock(verify)) => {
422
                // Header to verify.
423
0
                let verified_hash = verify.hash();
424
0
                match verify.verify_header(task.platform.now_from_unix_epoch()) {
425
                    all::HeaderVerifyOutcome::Success {
426
0
                        success,
427
0
                        is_new_best,
428
                        ..
429
                    } => {
430
0
                        let sync = task.sync.insert(success.finish(()));
431
432
0
                        log!(
433
0
                            &task.platform,
434
                            Debug,
435
0
                            &task.log_target,
436
                            "header-verify-success",
437
0
                            hash = HashDisplay(&verified_hash),
438
0
                            is_new_best = if is_new_best { "yes" } else { "no" }
439
                        );
440
441
0
                        if is_new_best {
442
0
                            task.network_up_to_date_best = false;
443
0
                        }
444
445
0
                        let (parent_hash, scale_encoded_header) = {
446
                            // TODO: the code below is `O(n)` complexity
447
0
                            let header = sync
448
0
                                .non_finalized_blocks_unordered()
449
0
                                .find(|h| h.hash(sync.block_number_bytes()) == verified_hash)
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s7_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s7_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s7_0Ba_
450
0
                                .unwrap();
451
0
                            (
452
0
                                *header.parent_hash,
453
0
                                header.scale_encoding_vec(sync.block_number_bytes()),
454
0
                            )
455
                        };
456
457
                        // Notify of the new block.
458
0
                        task.dispatch_all_subscribers({
459
0
                            Notification::Block(BlockNotification {
460
0
                                is_new_best,
461
0
                                scale_encoded_header,
462
0
                                parent_hash,
463
0
                            })
464
                        });
465
                    }
466
467
0
                    all::HeaderVerifyOutcome::Error { sync, error, .. } => {
468
0
                        task.sync = Some(sync);
469
0
470
0
                        // TODO: print which peer sent the header
471
0
                        log!(
472
0
                            &task.platform,
473
0
                            Debug,
474
0
                            &task.log_target,
475
0
                            "header-verify-error",
476
0
                            hash = HashDisplay(&verified_hash),
477
0
                            ?error
478
0
                        );
479
0
480
0
                        log!(
481
0
                            &task.platform,
482
0
                            Warn,
483
0
                            &task.log_target,
484
0
                            format!(
485
0
                                "Error while verifying header {}: {}",
486
0
                                HashDisplay(&verified_hash),
487
0
                                error
488
0
                            )
489
0
                        );
490
0
491
0
                        // TODO: ban peers that have announced the block
492
0
                        /*for peer_id in task.sync.knows_non_finalized_block(height, hash) {
493
0
                            task.network_service
494
0
                                .ban_and_disconnect(
495
0
                                    peer_id,
496
0
                                    network_service::BanSeverity::High,
497
0
                                    "bad-block",
498
0
                                )
499
0
                                .await;
500
0
                        }*/
501
0
                    }
502
                }
503
            }
504
505
0
            WakeUpReason::SyncProcess(all::ProcessOne::VerifyFinalityProof(verify)) => {
506
                // Finality proof to verify.
507
0
                let sender = verify.sender().1.0.clone();
508
0
                match verify.perform({
509
0
                    let mut seed = [0; 32];
510
0
                    task.platform.fill_random_bytes(&mut seed);
511
0
                    seed
512
0
                }) {
513
                    (
514
0
                        sync,
515
                        all::FinalityProofVerifyOutcome::NewFinalized {
516
0
                            updates_best_block,
517
0
                            finalized_blocks_newest_to_oldest,
518
0
                            pruned_blocks,
519
                        },
520
                    ) => {
521
0
                        log!(
522
0
                            &task.platform,
523
                            Debug,
524
0
                            &task.log_target,
525
                            "finality-proof-verify-success",
526
0
                            finalized_blocks = finalized_blocks_newest_to_oldest.len(),
527
                            sender
528
                        );
529
530
0
                        if updates_best_block {
531
0
                            task.network_up_to_date_best = false;
532
0
                        }
533
0
                        task.network_up_to_date_finalized = false;
534
                        // Invalidate the cache of the runtime of the finalized blocks if any
535
                        // of the finalized blocks indicates that a runtime update happened.
536
0
                        if finalized_blocks_newest_to_oldest.iter().any(|b| {
537
0
                            header::decode(&b.header, sync.block_number_bytes())
538
0
                                .unwrap()
539
0
                                .digest
540
0
                                .has_runtime_environment_updated()
541
0
                        }) {
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s8_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0s8_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0s8_0Ba_
542
0
                            task.known_finalized_runtime = None;
543
0
                        }
544
0
                        task.dispatch_all_subscribers(Notification::Finalized {
545
0
                            hash: *sync.finalized_block_hash(),
546
0
                            best_block_hash_if_changed: if updates_best_block {
547
0
                                Some(*sync.best_block_hash())
548
                            } else {
549
0
                                None
550
                            },
551
0
                            pruned_blocks,
552
                        });
553
554
0
                        task.sync = Some(sync);
555
                    }
556
557
                    (
558
0
                        sync,
559
                        all::FinalityProofVerifyOutcome::AlreadyFinalized
560
                        | all::FinalityProofVerifyOutcome::GrandpaCommitPending,
561
0
                    ) => {
562
0
                        task.sync = Some(sync);
563
0
                    }
564
565
0
                    (sync, all::FinalityProofVerifyOutcome::JustificationError(error)) => {
566
0
                        task.sync = Some(sync);
567
568
0
                        log!(
569
0
                            &task.platform,
570
                            Debug,
571
0
                            &task.log_target,
572
                            "finality-proof-verify-error",
573
                            ?error,
574
                            sender,
575
                        );
576
577
                        // Errors of type `JustificationEngineMismatch` indicate that the chain
578
                        // uses a finality engine that smoldot doesn't recognize. This is a benign
579
                        // error that shouldn't lead to a ban.
580
0
                        if !matches!(
581
0
                            error,
582
                            all::JustificationVerifyError::JustificationEngineMismatch
583
                        ) {
584
0
                            log!(
585
0
                                &task.platform,
586
                                Warn,
587
0
                                &task.log_target,
588
0
                                format!("Error while verifying justification: {error}")
589
                            );
590
591
0
                            task.network_service
592
0
                                .ban_and_disconnect(
593
0
                                    sender,
594
0
                                    network_service::BanSeverity::High,
595
0
                                    "bad-justification",
596
0
                                )
597
0
                                .await;
598
0
                        }
599
                    }
600
601
0
                    (sync, all::FinalityProofVerifyOutcome::GrandpaCommitError(error)) => {
602
0
                        task.sync = Some(sync);
603
604
0
                        log!(
605
0
                            &task.platform,
606
                            Debug,
607
0
                            &task.log_target,
608
                            "finality-proof-verify-error",
609
                            ?error,
610
                            sender,
611
                        );
612
613
0
                        log!(
614
0
                            &task.platform,
615
                            Warn,
616
0
                            &task.log_target,
617
0
                            format!("Error while verifying GrandPa commit: {}", error)
618
                        );
619
620
0
                        task.network_service
621
0
                            .ban_and_disconnect(
622
0
                                sender,
623
0
                                network_service::BanSeverity::High,
624
0
                                "bad-grandpa-commit",
625
0
                            )
626
0
                            .await;
627
                    }
628
                }
629
            }
630
631
            WakeUpReason::NetworkEvent(network_service::Event::Connected {
632
0
                peer_id,
633
0
                role,
634
0
                best_block_number,
635
0
                best_block_hash,
636
            }) => {
637
0
                task.peers_source_id_map.insert(
638
0
                    peer_id.clone(),
639
0
                    task.sync
640
0
                        .as_mut()
641
0
                        .unwrap_or_else(|| unreachable!())
642
0
                        .prepare_add_source(best_block_number, best_block_hash)
643
0
                        .add_source((peer_id, role), ()),
644
                );
645
            }
646
647
0
            WakeUpReason::NetworkEvent(network_service::Event::Disconnected { peer_id }) => {
648
0
                let sync_source_id = task.peers_source_id_map.remove(&peer_id).unwrap();
649
0
                let (_, requests) = task
650
0
                    .sync
651
0
                    .as_mut()
652
0
                    .unwrap_or_else(|| unreachable!())
653
0
                    .remove_source(sync_source_id);
654
655
                // The `Disconnect` network event indicates that the main notifications substream
656
                // with that peer has been closed, not necessarily that the connection as a whole
657
                // has been closed. As such, the in-progress network requests might continue if
658
                // we don't abort them.
659
0
                for (_, abort) in requests {
660
0
                    abort.abort();
661
0
                }
662
            }
663
664
            WakeUpReason::NetworkEvent(network_service::Event::BlockAnnounce {
665
0
                peer_id,
666
0
                announce,
667
            }) => {
668
0
                let sync_source_id = *task.peers_source_id_map.get(&peer_id).unwrap();
669
0
                let decoded = announce.decode();
670
671
0
                match task
672
0
                    .sync
673
0
                    .as_mut()
674
0
                    .unwrap_or_else(|| unreachable!())
675
0
                    .block_announce(
676
0
                        sync_source_id,
677
0
                        decoded.scale_encoded_header.to_owned(),
678
0
                        decoded.is_best,
679
                    ) {
680
                    all::BlockAnnounceOutcome::TooOld {
681
0
                        announce_block_height,
682
                        ..
683
0
                    } => {
684
0
                        log!(
685
0
                            &task.platform,
686
0
                            Debug,
687
0
                            &task.log_target,
688
0
                            "block-announce",
689
0
                            sender = peer_id,
690
0
                            hash = HashDisplay(&header::hash_from_scale_encoded_header(
691
0
                                decoded.scale_encoded_header
692
0
                            )),
693
0
                            height = announce_block_height,
694
0
                            is_best = decoded.is_best,
695
0
                            outcome = "older-than-finalized-block",
696
0
                        );
697
0
                    }
698
0
                    all::BlockAnnounceOutcome::AlreadyVerified(known) => {
699
0
                        log!(
700
0
                            &task.platform,
701
0
                            Debug,
702
0
                            &task.log_target,
703
0
                            "block-announce",
704
0
                            sender = peer_id,
705
0
                            hash = HashDisplay(known.hash()),
706
0
                            height = known.height(),
707
0
                            parent_hash = HashDisplay(known.parent_hash()),
708
0
                            is_best = decoded.is_best,
709
0
                            outcome = "already-verified",
710
0
                        );
711
0
                        known.update_source_and_block();
712
0
                    }
713
0
                    all::BlockAnnounceOutcome::AlreadyPending(known) => {
714
0
                        log!(
715
0
                            &task.platform,
716
0
                            Debug,
717
0
                            &task.log_target,
718
0
                            "block-announce",
719
0
                            sender = peer_id,
720
0
                            hash = HashDisplay(known.hash()),
721
0
                            height = known.height(),
722
0
                            parent_hash = HashDisplay(known.parent_hash()),
723
0
                            is_best = decoded.is_best,
724
0
                            outcome = "already-pending",
725
0
                        );
726
0
                        known.update_source_and_block();
727
0
                    }
728
0
                    all::BlockAnnounceOutcome::Unknown(unknown) => {
729
0
                        log!(
730
0
                            &task.platform,
731
0
                            Debug,
732
0
                            &task.log_target,
733
0
                            "block-announce",
734
0
                            sender = peer_id,
735
0
                            hash = HashDisplay(unknown.hash()),
736
0
                            height = unknown.height(),
737
0
                            parent_hash = HashDisplay(unknown.parent_hash()),
738
0
                            is_best = decoded.is_best,
739
0
                            outcome = "previously-unknown",
740
0
                        );
741
0
                        unknown.insert_and_update_source(());
742
0
                    }
743
0
                    all::BlockAnnounceOutcome::InvalidHeader(error) => {
744
0
                        log!(
745
0
                            &task.platform,
746
                            Debug,
747
0
                            &task.log_target,
748
                            "block-announce",
749
                            sender = peer_id,
750
0
                            hash = HashDisplay(&header::hash_from_scale_encoded_header(
751
0
                                decoded.scale_encoded_header
752
0
                            )),
753
                            is_best = decoded.is_best,
754
                            outcome = "invalid-header",
755
                            ?error,
756
                        );
757
0
                        task.network_service
758
0
                            .ban_and_disconnect(
759
0
                                peer_id,
760
0
                                network_service::BanSeverity::High,
761
0
                                "bad-block-announce",
762
0
                            )
763
0
                            .await;
764
                    }
765
                }
766
            }
767
768
            WakeUpReason::NetworkEvent(network_service::Event::GrandpaNeighborPacket {
769
0
                peer_id,
770
0
                finalized_block_height,
771
            }) => {
772
0
                let sync_source_id = *task.peers_source_id_map.get(&peer_id).unwrap();
773
0
                task.sync
774
0
                    .as_mut()
775
0
                    .unwrap_or_else(|| unreachable!())
776
0
                    .update_source_finality_state(sync_source_id, finalized_block_height);
777
            }
778
779
            WakeUpReason::NetworkEvent(network_service::Event::GrandpaCommitMessage {
780
0
                peer_id,
781
0
                message,
782
            }) => {
783
0
                let sync_source_id = *task.peers_source_id_map.get(&peer_id).unwrap();
784
0
                match task
785
0
                    .sync
786
0
                    .as_mut()
787
0
                    .unwrap_or_else(|| unreachable!())
788
0
                    .grandpa_commit_message(sync_source_id, message.into_encoded())
789
                {
790
0
                    all::GrandpaCommitMessageOutcome::Queued => {
791
0
                        // TODO: print more details?
792
0
                        log!(
793
0
                            &task.platform,
794
0
                            Debug,
795
0
                            &task.log_target,
796
0
                            "grandpa-commit-message-queued",
797
0
                            sender = peer_id
798
0
                        );
799
0
                    }
800
0
                    all::GrandpaCommitMessageOutcome::Discarded => {
801
0
                        log!(
802
0
                            &task.platform,
803
0
                            Debug,
804
0
                            &task.log_target,
805
0
                            "grandpa-commit-message-ignored",
806
0
                            sender = peer_id
807
0
                        );
808
0
                    }
809
                }
810
            }
811
812
            WakeUpReason::MustSubscribeNetworkEvents => {
813
0
                debug_assert!(task.from_network_service.is_none());
814
0
                for (_, sync_source_id) in task.peers_source_id_map.drain() {
815
0
                    let (_, requests) = task
816
0
                        .sync
817
0
                        .as_mut()
818
0
                        .unwrap_or_else(|| unreachable!())
819
0
                        .remove_source(sync_source_id);
820
0
                    for (_, abort) in requests {
821
0
                        abort.abort();
822
0
                    }
823
                }
824
0
                task.from_network_service = Some(Box::pin(
825
                    // As documented, `subscribe().await` is expected to return quickly.
826
0
                    task.network_service.subscribe().await,
827
                ));
828
            }
829
830
            WakeUpReason::MustUpdateNetworkWithBestBlock => {
831
                // The networking service needs to be kept up to date with what the local node
832
                // considers as the best block.
833
                // For some reason, first building the future then executing it solves a borrow
834
                // checker error.
835
0
                let Some(sync) = &task.sync else {
836
0
                    unreachable!()
837
                };
838
839
0
                let fut = task
840
0
                    .network_service
841
0
                    .set_local_best_block(*sync.best_block_hash(), sync.best_block_number());
842
0
                fut.await;
843
844
0
                task.network_up_to_date_best = true;
845
            }
846
847
            WakeUpReason::MustUpdateNetworkWithFinalizedBlock => {
848
                // If the chain uses GrandPa, the networking has to be kept up-to-date with the
849
                // state of finalization for other peers to send back relevant gossip messages.
850
                // (code style) `grandpa_set_id` is extracted first in order to avoid borrowing
851
                // checker issues.
852
0
                let Some(sync) = &mut task.sync else {
853
0
                    unreachable!()
854
                };
855
856
0
                let grandpa_set_id =
857
                    if let chain::chain_information::ChainInformationFinalityRef::Grandpa {
858
0
                        after_finalized_block_authorities_set_id,
859
                        ..
860
0
                    } = sync.as_chain_information().as_ref().finality
861
                    {
862
0
                        Some(after_finalized_block_authorities_set_id)
863
                    } else {
864
0
                        None
865
                    };
866
867
0
                if let Some(set_id) = grandpa_set_id {
868
0
                    task.network_service
869
0
                        .set_local_grandpa_state(network::service::GrandpaState {
870
0
                            set_id,
871
0
                            round_number: 1, // TODO:
872
0
                            commit_finalized_height: sync.finalized_block_number(),
873
0
                        })
874
0
                        .await;
875
0
                }
876
877
0
                task.network_up_to_date_finalized = true;
878
            }
879
880
            WakeUpReason::ForegroundMessage(ToBackground::IsNearHeadOfChainHeuristic {
881
0
                send_back,
882
            }) => {
883
                // Frontend is querying something.
884
0
                let _ = send_back.send(
885
0
                    task.sync
886
0
                        .as_ref()
887
0
                        .unwrap_or_else(|| unreachable!())
888
0
                        .is_near_head_of_chain_heuristic(),
889
                );
890
            }
891
892
            WakeUpReason::ForegroundMessage(ToBackground::SubscribeAll {
893
0
                send_back,
894
0
                buffer_size,
895
0
                runtime_interest,
896
            }) => {
897
                // Frontend would like to subscribe to events.
898
899
0
                let Some(sync) = &task.sync else {
900
0
                    unreachable!()
901
                };
902
903
0
                let (tx, new_blocks) = async_channel::bounded(buffer_size.saturating_sub(1));
904
0
                task.all_notifications.push(tx);
905
906
0
                let non_finalized_blocks_ancestry_order = {
907
0
                    sync.non_finalized_blocks_ancestry_order()
908
0
                        .map(|h| {
909
0
                            let scale_encoding = h.scale_encoding_vec(sync.block_number_bytes());
910
0
                            BlockNotification {
911
0
                                is_new_best: header::hash_from_scale_encoded_header(
912
0
                                    &scale_encoding,
913
0
                                ) == *sync.best_block_hash(),
914
0
                                scale_encoded_header: scale_encoding,
915
0
                                parent_hash: *h.parent_hash,
916
0
                            }
917
0
                        })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sg_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sg_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sg_0Ba_
918
0
                        .collect()
919
                };
920
921
0
                let _ = send_back.send(SubscribeAll {
922
0
                    finalized_block_scale_encoded_header: sync.finalized_block_header().to_owned(),
923
0
                    finalized_block_runtime: if runtime_interest {
924
0
                        task.known_finalized_runtime.take()
925
                    } else {
926
0
                        None
927
                    },
928
0
                    non_finalized_blocks_ancestry_order,
929
0
                    new_blocks,
930
                });
931
            }
932
933
            WakeUpReason::ForegroundMessage(ToBackground::PeersAssumedKnowBlock {
934
0
                send_back,
935
0
                block_number,
936
0
                block_hash,
937
            }) => {
938
                // Frontend queries the list of peers which are expected to know about a certain
939
                // block.
940
0
                let Some(sync) = &task.sync else {
941
0
                    unreachable!()
942
                };
943
944
0
                let outcome = if block_number <= sync.finalized_block_number() {
945
0
                    sync.sources()
946
0
                        .filter(|source_id| {
947
0
                            let source_best = sync.source_best_block(*source_id);
948
0
                            source_best.0 > block_number
949
0
                                || (source_best.0 == block_number && *source_best.1 == block_hash)
950
0
                        })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sh_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sh_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sh_0Ba_
951
0
                        .map(|id| sync[id].0.clone())
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0si_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0si_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0si_0Ba_
952
0
                        .collect()
953
                } else {
954
                    // As documented, `knows_non_finalized_block` would panic if the
955
                    // block height was below the one of the known finalized block.
956
0
                    sync.knows_non_finalized_block(block_number, &block_hash)
957
0
                        .map(|id| sync[id].0.clone())
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sj_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sj_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sj_0Ba_
958
0
                        .collect()
959
                };
960
961
0
                let _ = send_back.send(outcome);
962
            }
963
964
0
            WakeUpReason::ForegroundMessage(ToBackground::SyncingPeers { send_back }) => {
965
                // Frontend is querying the list of peers.
966
0
                let Some(sync) = &task.sync else {
967
0
                    unreachable!()
968
                };
969
970
0
                let out = sync
971
0
                    .sources()
972
0
                    .map(|src| {
973
0
                        let (peer_id, role) = sync[src].clone();
974
0
                        let (height, hash) = sync.source_best_block(src);
975
0
                        (peer_id, role, height, *hash)
976
0
                    })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sk_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sk_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sk_0Ba_
977
0
                    .collect::<Vec<_>>();
978
979
0
                let _ = send_back.send(out);
980
            }
981
982
            WakeUpReason::ForegroundMessage(ToBackground::SerializeChainInformation {
983
0
                send_back,
984
            }) => {
985
                // Frontend is querying the chain information.
986
0
                let _ = send_back.send(Some(
987
0
                    task.sync
988
0
                        .as_ref()
989
0
                        .unwrap_or_else(|| unreachable!())
990
0
                        .as_chain_information()
991
0
                        .into(),
992
                ));
993
            }
994
995
            WakeUpReason::ForegroundClosed => {
996
                // The channel with the frontend sync service has been closed.
997
                // Closing the sync background task as a result.
998
0
                return;
999
            }
1000
1001
0
            WakeUpReason::RequestFinished(_, Err(_)) => {
1002
0
                // A request has been cancelled by the sync state machine. Nothing to do.
1003
0
            }
1004
1005
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::Block(Ok(v)))) => {
1006
                // Successful block request.
1007
0
                task.sync
1008
0
                    .as_mut()
1009
0
                    .unwrap_or_else(|| unreachable!())
1010
0
                    .blocks_request_response(
1011
0
                        request_id,
1012
0
                        v.into_iter().filter_map(|block| {
1013
                            Some(all::BlockRequestSuccessBlock {
1014
0
                                scale_encoded_header: block.header?,
1015
0
                                scale_encoded_justifications: block
1016
0
                                    .justifications
1017
0
                                    .unwrap_or(Vec::new())
1018
0
                                    .into_iter()
1019
0
                                    .map(|j| all::Justification {
1020
0
                                        engine_id: j.engine_id,
1021
0
                                        justification: j.justification,
1022
0
                                    })
Unexecuted instantiation: _RNCNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sn_00Bc_
Unexecuted instantiation: _RNCNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sn_00B1x_
Unexecuted instantiation: _RNCNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sn_00Bc_
1023
0
                                    .collect(),
1024
0
                                scale_encoded_extrinsics: Vec::new(),
1025
0
                                user_data: (),
1026
                            })
1027
0
                        }),
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sn_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sn_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sn_0Ba_
1028
                    );
1029
            }
1030
1031
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::Block(Err(_)))) => {
1032
                // Failed block request.
1033
0
                let Some(sync) = &mut task.sync else {
1034
0
                    unreachable!()
1035
                };
1036
1037
0
                let source_peer_id = sync[sync.request_source_id(request_id)].0.clone();
1038
1039
0
                task.network_service
1040
0
                    .ban_and_disconnect(
1041
0
                        source_peer_id,
1042
0
                        network_service::BanSeverity::Low,
1043
0
                        "failed-blocks-request",
1044
0
                    )
1045
0
                    .await;
1046
1047
0
                sync.remove_request(request_id);
1048
            }
1049
1050
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::WarpSync(Ok(result)))) => {
1051
                // Successful warp sync request.
1052
0
                let decoded = result.decode();
1053
0
                let fragments = decoded
1054
0
                    .fragments
1055
0
                    .into_iter()
1056
0
                    .map(|f| all::WarpSyncFragment {
1057
0
                        scale_encoded_header: f.scale_encoded_header.to_vec(),
1058
0
                        scale_encoded_justification: f.scale_encoded_justification.to_vec(),
1059
0
                    })
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0so_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0so_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0so_0Ba_
1060
0
                    .collect();
1061
0
                task.sync
1062
0
                    .as_mut()
1063
0
                    .unwrap_or_else(|| unreachable!())
1064
0
                    .grandpa_warp_sync_response(request_id, fragments, decoded.is_finished);
1065
            }
1066
1067
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::WarpSync(Err(_)))) => {
1068
                // Failed warp sync request.
1069
0
                let Some(sync) = &mut task.sync else {
1070
0
                    unreachable!()
1071
                };
1072
1073
0
                task.network_service
1074
0
                    .ban_and_disconnect(
1075
0
                        sync[sync.request_source_id(request_id)].0.clone(),
1076
0
                        network_service::BanSeverity::Low,
1077
0
                        "failed-warp-sync-request",
1078
0
                    )
1079
0
                    .await;
1080
1081
0
                sync.remove_request(request_id);
1082
            }
1083
1084
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::Storage(Ok(r)))) => {
1085
                // Storage proof request.
1086
0
                let Some(sync) = &mut task.sync else {
1087
0
                    unreachable!()
1088
                };
1089
1090
0
                sync.storage_get_response(request_id, r);
1091
            }
1092
1093
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::Storage(Err(_)))) => {
1094
                // Storage proof request.
1095
0
                let Some(sync) = &mut task.sync else {
1096
0
                    unreachable!()
1097
                };
1098
1099
0
                task.network_service
1100
0
                    .ban_and_disconnect(
1101
0
                        sync[sync.request_source_id(request_id)].0.clone(),
1102
0
                        network_service::BanSeverity::Low,
1103
0
                        "failed-storage-request",
1104
0
                    )
1105
0
                    .await;
1106
1107
0
                sync.remove_request(request_id);
1108
            }
1109
1110
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::CallProof(Ok(r)))) => {
1111
                // Successful call proof request.
1112
0
                task.sync
1113
0
                    .as_mut()
1114
0
                    .unwrap_or_else(|| unreachable!())
1115
0
                    .call_proof_response(request_id, r.decode().to_owned());
1116
                // TODO: need help from networking service to avoid this to_owned
1117
            }
1118
1119
0
            WakeUpReason::RequestFinished(request_id, Ok(RequestOutcome::CallProof(Err(_)))) => {
1120
                // Failed call proof request.
1121
0
                let Some(sync) = &mut task.sync else {
1122
0
                    unreachable!()
1123
                };
1124
1125
0
                task.network_service
1126
0
                    .ban_and_disconnect(
1127
0
                        sync[sync.request_source_id(request_id)].0.clone(),
1128
0
                        network_service::BanSeverity::Low,
1129
0
                        "failed-call-proof-request",
1130
0
                    )
1131
0
                    .await;
1132
1133
0
                sync.remove_request(request_id);
1134
            }
1135
1136
0
            WakeUpReason::ObsoleteRequest(request_id) => {
1137
                // We are no longer interested in the answer to that request.
1138
0
                let Some(sync) = &mut task.sync else {
1139
0
                    unreachable!()
1140
                };
1141
1142
0
                let abort_handle = sync.remove_request(request_id);
1143
0
                abort_handle.abort();
1144
            }
1145
1146
            WakeUpReason::StartRequest(
1147
0
                source_id,
1148
                all::DesiredRequest::BlocksRequest {
1149
0
                    first_block_hash,
1150
0
                    first_block_height,
1151
0
                    num_blocks,
1152
0
                    request_headers,
1153
0
                    request_bodies,
1154
0
                    request_justification,
1155
                },
1156
            ) => {
1157
0
                let Some(sync) = &mut task.sync else {
1158
0
                    unreachable!()
1159
                };
1160
1161
                // Before inserting the request back to the syncing state machine, clamp the number
1162
                // of blocks to the number of blocks we expect to receive.
1163
                // This constant corresponds to the maximum number of blocks that nodes will answer
1164
                // in one request. If this constant happens to be inaccurate, everything will still
1165
                // work but less efficiently.
1166
0
                let num_blocks = NonZero::<u64>::new(cmp::min(64, num_blocks.get())).unwrap();
1167
1168
0
                let peer_id = sync[source_id].0.clone(); // TODO: why does this require cloning? weird borrow chk issue
1169
1170
0
                let block_request = task.network_service.clone().blocks_request(
1171
0
                    peer_id,
1172
0
                    network::codec::BlocksRequestConfig {
1173
0
                        start: network::codec::BlocksRequestConfigStart::Hash(first_block_hash),
1174
0
                        desired_count: NonZero::<u32>::new(
1175
0
                            u32::try_from(num_blocks.get()).unwrap_or(u32::MAX),
1176
0
                        )
1177
0
                        .unwrap(),
1178
0
                        // The direction is hardcoded based on the documentation of the syncing
1179
0
                        // state machine.
1180
0
                        direction: network::codec::BlocksRequestDirection::Descending,
1181
0
                        fields: network::codec::BlocksRequestFields {
1182
0
                            header: request_headers,
1183
0
                            body: request_bodies,
1184
0
                            justifications: request_justification,
1185
0
                        },
1186
0
                    },
1187
0
                    Duration::from_secs(10),
1188
                );
1189
1190
0
                let (block_request, abort) = future::abortable(block_request);
1191
0
                let request_id = sync.add_request(
1192
0
                    source_id,
1193
0
                    all::RequestDetail::BlocksRequest {
1194
0
                        first_block_hash,
1195
0
                        first_block_height,
1196
0
                        num_blocks,
1197
0
                        request_headers,
1198
0
                        request_bodies,
1199
0
                        request_justification,
1200
0
                    },
1201
0
                    abort,
1202
                );
1203
1204
0
                task.pending_requests.push(Box::pin(async move {
1205
0
                    (request_id, block_request.await.map(RequestOutcome::Block))
1206
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sr_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sr_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sr_0Ba_
1207
            }
1208
1209
            WakeUpReason::StartRequest(
1210
0
                source_id,
1211
                all::DesiredRequest::WarpSync {
1212
0
                    sync_start_block_hash,
1213
                },
1214
            ) => {
1215
0
                let Some(sync) = &mut task.sync else {
1216
0
                    unreachable!()
1217
                };
1218
1219
0
                let peer_id = sync[source_id].0.clone(); // TODO: why does this require cloning? weird borrow chk issue
1220
1221
0
                let grandpa_request = task.network_service.clone().grandpa_warp_sync_request(
1222
0
                    peer_id,
1223
0
                    sync_start_block_hash,
1224
                    // The timeout needs to be long enough to potentially download the maximum
1225
                    // response size of 16 MiB. Assuming a 128 kiB/sec connection, that's
1226
                    // 128 seconds. Unfortunately, 128 seconds is way too large, and for
1227
                    // pragmatic reasons we use a lower value.
1228
0
                    Duration::from_secs(24),
1229
                );
1230
1231
0
                let (grandpa_request, abort) = future::abortable(grandpa_request);
1232
0
                let request_id = sync.add_request(
1233
0
                    source_id,
1234
0
                    all::RequestDetail::WarpSync {
1235
0
                        sync_start_block_hash,
1236
0
                    },
1237
0
                    abort,
1238
                );
1239
1240
0
                task.pending_requests.push(Box::pin(async move {
1241
                    (
1242
0
                        request_id,
1243
0
                        grandpa_request.await.map(RequestOutcome::WarpSync),
1244
                    )
1245
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0ss_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0ss_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0ss_0Ba_
1246
            }
1247
1248
            WakeUpReason::StartRequest(
1249
0
                source_id,
1250
                all::DesiredRequest::StorageGetMerkleProof {
1251
0
                    block_hash, keys, ..
1252
                },
1253
            ) => {
1254
0
                let Some(sync) = &mut task.sync else {
1255
0
                    unreachable!()
1256
                };
1257
1258
0
                let peer_id = sync[source_id].0.clone(); // TODO: why does this require cloning? weird borrow chk issue
1259
1260
0
                let storage_request = task.network_service.clone().storage_proof_request(
1261
0
                    peer_id,
1262
0
                    network::codec::StorageProofRequestConfig {
1263
0
                        block_hash,
1264
0
                        keys: keys.clone().into_iter(),
1265
0
                    },
1266
0
                    Duration::from_secs(16),
1267
                );
1268
1269
0
                let storage_request = async move {
1270
0
                    if let Ok(outcome) = storage_request.await {
1271
                        // TODO: log what happens
1272
0
                        Ok(outcome.decode().to_vec()) // TODO: no to_vec() here, needs some API change on the networking
1273
                    } else {
1274
0
                        Err(())
1275
                    }
1276
0
                };
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0st_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0st_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0st_0Ba_
1277
1278
0
                let (storage_request, abort) = future::abortable(storage_request);
1279
0
                let request_id = sync.add_request(
1280
0
                    source_id,
1281
0
                    all::RequestDetail::StorageGet { block_hash, keys },
1282
0
                    abort,
1283
                );
1284
1285
0
                task.pending_requests.push(Box::pin(async move {
1286
                    (
1287
0
                        request_id,
1288
0
                        storage_request.await.map(RequestOutcome::Storage),
1289
                    )
1290
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0su_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0su_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0su_0Ba_
1291
            }
1292
1293
            WakeUpReason::StartRequest(
1294
0
                source_id,
1295
                all::DesiredRequest::RuntimeCallMerkleProof {
1296
0
                    block_hash,
1297
0
                    function_name,
1298
0
                    parameter_vectored,
1299
                },
1300
            ) => {
1301
0
                let Some(sync) = &mut task.sync else {
1302
0
                    unreachable!()
1303
                };
1304
1305
0
                let peer_id = sync[source_id].0.clone(); // TODO: why does this require cloning? weird borrow chk issue
1306
1307
0
                let call_proof_request = {
1308
                    // TODO: all this copying is done because of lifetime requirements in NetworkService::call_proof_request; maybe check if it can be avoided
1309
0
                    let network_service = task.network_service.clone();
1310
0
                    let parameter_vectored = parameter_vectored.clone();
1311
0
                    let function_name = function_name.clone();
1312
0
                    async move {
1313
0
                        let rq = network_service.call_proof_request(
1314
0
                            peer_id,
1315
0
                            network::codec::CallProofRequestConfig {
1316
0
                                block_hash,
1317
0
                                method: Cow::Borrowed(&*function_name),
1318
0
                                parameter_vectored: iter::once(&parameter_vectored),
1319
0
                            },
1320
0
                            Duration::from_secs(16),
1321
                        );
1322
1323
0
                        match rq.await {
1324
0
                            Ok(p) => Ok(p),
1325
0
                            Err(_) => Err(()),
1326
                        }
1327
0
                    }
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sv_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sv_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sv_0Ba_
1328
                };
1329
1330
0
                let (call_proof_request, abort) = future::abortable(call_proof_request);
1331
0
                let request_id = sync.add_request(
1332
0
                    source_id,
1333
0
                    all::RequestDetail::RuntimeCallMerkleProof {
1334
0
                        block_hash,
1335
0
                        function_name,
1336
0
                        parameter_vectored,
1337
0
                    },
1338
0
                    abort,
1339
                );
1340
1341
0
                task.pending_requests.push(Box::pin(async move {
1342
                    (
1343
0
                        request_id,
1344
0
                        call_proof_request.await.map(RequestOutcome::CallProof),
1345
                    )
1346
0
                }));
Unexecuted instantiation: _RNCNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sw_0Ba_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0sw_0B1v_
Unexecuted instantiation: _RNCNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0sw_0Ba_
1347
            }
1348
1349
            WakeUpReason::WarpSyncTakingLongTimeWarning => {
1350
0
                match task
1351
0
                    .sync
1352
0
                    .as_mut()
1353
0
                    .unwrap_or_else(|| unreachable!())
1354
0
                    .status()
1355
                {
1356
0
                    all::Status::Sync => {}
1357
                    all::Status::WarpSyncFragments {
1358
                        source: None,
1359
0
                        finalized_block_hash,
1360
0
                        finalized_block_number,
1361
0
                    } => {
1362
0
                        log!(
1363
0
                            &task.platform,
1364
0
                            Warn,
1365
0
                            &task.log_target,
1366
0
                            format!(
1367
0
                                "GrandPa warp sync idle at block #{} (0x{})",
1368
0
                                finalized_block_number,
1369
0
                                HashDisplay(&finalized_block_hash)
1370
0
                            ),
1371
0
                        );
1372
0
                    }
1373
                    all::Status::WarpSyncFragments {
1374
0
                        finalized_block_hash,
1375
0
                        finalized_block_number,
1376
                        ..
1377
                    }
1378
                    | all::Status::WarpSyncChainInformation {
1379
0
                        finalized_block_hash,
1380
0
                        finalized_block_number,
1381
0
                    } => {
1382
0
                        log!(
1383
0
                            &task.platform,
1384
0
                            Warn,
1385
0
                            &task.log_target,
1386
0
                            format!(
1387
0
                                "GrandPa warp sync in progress. Block: #{} (0x{}).",
1388
0
                                finalized_block_number,
1389
0
                                HashDisplay(&finalized_block_hash)
1390
0
                            )
1391
0
                        );
1392
0
                    }
1393
                };
1394
            }
1395
        }
1396
    }
1397
0
}
Unexecuted instantiation: _RNCINvNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standalone22start_standalone_chainpE0B8_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0B1t_
Unexecuted instantiation: _RNCINvNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standalone22start_standalone_chainpE0B8_
1398
1399
struct Task<TPlat: PlatformRef> {
1400
    /// Log target to use for all logs that are emitted.
1401
    log_target: String,
1402
1403
    /// Access to the platform's capabilities.
1404
    platform: TPlat,
1405
1406
    /// Main syncing state machine. Contains a list of peers, requests, and blocks, and manages
1407
    /// everything about the non-finalized chain.
1408
    ///
1409
    /// For each request, we store a [`future::AbortHandle`] that can be used to abort the
1410
    /// request if desired.
1411
    ///
1412
    /// Always `Some`, except for temporary extraction.
1413
    sync: Option<all::AllSync<future::AbortHandle, (libp2p::PeerId, codec::Role), ()>>,
1414
1415
    /// If `Some`, contains the runtime of the current finalized block.
1416
    known_finalized_runtime: Option<FinalizedBlockRuntime>,
1417
1418
    /// For each networking peer, the index of the corresponding peer within the [`Task::sync`].
1419
    peers_source_id_map: HashMap<libp2p::PeerId, all::SourceId, util::SipHasherBuild>,
1420
1421
    /// `false` after the best block in the [`Task::sync`] has changed. Set back to `true`
1422
    /// after the networking has been notified of this change.
1423
    network_up_to_date_best: bool,
1424
    /// `false` after the finalized block in the [`Task::sync`] has changed. Set back to `true`
1425
    /// after the networking has been notified of this change.
1426
    network_up_to_date_finalized: bool,
1427
1428
    /// All event subscribers that are interested in events about the chain.
1429
    all_notifications: Vec<async_channel::Sender<Notification>>,
1430
1431
    /// Contains a `Delay` after which we print a warning about GrandPa warp sync taking a long
1432
    /// time. Set to `Pending` after the warp sync has finished, so that future remains pending
1433
    /// forever.
1434
    warp_sync_taking_long_time_warning:
1435
        future::Fuse<future::Either<Pin<Box<TPlat::Delay>>, future::Pending<()>>>,
1436
1437
    /// Chain of the network service. Used to send out requests to peers.
1438
    network_service: Arc<network_service::NetworkServiceChain<TPlat>>,
1439
    /// Events coming from the networking service. `None` if not subscribed yet.
1440
    from_network_service: Option<Pin<Box<async_channel::Receiver<network_service::Event>>>>,
1441
1442
    /// List of requests currently in progress.
1443
    pending_requests: stream::FuturesUnordered<
1444
        future::BoxFuture<'static, (all::RequestId, Result<RequestOutcome, future::Aborted>)>,
1445
    >,
1446
}
1447
1448
enum RequestOutcome {
1449
    Block(Result<Vec<codec::BlockData>, network_service::BlocksRequestError>),
1450
    WarpSync(
1451
        Result<
1452
            network::service::EncodedGrandpaWarpSyncResponse,
1453
            network_service::WarpSyncRequestError,
1454
        >,
1455
    ),
1456
    Storage(Result<Vec<u8>, ()>),
1457
    CallProof(Result<network::service::EncodedMerkleProof, ()>),
1458
}
1459
1460
impl<TPlat: PlatformRef> Task<TPlat> {
1461
    /// Sends a notification to all the notification receivers.
1462
0
    fn dispatch_all_subscribers(&mut self, notification: Notification) {
1463
        // Elements in `all_notifications` are removed one by one and inserted back if the
1464
        // channel is still open.
1465
0
        for index in (0..self.all_notifications.len()).rev() {
1466
0
            let subscription = self.all_notifications.swap_remove(index);
1467
0
            if subscription.try_send(notification.clone()).is_err() {
1468
0
                continue;
1469
0
            }
1470
1471
0
            self.all_notifications.push(subscription);
1472
        }
1473
0
    }
Unexecuted instantiation: _RNvMNtNtCsgnEOxJmACC4_13smoldot_light12sync_service10standaloneINtB2_4TaskpE24dispatch_all_subscribersB6_
Unexecuted instantiation: _RNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standaloneINtB2_4TaskNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE24dispatch_all_subscribersB1e_
Unexecuted instantiation: _RNvMNtNtCs508CmrSPkZh_13smoldot_light12sync_service10standaloneINtB2_4TaskpE24dispatch_all_subscribersB6_
1474
}