/__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(¶meter_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 | | } |