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