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