/__w/smoldot/smoldot/repo/lib/src/sync/warp_sync.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 | | //! Warp syncing. |
19 | | //! |
20 | | //! Warp syncing makes it possible to very quickly reach the currently finalized block of a chain. |
21 | | //! No attempt is made at verifying blocks. The algorithm assumes that the currently finalized |
22 | | //! block is valid, as the chain is likely bricked if this is not the case. |
23 | | //! |
24 | | //! # Long range attack vulnerability |
25 | | //! |
26 | | //! Warp syncing is particularly vulnerable to what is called long range attacks. |
27 | | //! |
28 | | //! The authorities allowed to finalize blocks can generate multiple proofs of finality for |
29 | | //! multiple different blocks of the same height. In other words, they can finalize more than one |
30 | | //! chain at a time. |
31 | | //! |
32 | | //! Finalizing multiple chains at the same time is called an equivocation. Client implementations |
33 | | //! detect equivocations and report them to the runtime. While this is out of scope of the client, |
34 | | //! the runtime then typically provides a mechanism that punishes the validators that have |
35 | | //! equivocated. |
36 | | //! However, this defense mechanism is flawed in case when a long time passes between the |
37 | | //! multiple finality proofs generated by the same validators. Clients cannot hold an unlimited |
38 | | //! amount of information in memory, so they might not detect the equivocation, and even if it is |
39 | | //! detected, the punishment might not be enforceable because validators have moved all their |
40 | | //! funds. |
41 | | //! |
42 | | //! In other words, it is possible for two thirds of the validators that were active at a certain |
43 | | //! past block N to collude and decide to finalize a different block N, even when N has been |
44 | | //! finalized for the first time several weeks or months in the past. When a client then warp |
45 | | //! syncs, it can be tricked to consider this alternative block N as the finalized one. |
46 | | //! |
47 | | //! There is no fool-proof defense against this attack. However, consider the extremely high |
48 | | //! investment and high risk for the malicious validators, and the difficulty of pulling off this |
49 | | //! attack, it is extremely unlikely to happen in reality. |
50 | | //! The aforementioned punishment system is the only defense against this attack, and in order to |
51 | | //! be effective, the starting point of the warp syncing shouldn't be too far in the past. How |
52 | | //! far exactly depends on the logic of the runtime of the chain. |
53 | | //! |
54 | | //! # Overview |
55 | | //! |
56 | | //! The warp syncing algorithm works only if the chain uses Grandpa for its finality. |
57 | | //! It consists in the following steps: |
58 | | //! |
59 | | //! - Downloading a warp sync proof from a source. This proof contains a list of *fragments*. Each |
60 | | //! fragment represents a change in the list of Grandpa authorities, and a list of signatures of |
61 | | //! the previous authorities that certify that this change is correct. |
62 | | //! - Verifying the fragments. Each fragment that is successfully verified progresses towards |
63 | | //! the head of the chain. Even if one fragment is invalid, all the previously-verified |
64 | | //! fragments can still be kept, and the warp syncing can resume from there. |
65 | | //! - Downloading from a source the runtime code of the final block of the proof. |
66 | | //! - Performing some runtime calls in order to obtain the current consensus-related parameters |
67 | | //! of the chain. This might require obtaining some storage items, in which case they must also |
68 | | //! be downloaded from a source. |
69 | | //! |
70 | | //! At the end of the syncing, a [`ValidChainInformation`] corresponding to the head of the chain |
71 | | //! is yielded. |
72 | | //! |
73 | | //! # Usage |
74 | | //! |
75 | | //! Use the [`start_warp_sync()`] function to start a Grandpa warp syncing state machine. |
76 | | //! |
77 | | //! At any given moment, this state machine holds a list of *sources* that it might use to |
78 | | //! download the warp sync proof or the runtime code. Sources must be added and removed by the API |
79 | | //! user by calling one of the various `add_source` and `remove_source` functions. |
80 | | //! |
81 | | //! Sources are identified through a [`SourceId`]. Each source has an opaque so-called "user data" |
82 | | //! of type `TSrc` associated to it. The content of this "user data" is at the discretion of the |
83 | | //! API user. |
84 | | //! |
85 | | //! Similarly, at any given moment, this state machine holds a list of requests that concern these |
86 | | //! sources. Use [`WarpSync::desired_requests`] to determine which requests will be useful to the |
87 | | //! progress of the warp syncing, then use [`WarpSync::add_request`] to update the state machine |
88 | | //! with a newly-started request. |
89 | | //! |
90 | | //! Use [`WarpSync::process_one`] in order to run verifications of the payloads that have |
91 | | //! previously been downloaded. |
92 | | //! |
93 | | |
94 | | use crate::{ |
95 | | chain::chain_information::{ |
96 | | self, ChainInformationConsensusRef, ChainInformationFinality, ChainInformationFinalityRef, |
97 | | ValidChainInformation, ValidChainInformationRef, |
98 | | }, |
99 | | executor::{ |
100 | | self, |
101 | | host::{self, HostVmPrototype}, |
102 | | vm::ExecHint, |
103 | | }, |
104 | | finality::{decode, verify}, |
105 | | header, |
106 | | informant::HashDisplay, |
107 | | trie::{self, proof_decode}, |
108 | | }; |
109 | | |
110 | | use alloc::{ |
111 | | borrow::{Cow, ToOwned as _}, |
112 | | collections::{BTreeSet, VecDeque}, |
113 | | vec, |
114 | | vec::Vec, |
115 | | }; |
116 | | use core::{cmp, fmt, iter, mem, ops}; |
117 | | |
118 | | pub use trie::Nibble; |
119 | | |
120 | | /// The configuration for [`start_warp_sync()`]. |
121 | | #[derive(Debug)] |
122 | | pub struct Config { |
123 | | /// The chain information of the starting point of the warp syncing. |
124 | | pub start_chain_information: ValidChainInformation, |
125 | | |
126 | | /// Number of bytes used when encoding/decoding the block number. Influences how various data |
127 | | /// structures should be parsed. |
128 | | pub block_number_bytes: usize, |
129 | | |
130 | | /// The initial capacity of the list of sources. |
131 | | pub sources_capacity: usize, |
132 | | |
133 | | /// The initial capacity of the list of requests. |
134 | | pub requests_capacity: usize, |
135 | | |
136 | | /// Known valid Merkle value and storage value combination for the `:code` key. |
137 | | /// |
138 | | /// If provided, the warp syncing algorithm will first fetch the Merkle value of `:code`, and |
139 | | /// if it matches the Merkle value provided in the hint, use the storage value in the hint |
140 | | /// instead of downloading it. If the hint doesn't match, an extra round-trip will be needed, |
141 | | /// but if the hint matches it saves a big download. |
142 | | pub code_trie_node_hint: Option<ConfigCodeTrieNodeHint>, |
143 | | |
144 | | /// Number of warp sync fragments after which the state machine will pause downloading new |
145 | | /// ones until the ones that have been downloaded are verified. |
146 | | /// |
147 | | /// A too low value will cause stalls, while a high value will use more memory and runs the |
148 | | /// risk of wasting more bandwidth in case the downloaded fragments need to be thrown away. |
149 | | pub num_download_ahead_fragments: usize, |
150 | | |
151 | | /// If the height of the current local finalized block is `N`, the warp sync state machine |
152 | | /// will not attempt to warp sync to blocks whose height inferior or equal to `N + k` where |
153 | | /// `k` is the value in this field. |
154 | | /// |
155 | | /// Because warp syncing is a relatively expensive process, it is not worth performing it |
156 | | /// between two blocks that are too close to each other. |
157 | | /// |
158 | | /// The ideal value of this field depends on the block production rate and the time it takes |
159 | | /// to answer requests. |
160 | | pub warp_sync_minimum_gap: usize, |
161 | | |
162 | | /// If `true`, the body of the warp sync target will be downloaded before the warp sync |
163 | | /// finishes. |
164 | | /// Determines whether [`RuntimeInformation::finalized_body`] is `Some`. |
165 | | pub download_block_body: bool, |
166 | | |
167 | | /// If `true`, all the storage proofs and call proofs necessary in order to compute the chain |
168 | | /// information of the warp synced block will be downloaded. If `false`, the finality |
169 | | /// information of the warp synced block is inferred from the warp sync fragments instead. |
170 | | pub download_all_chain_information_storage_proofs: bool, |
171 | | } |
172 | | |
173 | | /// See [`Config::code_trie_node_hint`]. |
174 | | #[derive(Debug)] |
175 | | pub struct ConfigCodeTrieNodeHint { |
176 | | /// Potential Merkle value of the `:code` key. |
177 | | pub merkle_value: Vec<u8>, |
178 | | |
179 | | /// Storage value corresponding to [`ConfigCodeTrieNodeHint::merkle_value`]. |
180 | | pub storage_value: Vec<u8>, |
181 | | |
182 | | /// Closest ancestor of the `:code` key except for `:code` itself. |
183 | | pub closest_ancestor_excluding: Vec<Nibble>, |
184 | | } |
185 | | |
186 | | /// Initializes the warp sync state machine. |
187 | | /// |
188 | | /// On error, returns the [`ValidChainInformation`] that was provided in the configuration. |
189 | 21 | pub fn start_warp_sync<TSrc, TRq>( |
190 | 21 | config: Config, |
191 | 21 | ) -> Result<WarpSync<TSrc, TRq>, (ValidChainInformation, WarpSyncInitError)> { |
192 | 21 | match config.start_chain_information.as_ref().finality { |
193 | | // TODO: we make sure that `finalized_scheduled_change` is `None` because it seems complicated to support, but ideally it would be supported |
194 | | ChainInformationFinalityRef::Grandpa { |
195 | | finalized_scheduled_change: None, |
196 | | .. |
197 | 21 | } => {} |
198 | | _ => { |
199 | 0 | return Err(( |
200 | 0 | config.start_chain_information, |
201 | 0 | WarpSyncInitError::NotGrandpa, |
202 | 0 | )) |
203 | | } |
204 | | } |
205 | | |
206 | 21 | match config.start_chain_information.as_ref().consensus { |
207 | 21 | ChainInformationConsensusRef::Babe { .. } | ChainInformationConsensusRef::Aura { .. } => {} |
208 | | ChainInformationConsensusRef::Unknown => { |
209 | 0 | return Err(( |
210 | 0 | config.start_chain_information, |
211 | 0 | WarpSyncInitError::UnknownConsensus, |
212 | 0 | )) |
213 | | } |
214 | | } |
215 | | |
216 | 21 | let warped_header = config |
217 | 21 | .start_chain_information |
218 | 21 | .as_ref() |
219 | 21 | .finalized_block_header |
220 | 21 | .scale_encoding_vec(config.block_number_bytes); |
221 | 21 | |
222 | 21 | Ok(WarpSync { |
223 | 21 | warped_header_number: config |
224 | 21 | .start_chain_information |
225 | 21 | .as_ref() |
226 | 21 | .finalized_block_header |
227 | 21 | .number, |
228 | 21 | warped_header_state_root: *config |
229 | 21 | .start_chain_information |
230 | 21 | .as_ref() |
231 | 21 | .finalized_block_header |
232 | 21 | .state_root, |
233 | 21 | warped_header_extrinsics_root: *config |
234 | 21 | .start_chain_information |
235 | 21 | .as_ref() |
236 | 21 | .finalized_block_header |
237 | 21 | .extrinsics_root, |
238 | 21 | warped_header_hash: header::hash_from_scale_encoded_header(&warped_header), |
239 | 21 | warped_header, |
240 | 21 | warped_finality: config.start_chain_information.as_ref().finality.into(), |
241 | 21 | warped_block_ty: WarpedBlockTy::AlreadyVerified, |
242 | 21 | runtime_calls: runtime_calls_default_value( |
243 | 21 | config.start_chain_information.as_ref().consensus, |
244 | 21 | ), |
245 | 21 | verified_chain_information: config.start_chain_information, |
246 | 21 | code_trie_node_hint: config.code_trie_node_hint, |
247 | 21 | num_download_ahead_fragments: config.num_download_ahead_fragments, |
248 | 21 | warp_sync_minimum_gap: config.warp_sync_minimum_gap, |
249 | 21 | block_number_bytes: config.block_number_bytes, |
250 | 21 | download_all_chain_information_storage_proofs: config |
251 | 21 | .download_all_chain_information_storage_proofs, |
252 | 21 | sources: slab::Slab::with_capacity(config.sources_capacity), |
253 | 21 | sources_by_finalized_height: BTreeSet::new(), |
254 | 21 | in_progress_requests: slab::Slab::with_capacity(config.requests_capacity), |
255 | 21 | in_progress_requests_by_source: BTreeSet::new(), |
256 | 21 | warp_sync_fragments_download: None, |
257 | 21 | verify_queue: VecDeque::new(), |
258 | 21 | runtime_download: RuntimeDownload::NotStarted { |
259 | 21 | hint_doesnt_match: false, |
260 | 21 | }, |
261 | 21 | body_download: if config.download_block_body { |
262 | 21 | BodyDownload::NotStarted |
263 | | } else { |
264 | 0 | BodyDownload::NotNeeded |
265 | | }, |
266 | | }) |
267 | 21 | } Unexecuted instantiation: _RINvNtNtCsN16ciHI6Qf_7smoldot4sync9warp_sync15start_warp_syncppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync15start_warp_syncNtNtB4_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraECsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync15start_warp_syncppEB6_ _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync15start_warp_syncNtNtB4_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraECsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 189 | 2 | pub fn start_warp_sync<TSrc, TRq>( | 190 | 2 | config: Config, | 191 | 2 | ) -> Result<WarpSync<TSrc, TRq>, (ValidChainInformation, WarpSyncInitError)> { | 192 | 2 | match config.start_chain_information.as_ref().finality { | 193 | | // TODO: we make sure that `finalized_scheduled_change` is `None` because it seems complicated to support, but ideally it would be supported | 194 | | ChainInformationFinalityRef::Grandpa { | 195 | | finalized_scheduled_change: None, | 196 | | .. | 197 | 2 | } => {} | 198 | | _ => { | 199 | 0 | return Err(( | 200 | 0 | config.start_chain_information, | 201 | 0 | WarpSyncInitError::NotGrandpa, | 202 | 0 | )) | 203 | | } | 204 | | } | 205 | | | 206 | 2 | match config.start_chain_information.as_ref().consensus { | 207 | 2 | ChainInformationConsensusRef::Babe { .. } | ChainInformationConsensusRef::Aura { .. } => {} | 208 | | ChainInformationConsensusRef::Unknown => { | 209 | 0 | return Err(( | 210 | 0 | config.start_chain_information, | 211 | 0 | WarpSyncInitError::UnknownConsensus, | 212 | 0 | )) | 213 | | } | 214 | | } | 215 | | | 216 | 2 | let warped_header = config | 217 | 2 | .start_chain_information | 218 | 2 | .as_ref() | 219 | 2 | .finalized_block_header | 220 | 2 | .scale_encoding_vec(config.block_number_bytes); | 221 | 2 | | 222 | 2 | Ok(WarpSync { | 223 | 2 | warped_header_number: config | 224 | 2 | .start_chain_information | 225 | 2 | .as_ref() | 226 | 2 | .finalized_block_header | 227 | 2 | .number, | 228 | 2 | warped_header_state_root: *config | 229 | 2 | .start_chain_information | 230 | 2 | .as_ref() | 231 | 2 | .finalized_block_header | 232 | 2 | .state_root, | 233 | 2 | warped_header_extrinsics_root: *config | 234 | 2 | .start_chain_information | 235 | 2 | .as_ref() | 236 | 2 | .finalized_block_header | 237 | 2 | .extrinsics_root, | 238 | 2 | warped_header_hash: header::hash_from_scale_encoded_header(&warped_header), | 239 | 2 | warped_header, | 240 | 2 | warped_finality: config.start_chain_information.as_ref().finality.into(), | 241 | 2 | warped_block_ty: WarpedBlockTy::AlreadyVerified, | 242 | 2 | runtime_calls: runtime_calls_default_value( | 243 | 2 | config.start_chain_information.as_ref().consensus, | 244 | 2 | ), | 245 | 2 | verified_chain_information: config.start_chain_information, | 246 | 2 | code_trie_node_hint: config.code_trie_node_hint, | 247 | 2 | num_download_ahead_fragments: config.num_download_ahead_fragments, | 248 | 2 | warp_sync_minimum_gap: config.warp_sync_minimum_gap, | 249 | 2 | block_number_bytes: config.block_number_bytes, | 250 | 2 | download_all_chain_information_storage_proofs: config | 251 | 2 | .download_all_chain_information_storage_proofs, | 252 | 2 | sources: slab::Slab::with_capacity(config.sources_capacity), | 253 | 2 | sources_by_finalized_height: BTreeSet::new(), | 254 | 2 | in_progress_requests: slab::Slab::with_capacity(config.requests_capacity), | 255 | 2 | in_progress_requests_by_source: BTreeSet::new(), | 256 | 2 | warp_sync_fragments_download: None, | 257 | 2 | verify_queue: VecDeque::new(), | 258 | 2 | runtime_download: RuntimeDownload::NotStarted { | 259 | 2 | hint_doesnt_match: false, | 260 | 2 | }, | 261 | 2 | body_download: if config.download_block_body { | 262 | 2 | BodyDownload::NotStarted | 263 | | } else { | 264 | 0 | BodyDownload::NotNeeded | 265 | | }, | 266 | | }) | 267 | 2 | } |
Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync15start_warp_syncNtNtB4_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraECscDgN54JpMGG_6author _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync15start_warp_syncNtNtB4_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraECsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 189 | 19 | pub fn start_warp_sync<TSrc, TRq>( | 190 | 19 | config: Config, | 191 | 19 | ) -> Result<WarpSync<TSrc, TRq>, (ValidChainInformation, WarpSyncInitError)> { | 192 | 19 | match config.start_chain_information.as_ref().finality { | 193 | | // TODO: we make sure that `finalized_scheduled_change` is `None` because it seems complicated to support, but ideally it would be supported | 194 | | ChainInformationFinalityRef::Grandpa { | 195 | | finalized_scheduled_change: None, | 196 | | .. | 197 | 19 | } => {} | 198 | | _ => { | 199 | 0 | return Err(( | 200 | 0 | config.start_chain_information, | 201 | 0 | WarpSyncInitError::NotGrandpa, | 202 | 0 | )) | 203 | | } | 204 | | } | 205 | | | 206 | 19 | match config.start_chain_information.as_ref().consensus { | 207 | 19 | ChainInformationConsensusRef::Babe { .. } | ChainInformationConsensusRef::Aura { .. } => {} | 208 | | ChainInformationConsensusRef::Unknown => { | 209 | 0 | return Err(( | 210 | 0 | config.start_chain_information, | 211 | 0 | WarpSyncInitError::UnknownConsensus, | 212 | 0 | )) | 213 | | } | 214 | | } | 215 | | | 216 | 19 | let warped_header = config | 217 | 19 | .start_chain_information | 218 | 19 | .as_ref() | 219 | 19 | .finalized_block_header | 220 | 19 | .scale_encoding_vec(config.block_number_bytes); | 221 | 19 | | 222 | 19 | Ok(WarpSync { | 223 | 19 | warped_header_number: config | 224 | 19 | .start_chain_information | 225 | 19 | .as_ref() | 226 | 19 | .finalized_block_header | 227 | 19 | .number, | 228 | 19 | warped_header_state_root: *config | 229 | 19 | .start_chain_information | 230 | 19 | .as_ref() | 231 | 19 | .finalized_block_header | 232 | 19 | .state_root, | 233 | 19 | warped_header_extrinsics_root: *config | 234 | 19 | .start_chain_information | 235 | 19 | .as_ref() | 236 | 19 | .finalized_block_header | 237 | 19 | .extrinsics_root, | 238 | 19 | warped_header_hash: header::hash_from_scale_encoded_header(&warped_header), | 239 | 19 | warped_header, | 240 | 19 | warped_finality: config.start_chain_information.as_ref().finality.into(), | 241 | 19 | warped_block_ty: WarpedBlockTy::AlreadyVerified, | 242 | 19 | runtime_calls: runtime_calls_default_value( | 243 | 19 | config.start_chain_information.as_ref().consensus, | 244 | 19 | ), | 245 | 19 | verified_chain_information: config.start_chain_information, | 246 | 19 | code_trie_node_hint: config.code_trie_node_hint, | 247 | 19 | num_download_ahead_fragments: config.num_download_ahead_fragments, | 248 | 19 | warp_sync_minimum_gap: config.warp_sync_minimum_gap, | 249 | 19 | block_number_bytes: config.block_number_bytes, | 250 | 19 | download_all_chain_information_storage_proofs: config | 251 | 19 | .download_all_chain_information_storage_proofs, | 252 | 19 | sources: slab::Slab::with_capacity(config.sources_capacity), | 253 | 19 | sources_by_finalized_height: BTreeSet::new(), | 254 | 19 | in_progress_requests: slab::Slab::with_capacity(config.requests_capacity), | 255 | 19 | in_progress_requests_by_source: BTreeSet::new(), | 256 | 19 | warp_sync_fragments_download: None, | 257 | 19 | verify_queue: VecDeque::new(), | 258 | 19 | runtime_download: RuntimeDownload::NotStarted { | 259 | 19 | hint_doesnt_match: false, | 260 | 19 | }, | 261 | 19 | body_download: if config.download_block_body { | 262 | 19 | BodyDownload::NotStarted | 263 | | } else { | 264 | 0 | BodyDownload::NotNeeded | 265 | | }, | 266 | | }) | 267 | 19 | } |
|
268 | | |
269 | | /// Error potentially returned by [`start_warp_sync()`]. |
270 | 0 | #[derive(Debug, derive_more::Display, Clone)] Unexecuted instantiation: _RNvXsb_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_17WarpSyncInitErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsb_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_17WarpSyncInitErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
271 | | pub enum WarpSyncInitError { |
272 | | /// Chain doesn't use the Grandpa finality algorithm. |
273 | | NotGrandpa, |
274 | | /// Chain uses an unrecognized consensus mechanism. |
275 | | UnknownConsensus, |
276 | | } |
277 | | |
278 | | /// Identifier for a source in the [`WarpSync`]. |
279 | | // |
280 | | // Implementation note: this represents the index within the `Slab` used for the list of sources. |
281 | | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] |
282 | | pub struct SourceId(usize); |
283 | | |
284 | | impl SourceId { |
285 | | /// Smallest possible [`SourceId`]. It is always inferior or equal to any other. |
286 | | pub const MIN: Self = SourceId(usize::MIN); |
287 | | } |
288 | | |
289 | | // TODO: consider removing this entirely |
290 | | pub struct RuntimeInformation { |
291 | | /// The runtime constructed in `VirtualMachineParamsGet`. Corresponds to the runtime of the |
292 | | /// finalized block of [`WarpSync::as_chain_information`]. |
293 | | pub finalized_runtime: HostVmPrototype, |
294 | | |
295 | | /// List of SCALE-encoded extrinsics of the body of the finalized block. |
296 | | /// `Some` if and only if [`Config::download_block_body`] was `true`. |
297 | | pub finalized_body: Option<Vec<Vec<u8>>>, |
298 | | |
299 | | /// Storage value at the `:code` key of the finalized block. |
300 | | pub finalized_storage_code: Option<Vec<u8>>, |
301 | | |
302 | | /// Storage value at the `:heappages` key of the finalized block. |
303 | | pub finalized_storage_heap_pages: Option<Vec<u8>>, |
304 | | |
305 | | /// Merkle value of the `:code` trie node of the finalized block. |
306 | | pub finalized_storage_code_merkle_value: Option<Vec<u8>>, |
307 | | |
308 | | /// Closest ancestor of the `:code` trie node of the finalized block excluding `:code` itself. |
309 | | pub finalized_storage_code_closest_ancestor_excluding: Option<Vec<Nibble>>, |
310 | | } |
311 | | |
312 | | /// Fragment to be verified. |
313 | | #[derive(Debug)] |
314 | | pub struct WarpSyncFragment { |
315 | | /// Header of a block in the chain. |
316 | | pub scale_encoded_header: Vec<u8>, |
317 | | |
318 | | /// Justification that proves the finality of [`WarpSyncFragment::scale_encoded_header`]. |
319 | | pub scale_encoded_justification: Vec<u8>, |
320 | | } |
321 | | |
322 | | /// Warp syncing process state machine. |
323 | | pub struct WarpSync<TSrc, TRq> { |
324 | | /// SCALE-encoded header of the finalized block of the chain we warp synced to. Initially |
325 | | /// identical to the value in [`WarpSync::verified_chain_information`]. |
326 | | warped_header: Vec<u8>, |
327 | | /// Hash of the block in [`WarpSync::warped_header`]. |
328 | | warped_header_hash: [u8; 32], |
329 | | /// State trie root hash of the block in [`WarpSync::warped_header`]. |
330 | | warped_header_state_root: [u8; 32], |
331 | | /// Extrinsics trie root hash of the block in [`WarpSync::warped_header`]. |
332 | | warped_header_extrinsics_root: [u8; 32], |
333 | | /// Number of the block in [`WarpSync::warped_header`]. |
334 | | warped_header_number: u64, |
335 | | /// Information about the finality of the chain at the point where we warp synced to. |
336 | | /// Initially identical to the value in [`WarpSync::verified_chain_information`]. |
337 | | warped_finality: ChainInformationFinality, |
338 | | /// Information about the block described by [`WarpSync::warped_header`] and |
339 | | /// [`WarpSync::warped_finality`]. |
340 | | warped_block_ty: WarpedBlockTy, |
341 | | /// See [`Config::code_trie_node_hint`]. |
342 | | code_trie_node_hint: Option<ConfigCodeTrieNodeHint>, |
343 | | /// Starting point of the warp syncing as provided to [`start_warp_sync`], or latest chain |
344 | | /// information that was warp synced to. |
345 | | verified_chain_information: ValidChainInformation, |
346 | | /// See [`Config::num_download_ahead_fragments`]. |
347 | | num_download_ahead_fragments: usize, |
348 | | /// See [`Config::warp_sync_minimum_gap`]. |
349 | | warp_sync_minimum_gap: usize, |
350 | | /// See [`Config::block_number_bytes`]. |
351 | | block_number_bytes: usize, |
352 | | /// See [`Config::download_all_chain_information_storage_proofs`]. |
353 | | download_all_chain_information_storage_proofs: bool, |
354 | | /// List of requests that have been added using [`WarpSync::add_source`]. |
355 | | sources: slab::Slab<Source<TSrc>>, |
356 | | /// Subset of the entries as [`WarpSync::sources`] whose [`Source::finalized_block_height`] |
357 | | /// is `Ok`. Indexed by [`Source::finalized_block_height`]. |
358 | | sources_by_finalized_height: BTreeSet<(u64, SourceId)>, |
359 | | /// List of requests that have been added using [`WarpSync::add_request`]. |
360 | | in_progress_requests: slab::Slab<(SourceId, TRq, RequestDetail)>, |
361 | | /// Identical to [`WarpSync::in_progress_requests`], but indexed differently. |
362 | | in_progress_requests_by_source: BTreeSet<(SourceId, RequestId)>, |
363 | | /// Request that is downloading warp sync fragments, if any has been started yet. |
364 | | warp_sync_fragments_download: Option<RequestId>, |
365 | | /// Queue of fragments that have been downloaded and need to be verified. |
366 | | verify_queue: VecDeque<PendingVerify>, |
367 | | /// State of the download of the runtime and chain information call proofs. |
368 | | runtime_download: RuntimeDownload, |
369 | | /// State of the download of the body of the block. |
370 | | body_download: BodyDownload, |
371 | | /// For each call required by the chain information builder, whether it has been downloaded yet. |
372 | | runtime_calls: |
373 | | hashbrown::HashMap<chain_information::build::RuntimeCall, CallProof, fnv::FnvBuildHasher>, |
374 | | } |
375 | | |
376 | | /// See [`WarpSync::sources`]. |
377 | | #[derive(Debug, Copy, Clone)] |
378 | | struct Source<TSrc> { |
379 | | /// User data chosen by the API user. |
380 | | user_data: TSrc, |
381 | | /// Height of the finalized block of the source, as reported by the source. |
382 | | finalized_block_height: u64, |
383 | | } |
384 | | |
385 | | /// See [`WarpSync::warped_block_ty`]. |
386 | | enum WarpedBlockTy { |
387 | | /// Block is equal to the finalized block in [`WarpSync::verified_chain_information`]. |
388 | | AlreadyVerified, |
389 | | /// Block is known to not be warp-syncable due to an incompatibility between smoldot and |
390 | | /// the chain. |
391 | | KnownBad, |
392 | | /// Block is expected to be warp syncable. |
393 | | Normal, |
394 | | } |
395 | | |
396 | | /// See [`WarpSync::runtime_download`]. |
397 | | enum RuntimeDownload { |
398 | | NotStarted { |
399 | | hint_doesnt_match: bool, |
400 | | }, |
401 | | Downloading { |
402 | | hint_doesnt_match: bool, |
403 | | request_id: RequestId, |
404 | | }, |
405 | | NotVerified { |
406 | | /// Source the runtime has been obtained from. `None` if the source has been removed. |
407 | | downloaded_source: Option<SourceId>, |
408 | | hint_doesnt_match: bool, |
409 | | trie_proof: Vec<u8>, |
410 | | }, |
411 | | Verified { |
412 | | downloaded_runtime: DownloadedRuntime, |
413 | | chain_info_builder: chain_information::build::ChainInformationBuild, |
414 | | }, |
415 | | } |
416 | | |
417 | | /// See [`WarpSync::body_download`]. |
418 | | enum BodyDownload { |
419 | | NotNeeded, |
420 | | NotStarted, |
421 | | Downloading { |
422 | | request_id: RequestId, |
423 | | }, |
424 | | Downloaded { |
425 | | /// Source the body has been obtained from. `None` if the source has been removed. |
426 | | downloaded_source: Option<SourceId>, |
427 | | body: Vec<Vec<u8>>, |
428 | | }, |
429 | | } |
430 | | |
431 | | /// See [`WarpSync::verify_queue`]. |
432 | | struct PendingVerify { |
433 | | /// Source the fragments have been obtained from. `None` if the source has been removed. |
434 | | downloaded_source: Option<SourceId>, |
435 | | /// `true` if the source has indicated that there is no more fragment afterwards, in other |
436 | | /// words that the last fragment corresponds to the current finalized block of the chain. |
437 | | final_set_of_fragments: bool, |
438 | | /// List of fragments to verify. Can be empty. |
439 | | fragments: Vec<WarpSyncFragment>, |
440 | | /// Number of fragments at the start of [`PendingVerify::fragments`] that have already been |
441 | | /// verified. Must always be strictly inferior to `fragments.len()`, unless the list of |
442 | | /// fragments is empty. |
443 | | next_fragment_to_verify_index: usize, |
444 | | } |
445 | | |
446 | | /// See [`RuntimeDownload::Verified`]. |
447 | | struct DownloadedRuntime { |
448 | | /// Storage item at the `:code` key. `None` if there is no entry at that key. |
449 | | storage_code: Option<Vec<u8>>, |
450 | | /// Storage item at the `:heappages` key. `None` if there is no entry at that key. |
451 | | storage_heap_pages: Option<Vec<u8>>, |
452 | | /// Merkle value of the `:code` trie node. `None` if there is no entry at that key. |
453 | | code_merkle_value: Option<Vec<u8>>, |
454 | | /// Closest ancestor of the `:code` key except for `:code` itself. |
455 | | closest_ancestor_excluding: Option<Vec<Nibble>>, |
456 | | } |
457 | | |
458 | | /// See [`WarpSync::runtime_calls`]. |
459 | | enum CallProof { |
460 | | NotStarted, |
461 | | Downloading(RequestId), |
462 | | Downloaded { |
463 | | /// Source the proof has been obtained from. `None` if the source has been removed. |
464 | | downloaded_source: Option<SourceId>, |
465 | | proof: Vec<u8>, |
466 | | }, |
467 | | } |
468 | | |
469 | | /// Returns the default value for [`WarpSync::runtime_calls`]. |
470 | | /// |
471 | | /// Contains the list of calls that we anticipate the chain information builder will make. This |
472 | | /// assumes that the runtime is the latest version available. |
473 | 21 | fn runtime_calls_default_value( |
474 | 21 | verified_chain_information_consensus: chain_information::ChainInformationConsensusRef, |
475 | 21 | ) -> hashbrown::HashMap<chain_information::build::RuntimeCall, CallProof, fnv::FnvBuildHasher> { |
476 | 21 | let mut list = hashbrown::HashMap::with_capacity_and_hasher(8, Default::default()); |
477 | 21 | match verified_chain_information_consensus { |
478 | 21 | ChainInformationConsensusRef::Aura { .. } => { |
479 | 21 | list.insert( |
480 | 21 | chain_information::build::RuntimeCall::AuraApiAuthorities, |
481 | 21 | CallProof::NotStarted, |
482 | 21 | ); |
483 | 21 | list.insert( |
484 | 21 | chain_information::build::RuntimeCall::AuraApiSlotDuration, |
485 | 21 | CallProof::NotStarted, |
486 | 21 | ); |
487 | 21 | } |
488 | 0 | ChainInformationConsensusRef::Babe { .. } => { |
489 | 0 | list.insert( |
490 | 0 | chain_information::build::RuntimeCall::BabeApiCurrentEpoch, |
491 | 0 | CallProof::NotStarted, |
492 | 0 | ); |
493 | 0 | list.insert( |
494 | 0 | chain_information::build::RuntimeCall::BabeApiNextEpoch, |
495 | 0 | CallProof::NotStarted, |
496 | 0 | ); |
497 | 0 | list.insert( |
498 | 0 | chain_information::build::RuntimeCall::BabeApiConfiguration, |
499 | 0 | CallProof::NotStarted, |
500 | 0 | ); |
501 | 0 | } |
502 | 0 | ChainInformationConsensusRef::Unknown => {} |
503 | | } |
504 | 21 | list |
505 | 21 | } Unexecuted instantiation: _RNvNtNtCsN16ciHI6Qf_7smoldot4sync9warp_sync27runtime_calls_default_value _RNvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync27runtime_calls_default_value Line | Count | Source | 473 | 21 | fn runtime_calls_default_value( | 474 | 21 | verified_chain_information_consensus: chain_information::ChainInformationConsensusRef, | 475 | 21 | ) -> hashbrown::HashMap<chain_information::build::RuntimeCall, CallProof, fnv::FnvBuildHasher> { | 476 | 21 | let mut list = hashbrown::HashMap::with_capacity_and_hasher(8, Default::default()); | 477 | 21 | match verified_chain_information_consensus { | 478 | 21 | ChainInformationConsensusRef::Aura { .. } => { | 479 | 21 | list.insert( | 480 | 21 | chain_information::build::RuntimeCall::AuraApiAuthorities, | 481 | 21 | CallProof::NotStarted, | 482 | 21 | ); | 483 | 21 | list.insert( | 484 | 21 | chain_information::build::RuntimeCall::AuraApiSlotDuration, | 485 | 21 | CallProof::NotStarted, | 486 | 21 | ); | 487 | 21 | } | 488 | 0 | ChainInformationConsensusRef::Babe { .. } => { | 489 | 0 | list.insert( | 490 | 0 | chain_information::build::RuntimeCall::BabeApiCurrentEpoch, | 491 | 0 | CallProof::NotStarted, | 492 | 0 | ); | 493 | 0 | list.insert( | 494 | 0 | chain_information::build::RuntimeCall::BabeApiNextEpoch, | 495 | 0 | CallProof::NotStarted, | 496 | 0 | ); | 497 | 0 | list.insert( | 498 | 0 | chain_information::build::RuntimeCall::BabeApiConfiguration, | 499 | 0 | CallProof::NotStarted, | 500 | 0 | ); | 501 | 0 | } | 502 | 0 | ChainInformationConsensusRef::Unknown => {} | 503 | | } | 504 | 21 | list | 505 | 21 | } |
|
506 | | |
507 | | /// See [`WarpSync::status`]. |
508 | | #[derive(Debug)] |
509 | | pub enum Status<'a, TSrc> { |
510 | | /// Warp syncing algorithm is downloading Grandpa warp sync fragments containing a finality |
511 | | /// proof. |
512 | | Fragments { |
513 | | /// Source from which the fragments are currently being downloaded, if any. |
514 | | source: Option<(SourceId, &'a TSrc)>, |
515 | | /// Hash of the highest block that is proven to be finalized. |
516 | | /// |
517 | | /// This isn't necessarily the same block as returned by |
518 | | /// [`WarpSync::as_chain_information`], as this function first has to download |
519 | | /// extra information compared to just the finalized block. |
520 | | finalized_block_hash: [u8; 32], |
521 | | /// Height of the block indicated by [`Status::ChainInformation::finalized_block_hash`]. |
522 | | finalized_block_number: u64, |
523 | | }, |
524 | | /// Warp syncing algorithm has reached the head of the finalized chain and is downloading and |
525 | | /// building the chain information. |
526 | | ChainInformation { |
527 | | /// Hash of the highest block that is proven to be finalized. |
528 | | /// |
529 | | /// This isn't necessarily the same block as returned by |
530 | | /// [`WarpSync::as_chain_information`], as this function first has to download |
531 | | /// extra information compared to just the finalized block. |
532 | | finalized_block_hash: [u8; 32], |
533 | | /// Height of the block indicated by [`Status::ChainInformation::finalized_block_hash`]. |
534 | | finalized_block_number: u64, |
535 | | }, |
536 | | } |
537 | | |
538 | | impl<TSrc, TRq> WarpSync<TSrc, TRq> { |
539 | | /// Returns the value that was initially passed in [`Config::block_number_bytes`]. |
540 | 0 | pub fn block_number_bytes(&self) -> usize { |
541 | 0 | self.block_number_bytes |
542 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE18block_number_bytesB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE18block_number_bytesCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE18block_number_bytesB8_ |
543 | | |
544 | | /// Returns the chain information that is considered verified. |
545 | 0 | pub fn as_chain_information(&self) -> ValidChainInformationRef { |
546 | 0 | // Note: after verifying a warp sync fragment, we are certain that the header targeted by |
547 | 0 | // this fragment is indeed part of the chain. However, this is not enough in order to |
548 | 0 | // produce a full chain information struct. Such struct can only be produced after the |
549 | 0 | // entire warp syncing has succeeded. If if it still in progress, all we can return is |
550 | 0 | // the starting point. |
551 | 0 | (&self.verified_chain_information).into() |
552 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE20as_chain_informationB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20as_chain_informationCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE20as_chain_informationB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20as_chain_informationCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20as_chain_informationCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20as_chain_informationCsibGXYHQB8Ea_25json_rpc_general_requests |
553 | | |
554 | | /// Modifies the chain information known to be valid. |
555 | 0 | pub fn set_chain_information(&mut self, chain_information: ValidChainInformationRef) { |
556 | 0 | // The implementation simply resets the state machine, apart from the fragment download |
557 | 0 | // and verification queue. |
558 | 0 | // TODO: what if the new chain doesn't support grandpa? |
559 | 0 | if self.warped_header_number <= chain_information.as_ref().finalized_block_header.number { |
560 | 0 | self.warped_header = chain_information |
561 | 0 | .as_ref() |
562 | 0 | .finalized_block_header |
563 | 0 | .scale_encoding_vec(self.block_number_bytes); |
564 | 0 | self.warped_header_hash = chain_information |
565 | 0 | .as_ref() |
566 | 0 | .finalized_block_header |
567 | 0 | .hash(self.block_number_bytes); |
568 | 0 | self.warped_header_state_root = |
569 | 0 | *chain_information.as_ref().finalized_block_header.state_root; |
570 | 0 | self.warped_header_extrinsics_root = *chain_information |
571 | 0 | .as_ref() |
572 | 0 | .finalized_block_header |
573 | 0 | .extrinsics_root; |
574 | 0 | self.warped_header_number = chain_information.as_ref().finalized_block_header.number; |
575 | 0 | self.warped_finality = chain_information.as_ref().finality.into(); |
576 | 0 | self.warped_block_ty = WarpedBlockTy::AlreadyVerified; |
577 | 0 |
|
578 | 0 | self.verified_chain_information = chain_information.into(); |
579 | 0 | self.runtime_calls = |
580 | 0 | runtime_calls_default_value(self.verified_chain_information.as_ref().consensus); |
581 | 0 |
|
582 | 0 | self.runtime_download = RuntimeDownload::NotStarted { |
583 | 0 | hint_doesnt_match: false, |
584 | 0 | }; |
585 | | |
586 | 0 | if !matches!(self.body_download, BodyDownload::NotNeeded) { |
587 | 0 | self.body_download = BodyDownload::NotStarted; |
588 | 0 | } |
589 | 0 | } |
590 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE21set_chain_informationB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21set_chain_informationCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE21set_chain_informationB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21set_chain_informationCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21set_chain_informationCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21set_chain_informationCsibGXYHQB8Ea_25json_rpc_general_requests |
591 | | |
592 | | /// Returns the current status of the warp syncing. |
593 | 0 | pub fn status(&self) -> Status<TSrc> { |
594 | 0 | match &self.runtime_download { |
595 | | RuntimeDownload::NotStarted { .. } => { |
596 | 0 | let finalized_block_hash = self.warped_header_hash; |
597 | | |
598 | 0 | let source_id = |
599 | 0 | if let Some(warp_sync_fragments_download) = self.warp_sync_fragments_download { |
600 | 0 | Some( |
601 | 0 | self.in_progress_requests |
602 | 0 | .get(warp_sync_fragments_download.0) |
603 | 0 | .unwrap() |
604 | 0 | .0, |
605 | 0 | ) |
606 | | } else { |
607 | 0 | self.verify_queue.back().and_then(|f| f.downloaded_source) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE6status0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE6status0Ba_ |
608 | | }; |
609 | | |
610 | 0 | Status::Fragments { |
611 | 0 | source: source_id.map(|id| (id, &self.sources[id.0].user_data)), Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE6statuss_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE6statuss_0Ba_ |
612 | 0 | finalized_block_hash, |
613 | 0 | finalized_block_number: self.warped_header_number, |
614 | 0 | } |
615 | | } |
616 | 0 | _ => Status::ChainInformation { |
617 | 0 | finalized_block_hash: self.warped_header_hash, |
618 | 0 | finalized_block_number: self.warped_header_number, |
619 | 0 | }, |
620 | | } |
621 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE6statusB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE6statusB8_ |
622 | | |
623 | | /// Returns a list of all known sources stored in the state machine. |
624 | 0 | pub fn sources(&'_ self) -> impl Iterator<Item = SourceId> + '_ { |
625 | 0 | self.sources.iter().map(|(id, _)| SourceId(id)) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE7sources0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE7sources0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE7sources0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE7sources0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE7sources0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE7sources0CsibGXYHQB8Ea_25json_rpc_general_requests |
626 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE7sourcesB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE7sourcesCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE7sourcesB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE7sourcesCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE7sourcesCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE7sourcesCsibGXYHQB8Ea_25json_rpc_general_requests |
627 | | |
628 | | /// Returns the number of ongoing requests that concern this source. |
629 | | /// |
630 | | /// # Panic |
631 | | /// |
632 | | /// Panics if the [`SourceId`] is invalid. |
633 | | /// |
634 | 0 | pub fn source_num_ongoing_requests(&self, source_id: SourceId) -> usize { |
635 | 0 | assert!(self.sources.contains(source_id.0)); |
636 | 0 | self.in_progress_requests_by_source |
637 | 0 | .range((source_id, RequestId(usize::MIN))..=(source_id, RequestId(usize::MAX))) |
638 | 0 | .count() |
639 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE27source_num_ongoing_requestsB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE27source_num_ongoing_requestsB8_ |
640 | | |
641 | | /// Add a source to the list of sources. |
642 | | /// |
643 | | /// The source has a finalized block height of 0, which should later be updated using |
644 | | /// [`WarpSync::set_source_finality_state`]. |
645 | 21 | pub fn add_source(&mut self, user_data: TSrc) -> SourceId { |
646 | 21 | let source_id = SourceId(self.sources.insert(Source { |
647 | 21 | user_data, |
648 | 21 | finalized_block_height: 0, |
649 | 21 | })); |
650 | 21 | |
651 | 21 | let _inserted = self.sources_by_finalized_height.insert((0, source_id)); |
652 | 21 | debug_assert!(_inserted); |
653 | 21 | debug_assert!(self.sources.len() >= self.sources_by_finalized_height.len()); |
654 | | |
655 | 21 | source_id |
656 | 21 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE10add_sourceB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE10add_sourceCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE10add_sourceB8_ _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE10add_sourceCsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 645 | 2 | pub fn add_source(&mut self, user_data: TSrc) -> SourceId { | 646 | 2 | let source_id = SourceId(self.sources.insert(Source { | 647 | 2 | user_data, | 648 | 2 | finalized_block_height: 0, | 649 | 2 | })); | 650 | 2 | | 651 | 2 | let _inserted = self.sources_by_finalized_height.insert((0, source_id)); | 652 | 2 | debug_assert!(_inserted); | 653 | 2 | debug_assert!(self.sources.len() >= self.sources_by_finalized_height.len()); | 654 | | | 655 | 2 | source_id | 656 | 2 | } |
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE10add_sourceCscDgN54JpMGG_6author _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE10add_sourceCsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 645 | 19 | pub fn add_source(&mut self, user_data: TSrc) -> SourceId { | 646 | 19 | let source_id = SourceId(self.sources.insert(Source { | 647 | 19 | user_data, | 648 | 19 | finalized_block_height: 0, | 649 | 19 | })); | 650 | 19 | | 651 | 19 | let _inserted = self.sources_by_finalized_height.insert((0, source_id)); | 652 | 19 | debug_assert!(_inserted); | 653 | 19 | debug_assert!(self.sources.len() >= self.sources_by_finalized_height.len()); | 654 | | | 655 | 19 | source_id | 656 | 19 | } |
|
657 | | |
658 | | /// Removes a source from the list of sources. In addition to the user data associated to this |
659 | | /// source, also returns a list of requests that were in progress concerning this source. These |
660 | | /// requests are now considered obsolete. |
661 | | /// |
662 | | /// # Panic |
663 | | /// |
664 | | /// Panics if the [`SourceId`] is invalid. |
665 | | /// |
666 | 0 | pub fn remove_source( |
667 | 0 | &'_ mut self, |
668 | 0 | to_remove: SourceId, |
669 | 0 | ) -> (TSrc, impl Iterator<Item = (RequestId, TRq)> + '_) { |
670 | 0 | debug_assert!(self.sources.contains(to_remove.0)); |
671 | 0 | let removed = self.sources.remove(to_remove.0); |
672 | 0 | let _was_in = self |
673 | 0 | .sources_by_finalized_height |
674 | 0 | .remove(&(removed.finalized_block_height, to_remove)); |
675 | 0 | debug_assert!(_was_in); |
676 | 0 | debug_assert!(self.sources.len() >= self.sources_by_finalized_height.len()); |
677 | | |
678 | | // We make sure to not leave invalid source IDs in the state of `self`. |
679 | | // TODO: O(n) |
680 | 0 | for item in &mut self.verify_queue { |
681 | 0 | if item.downloaded_source == Some(to_remove) { |
682 | 0 | item.downloaded_source = None; |
683 | 0 | } |
684 | | } |
685 | | if let RuntimeDownload::NotVerified { |
686 | 0 | downloaded_source, .. |
687 | 0 | } = &mut self.runtime_download |
688 | | { |
689 | 0 | if *downloaded_source == Some(to_remove) { |
690 | 0 | *downloaded_source = None; |
691 | 0 | } |
692 | 0 | } |
693 | | if let BodyDownload::Downloaded { |
694 | 0 | downloaded_source, .. |
695 | 0 | } = &mut self.body_download |
696 | | { |
697 | 0 | if *downloaded_source == Some(to_remove) { |
698 | 0 | *downloaded_source = None; |
699 | 0 | } |
700 | 0 | } |
701 | 0 | for (_, call_proof) in &mut self.runtime_calls { |
702 | | if let CallProof::Downloaded { |
703 | 0 | downloaded_source, .. |
704 | 0 | } = call_proof |
705 | | { |
706 | 0 | if *downloaded_source == Some(to_remove) { |
707 | 0 | *downloaded_source = None; |
708 | 0 | } |
709 | 0 | } |
710 | | } |
711 | | |
712 | 0 | let obsolete_requests_indices = self |
713 | 0 | .in_progress_requests_by_source |
714 | 0 | .range((to_remove, RequestId(usize::MIN))..=(to_remove, RequestId(usize::MAX))) |
715 | 0 | .map(|(_, rq_id)| rq_id.0) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE13remove_source0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE13remove_source0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE13remove_source0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE13remove_source0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE13remove_source0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE13remove_source0CsibGXYHQB8Ea_25json_rpc_general_requests |
716 | 0 | .collect::<Vec<_>>(); |
717 | 0 | let mut obsolete_requests = Vec::with_capacity(obsolete_requests_indices.len()); |
718 | 0 | for index in obsolete_requests_indices { |
719 | 0 | let (_, user_data, _) = self.in_progress_requests.remove(index); |
720 | 0 | self.in_progress_requests_by_source |
721 | 0 | .remove(&(to_remove, RequestId(index))); |
722 | 0 | if self.warp_sync_fragments_download == Some(RequestId(index)) { |
723 | 0 | self.warp_sync_fragments_download = None; |
724 | 0 | } |
725 | 0 | for call in self.runtime_calls.values_mut() { |
726 | 0 | if matches!(call, CallProof::Downloading(rq_id) if *rq_id == RequestId(index)) { |
727 | 0 | *call = CallProof::NotStarted; |
728 | 0 | } |
729 | | } |
730 | | if let RuntimeDownload::Downloading { |
731 | 0 | request_id, |
732 | 0 | hint_doesnt_match, |
733 | 0 | } = &mut self.runtime_download |
734 | | { |
735 | 0 | if *request_id == RequestId(index) { |
736 | 0 | self.runtime_download = RuntimeDownload::NotStarted { |
737 | 0 | hint_doesnt_match: *hint_doesnt_match, |
738 | 0 | }; |
739 | 0 | } |
740 | 0 | } |
741 | 0 | if let BodyDownload::Downloading { request_id } = &mut self.body_download { |
742 | 0 | if *request_id == RequestId(index) { |
743 | 0 | self.body_download = BodyDownload::NotStarted; |
744 | 0 | } |
745 | 0 | } |
746 | 0 | obsolete_requests.push((RequestId(index), user_data)); |
747 | | } |
748 | | |
749 | 0 | (removed.user_data, obsolete_requests.into_iter()) |
750 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE13remove_sourceB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE13remove_sourceCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE13remove_sourceB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE13remove_sourceCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE13remove_sourceCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE13remove_sourceCsibGXYHQB8Ea_25json_rpc_general_requests |
751 | | |
752 | | /// Sets the finalized block height of the given source. |
753 | | /// |
754 | | /// # Panic |
755 | | /// |
756 | | /// Panics if `source_id` is invalid. |
757 | | /// |
758 | 0 | pub fn set_source_finality_state(&mut self, source_id: SourceId, finalized_block_height: u64) { |
759 | 0 | let stored_height = &mut self.sources[source_id.0].finalized_block_height; |
760 | 0 |
|
761 | 0 | // Small optimization. No need to do anything more if the block doesn't actuall change. |
762 | 0 | if *stored_height == finalized_block_height { |
763 | 0 | return; |
764 | 0 | } |
765 | 0 |
|
766 | 0 | // Note that if the new finalized block is below the former one (which is not something |
767 | 0 | // that is ever supposed to happen), we should in principle cancel the requests |
768 | 0 | // targeting that source that require a specific block height. In practice, however, |
769 | 0 | // we don't care as again this isn't supposed to ever happen. While ongoing requests |
770 | 0 | // might fail as a result, this is handled the same way as a regular request failure. |
771 | 0 |
|
772 | 0 | let _was_in = self |
773 | 0 | .sources_by_finalized_height |
774 | 0 | .remove(&(*stored_height, source_id)); |
775 | 0 | debug_assert!(_was_in); |
776 | 0 | let _inserted = self |
777 | 0 | .sources_by_finalized_height |
778 | 0 | .insert((finalized_block_height, source_id)); |
779 | 0 | debug_assert!(_inserted); |
780 | | |
781 | 0 | *stored_height = finalized_block_height; |
782 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE25set_source_finality_stateB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE25set_source_finality_stateCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE25set_source_finality_stateB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE25set_source_finality_stateCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE25set_source_finality_stateCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE25set_source_finality_stateCsibGXYHQB8Ea_25json_rpc_general_requests |
783 | | |
784 | | /// Gets the finalized block height of the given source. |
785 | | /// |
786 | | /// Equal to 0 if [`WarpSync::set_source_finality_state`] hasn't been called. |
787 | | /// |
788 | | /// # Panic |
789 | | /// |
790 | | /// Panics if `source_id` is invalid. |
791 | | /// |
792 | 0 | pub fn source_finality_state(&self, source_id: SourceId) -> u64 { |
793 | 0 | self.sources[source_id.0].finalized_block_height |
794 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE21source_finality_stateB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21source_finality_stateCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE21source_finality_stateB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21source_finality_stateCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21source_finality_stateCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE21source_finality_stateCsibGXYHQB8Ea_25json_rpc_general_requests |
795 | | |
796 | | /// Returns a list of requests that should be started in order to drive the warp syncing |
797 | | /// process to completion. |
798 | | /// |
799 | | /// Once a request that matches a desired request is added through |
800 | | /// [`WarpSync::add_request`], it is no longer returned by this function. |
801 | 43 | pub fn desired_requests( |
802 | 43 | &'_ self, |
803 | 43 | ) -> impl Iterator<Item = (SourceId, &'_ TSrc, DesiredRequest)> + '_ { |
804 | | // If we are in the fragments download phase, return a fragments download request. |
805 | 43 | let mut desired_warp_sync_request = if self.warp_sync_fragments_download.is_none() { |
806 | 43 | if self.verify_queue.iter().fold(0, |sum, entry| { |
807 | 0 | sum + entry.fragments.len() - entry.next_fragment_to_verify_index |
808 | 43 | }) < self.num_download_ahead_fragments Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requests0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requests0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requests0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requests0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requests0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requests0CsibGXYHQB8Ea_25json_rpc_general_requests |
809 | | { |
810 | | // Block hash to request. |
811 | 43 | let start_block_hash = self |
812 | 43 | .verify_queue |
813 | 43 | .back() |
814 | 43 | .and_then(|entry| entry.fragments.last()0 ) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss_0CsibGXYHQB8Ea_25json_rpc_general_requests |
815 | 43 | .map(|fragment| { |
816 | 0 | header::hash_from_scale_encoded_header(&fragment.scale_encoded_header) |
817 | 43 | }) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss0_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss0_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss0_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss0_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss0_0CsibGXYHQB8Ea_25json_rpc_general_requests |
818 | 43 | .unwrap_or(self.warped_header_hash); |
819 | 43 | |
820 | 43 | // Calculate the block number at the tail of the verify queue. |
821 | 43 | // Contains `None` if the verify queue has a problem such as an indecodable header. |
822 | 43 | // In that situation, we don't start any new request and wait for the verify |
823 | 43 | // queue to empty itself. |
824 | 43 | let verify_queue_tail_block_number = self |
825 | 43 | .verify_queue |
826 | 43 | .back() |
827 | 43 | .map(|entry| { |
828 | 0 | entry |
829 | 0 | .fragments |
830 | 0 | .last() |
831 | 0 | .and_then(|fragment| { |
832 | 0 | header::decode( |
833 | 0 | &fragment.scale_encoded_header, |
834 | 0 | self.block_number_bytes, |
835 | 0 | ) |
836 | 0 | .ok() |
837 | 0 | }) Unexecuted instantiation: _RNCNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss1_00Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_00CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss1_00Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_00CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_00CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_00CsibGXYHQB8Ea_25json_rpc_general_requests |
838 | 0 | .map(|header| header.number) Unexecuted instantiation: _RNCNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss1_0s_0Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_0s_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss1_0s_0Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_0s_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_0s_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss1_0s_0CsibGXYHQB8Ea_25json_rpc_general_requests |
839 | 43 | }) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss1_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss1_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss1_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss1_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss1_0CsibGXYHQB8Ea_25json_rpc_general_requests |
840 | 43 | .unwrap_or(Some(self.warped_header_number)); |
841 | 43 | let warp_sync_minimum_gap = self.warp_sync_minimum_gap; |
842 | | |
843 | 43 | if let Some(verify_queue_tail_block_number) = verify_queue_tail_block_number { |
844 | | // Combine the request with every single available source. |
845 | 43 | either::Left(self.sources.iter().filter_map(move |(src_id, src)| { |
846 | 43 | if src.finalized_block_height |
847 | 43 | <= verify_queue_tail_block_number.saturating_add( |
848 | 43 | u64::try_from(warp_sync_minimum_gap).unwrap_or(u64::MAX), |
849 | 43 | ) |
850 | | { |
851 | 43 | return None; |
852 | 0 | } |
853 | 0 |
|
854 | 0 | Some(( |
855 | 0 | SourceId(src_id), |
856 | 0 | &src.user_data, |
857 | 0 | DesiredRequest::WarpSyncRequest { |
858 | 0 | block_hash: start_block_hash, |
859 | 0 | }, |
860 | 0 | )) |
861 | 43 | })) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss2_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss2_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss2_0Ba_ _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss2_0CsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 845 | 4 | either::Left(self.sources.iter().filter_map(move |(src_id, src)| { | 846 | 4 | if src.finalized_block_height | 847 | 4 | <= verify_queue_tail_block_number.saturating_add( | 848 | 4 | u64::try_from(warp_sync_minimum_gap).unwrap_or(u64::MAX), | 849 | 4 | ) | 850 | | { | 851 | 4 | return None; | 852 | 0 | } | 853 | 0 |
| 854 | 0 | Some(( | 855 | 0 | SourceId(src_id), | 856 | 0 | &src.user_data, | 857 | 0 | DesiredRequest::WarpSyncRequest { | 858 | 0 | block_hash: start_block_hash, | 859 | 0 | }, | 860 | 0 | )) | 861 | 4 | })) |
Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss2_0CscDgN54JpMGG_6author _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss2_0CsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 845 | 39 | either::Left(self.sources.iter().filter_map(move |(src_id, src)| { | 846 | 39 | if src.finalized_block_height | 847 | 39 | <= verify_queue_tail_block_number.saturating_add( | 848 | 39 | u64::try_from(warp_sync_minimum_gap).unwrap_or(u64::MAX), | 849 | 39 | ) | 850 | | { | 851 | 39 | return None; | 852 | 0 | } | 853 | 0 |
| 854 | 0 | Some(( | 855 | 0 | SourceId(src_id), | 856 | 0 | &src.user_data, | 857 | 0 | DesiredRequest::WarpSyncRequest { | 858 | 0 | block_hash: start_block_hash, | 859 | 0 | }, | 860 | 0 | )) | 861 | 39 | })) |
|
862 | | } else { |
863 | 0 | either::Right(iter::empty()) |
864 | | } |
865 | | } else { |
866 | 0 | either::Right(iter::empty()) |
867 | | } |
868 | | } else { |
869 | 0 | either::Right(iter::empty()) |
870 | | } |
871 | 43 | .peekable(); |
872 | | |
873 | | // If we are in the appropriate phase, and we are not currently downloading the runtime, |
874 | | // return a runtime download request. |
875 | 43 | let desired_runtime_parameters_get = if let ( |
876 | | WarpedBlockTy::Normal, |
877 | 0 | RuntimeDownload::NotStarted { hint_doesnt_match }, |
878 | | None, |
879 | | true, |
880 | | None, |
881 | 43 | ) = ( |
882 | 43 | &self.warped_block_ty, |
883 | 43 | &self.runtime_download, |
884 | 43 | self.warp_sync_fragments_download, |
885 | 43 | self.verify_queue.is_empty(), |
886 | 43 | desired_warp_sync_request.peek(), |
887 | 43 | ) { |
888 | 0 | let code_key_to_request = if let (false, Some(hint)) = |
889 | 0 | (*hint_doesnt_match, self.code_trie_node_hint.as_ref()) |
890 | | { |
891 | 0 | Cow::Owned( |
892 | 0 | trie::nibbles_to_bytes_truncate( |
893 | 0 | hint.closest_ancestor_excluding.iter().copied(), |
894 | 0 | ) |
895 | 0 | .collect::<Vec<_>>(), |
896 | 0 | ) |
897 | | } else { |
898 | 0 | Cow::Borrowed(&b":code"[..]) |
899 | | }; |
900 | | |
901 | | // Sources are ordered by increasing finalized block height, in order to |
902 | | // have the highest chance for the block to not be pruned. |
903 | 0 | let sources_with_block = self |
904 | 0 | .sources_by_finalized_height |
905 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) |
906 | 0 | .map(|(_, src_id)| src_id); Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss3_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss3_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss3_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss3_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss3_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss3_0CsibGXYHQB8Ea_25json_rpc_general_requests |
907 | 0 |
|
908 | 0 | either::Left(sources_with_block.map(move |source_id| { |
909 | 0 | ( |
910 | 0 | *source_id, |
911 | 0 | &self.sources[source_id.0].user_data, |
912 | 0 | DesiredRequest::StorageGetMerkleProof { |
913 | 0 | block_hash: self.warped_header_hash, |
914 | 0 | state_trie_root: self.warped_header_state_root, |
915 | 0 | keys: vec![code_key_to_request.to_vec(), b":heappages".to_vec()], |
916 | 0 | }, |
917 | 0 | ) |
918 | 0 | })) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss4_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss4_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss4_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss4_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss4_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss4_0CsibGXYHQB8Ea_25json_rpc_general_requests |
919 | | } else { |
920 | 43 | either::Right(iter::empty()) |
921 | | }; |
922 | | |
923 | | // If we are in the appropriate phase, and we are not currently downloading the body of |
924 | | // the block, return a runtime download request. |
925 | 43 | let desired_body_download = |
926 | 43 | if let (WarpedBlockTy::Normal, BodyDownload::NotStarted, None, true, None)0 = ( |
927 | 43 | &self.warped_block_ty, |
928 | 43 | &self.body_download, |
929 | 43 | self.warp_sync_fragments_download, |
930 | 43 | self.verify_queue.is_empty(), |
931 | 43 | desired_warp_sync_request.peek(), |
932 | 43 | ) { |
933 | | // Sources are ordered by increasing finalized block height, in order to |
934 | | // have the highest chance for the block to not be pruned. |
935 | 0 | let sources_with_block = self |
936 | 0 | .sources_by_finalized_height |
937 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) |
938 | 0 | .map(|(_, src_id)| src_id); Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss5_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss5_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss5_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss5_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss5_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss5_0CsibGXYHQB8Ea_25json_rpc_general_requests |
939 | 0 |
|
940 | 0 | either::Left(sources_with_block.map(move |source_id| { |
941 | 0 | ( |
942 | 0 | *source_id, |
943 | 0 | &self.sources[source_id.0].user_data, |
944 | 0 | DesiredRequest::BlockBodyDownload { |
945 | 0 | block_hash: self.warped_header_hash, |
946 | 0 | block_number: self.warped_header_number, |
947 | 0 | extrinsics_root: self.warped_header_extrinsics_root, |
948 | 0 | }, |
949 | 0 | ) |
950 | 0 | })) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss6_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss6_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss6_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss6_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss6_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss6_0CsibGXYHQB8Ea_25json_rpc_general_requests |
951 | | } else { |
952 | 43 | either::Right(iter::empty()) |
953 | | }; |
954 | | |
955 | | // Return the list of runtime calls indicated by the chain information builder state |
956 | | // machine. |
957 | 43 | let desired_call_proofs = if matches!(self.warped_block_ty, WarpedBlockTy::Normal) |
958 | 0 | && self.warp_sync_fragments_download.is_none() |
959 | 0 | && self.verify_queue.is_empty() |
960 | 0 | && desired_warp_sync_request.peek().is_none() |
961 | | { |
962 | 0 | either::Left( |
963 | 0 | self.runtime_calls |
964 | 0 | .iter() |
965 | 0 | .filter(|(_, v)| matches!(v, CallProof::NotStarted)) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss7_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss7_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss7_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss7_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss7_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss7_0CsibGXYHQB8Ea_25json_rpc_general_requests |
966 | 0 | .map(|(call, _)| DesiredRequest::RuntimeCallMerkleProof { |
967 | 0 | block_hash: self.warped_header_hash, |
968 | 0 | function_name: call.function_name().into(), |
969 | 0 | parameter_vectored: Cow::Owned(call.parameter_vectored_vec()), |
970 | 0 | }) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss8_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss8_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss8_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss8_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss8_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss8_0CsibGXYHQB8Ea_25json_rpc_general_requests |
971 | 0 | .flat_map(move |request_detail| { |
972 | 0 | // Sources are ordered by increasing finalized block height, in order to |
973 | 0 | // have the highest chance for the block to not be pruned. |
974 | 0 | let sources_with_block = self |
975 | 0 | .sources_by_finalized_height |
976 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) |
977 | 0 | .map(|(_, src_id)| src_id); Unexecuted instantiation: _RNCNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss9_00Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_00CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss9_00Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_00CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_00CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_00CsibGXYHQB8Ea_25json_rpc_general_requests |
978 | 0 |
|
979 | 0 | sources_with_block.map(move |source_id| { |
980 | 0 | ( |
981 | 0 | *source_id, |
982 | 0 | &self.sources[source_id.0].user_data, |
983 | 0 | request_detail.clone(), |
984 | 0 | ) |
985 | 0 | }) Unexecuted instantiation: _RNCNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss9_0s_0Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_0s_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncppE16desired_requestss9_0s_0Bc_ Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_0s_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_0s_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB8_8WarpSyncNtNtBa_3all19WarpSyncSourceExtraNtB14_20WarpSyncRequestExtraE16desired_requestss9_0s_0CsibGXYHQB8Ea_25json_rpc_general_requests |
986 | 0 | }), Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss9_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss9_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE16desired_requestss9_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss9_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss9_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE16desired_requestss9_0CsibGXYHQB8Ea_25json_rpc_general_requests |
987 | 0 | ) |
988 | | } else { |
989 | 43 | either::Right(iter::empty()) |
990 | | }; |
991 | | |
992 | | // Chain all these demanded requests together. |
993 | 43 | desired_warp_sync_request |
994 | 43 | .chain(desired_runtime_parameters_get) |
995 | 43 | .chain(desired_body_download) |
996 | 43 | .chain(desired_call_proofs) |
997 | 43 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE16desired_requestsB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE16desired_requestsCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE16desired_requestsB8_ _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE16desired_requestsCsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 801 | 4 | pub fn desired_requests( | 802 | 4 | &'_ self, | 803 | 4 | ) -> impl Iterator<Item = (SourceId, &'_ TSrc, DesiredRequest)> + '_ { | 804 | | // If we are in the fragments download phase, return a fragments download request. | 805 | 4 | let mut desired_warp_sync_request = if self.warp_sync_fragments_download.is_none() { | 806 | 4 | if self.verify_queue.iter().fold(0, |sum, entry| { | 807 | | sum + entry.fragments.len() - entry.next_fragment_to_verify_index | 808 | 4 | }) < self.num_download_ahead_fragments | 809 | | { | 810 | | // Block hash to request. | 811 | 4 | let start_block_hash = self | 812 | 4 | .verify_queue | 813 | 4 | .back() | 814 | 4 | .and_then(|entry| entry.fragments.last()) | 815 | 4 | .map(|fragment| { | 816 | | header::hash_from_scale_encoded_header(&fragment.scale_encoded_header) | 817 | 4 | }) | 818 | 4 | .unwrap_or(self.warped_header_hash); | 819 | 4 | | 820 | 4 | // Calculate the block number at the tail of the verify queue. | 821 | 4 | // Contains `None` if the verify queue has a problem such as an indecodable header. | 822 | 4 | // In that situation, we don't start any new request and wait for the verify | 823 | 4 | // queue to empty itself. | 824 | 4 | let verify_queue_tail_block_number = self | 825 | 4 | .verify_queue | 826 | 4 | .back() | 827 | 4 | .map(|entry| { | 828 | | entry | 829 | | .fragments | 830 | | .last() | 831 | | .and_then(|fragment| { | 832 | | header::decode( | 833 | | &fragment.scale_encoded_header, | 834 | | self.block_number_bytes, | 835 | | ) | 836 | | .ok() | 837 | | }) | 838 | | .map(|header| header.number) | 839 | 4 | }) | 840 | 4 | .unwrap_or(Some(self.warped_header_number)); | 841 | 4 | let warp_sync_minimum_gap = self.warp_sync_minimum_gap; | 842 | | | 843 | 4 | if let Some(verify_queue_tail_block_number) = verify_queue_tail_block_number { | 844 | | // Combine the request with every single available source. | 845 | 4 | either::Left(self.sources.iter().filter_map(move |(src_id, src)| { | 846 | | if src.finalized_block_height | 847 | | <= verify_queue_tail_block_number.saturating_add( | 848 | | u64::try_from(warp_sync_minimum_gap).unwrap_or(u64::MAX), | 849 | | ) | 850 | | { | 851 | | return None; | 852 | | } | 853 | | | 854 | | Some(( | 855 | | SourceId(src_id), | 856 | | &src.user_data, | 857 | | DesiredRequest::WarpSyncRequest { | 858 | | block_hash: start_block_hash, | 859 | | }, | 860 | | )) | 861 | 4 | })) | 862 | | } else { | 863 | 0 | either::Right(iter::empty()) | 864 | | } | 865 | | } else { | 866 | 0 | either::Right(iter::empty()) | 867 | | } | 868 | | } else { | 869 | 0 | either::Right(iter::empty()) | 870 | | } | 871 | 4 | .peekable(); | 872 | | | 873 | | // If we are in the appropriate phase, and we are not currently downloading the runtime, | 874 | | // return a runtime download request. | 875 | 4 | let desired_runtime_parameters_get = if let ( | 876 | | WarpedBlockTy::Normal, | 877 | 0 | RuntimeDownload::NotStarted { hint_doesnt_match }, | 878 | | None, | 879 | | true, | 880 | | None, | 881 | 4 | ) = ( | 882 | 4 | &self.warped_block_ty, | 883 | 4 | &self.runtime_download, | 884 | 4 | self.warp_sync_fragments_download, | 885 | 4 | self.verify_queue.is_empty(), | 886 | 4 | desired_warp_sync_request.peek(), | 887 | 4 | ) { | 888 | 0 | let code_key_to_request = if let (false, Some(hint)) = | 889 | 0 | (*hint_doesnt_match, self.code_trie_node_hint.as_ref()) | 890 | | { | 891 | 0 | Cow::Owned( | 892 | 0 | trie::nibbles_to_bytes_truncate( | 893 | 0 | hint.closest_ancestor_excluding.iter().copied(), | 894 | 0 | ) | 895 | 0 | .collect::<Vec<_>>(), | 896 | 0 | ) | 897 | | } else { | 898 | 0 | Cow::Borrowed(&b":code"[..]) | 899 | | }; | 900 | | | 901 | | // Sources are ordered by increasing finalized block height, in order to | 902 | | // have the highest chance for the block to not be pruned. | 903 | 0 | let sources_with_block = self | 904 | 0 | .sources_by_finalized_height | 905 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) | 906 | 0 | .map(|(_, src_id)| src_id); | 907 | 0 |
| 908 | 0 | either::Left(sources_with_block.map(move |source_id| { | 909 | | ( | 910 | | *source_id, | 911 | | &self.sources[source_id.0].user_data, | 912 | | DesiredRequest::StorageGetMerkleProof { | 913 | | block_hash: self.warped_header_hash, | 914 | | state_trie_root: self.warped_header_state_root, | 915 | | keys: vec![code_key_to_request.to_vec(), b":heappages".to_vec()], | 916 | | }, | 917 | | ) | 918 | 0 | })) | 919 | | } else { | 920 | 4 | either::Right(iter::empty()) | 921 | | }; | 922 | | | 923 | | // If we are in the appropriate phase, and we are not currently downloading the body of | 924 | | // the block, return a runtime download request. | 925 | 4 | let desired_body_download = | 926 | 4 | if let (WarpedBlockTy::Normal, BodyDownload::NotStarted, None, true, None)0 = ( | 927 | 4 | &self.warped_block_ty, | 928 | 4 | &self.body_download, | 929 | 4 | self.warp_sync_fragments_download, | 930 | 4 | self.verify_queue.is_empty(), | 931 | 4 | desired_warp_sync_request.peek(), | 932 | 4 | ) { | 933 | | // Sources are ordered by increasing finalized block height, in order to | 934 | | // have the highest chance for the block to not be pruned. | 935 | 0 | let sources_with_block = self | 936 | 0 | .sources_by_finalized_height | 937 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) | 938 | 0 | .map(|(_, src_id)| src_id); | 939 | 0 |
| 940 | 0 | either::Left(sources_with_block.map(move |source_id| { | 941 | | ( | 942 | | *source_id, | 943 | | &self.sources[source_id.0].user_data, | 944 | | DesiredRequest::BlockBodyDownload { | 945 | | block_hash: self.warped_header_hash, | 946 | | block_number: self.warped_header_number, | 947 | | extrinsics_root: self.warped_header_extrinsics_root, | 948 | | }, | 949 | | ) | 950 | 0 | })) | 951 | | } else { | 952 | 4 | either::Right(iter::empty()) | 953 | | }; | 954 | | | 955 | | // Return the list of runtime calls indicated by the chain information builder state | 956 | | // machine. | 957 | 4 | let desired_call_proofs = if matches!(self.warped_block_ty, WarpedBlockTy::Normal) | 958 | 0 | && self.warp_sync_fragments_download.is_none() | 959 | 0 | && self.verify_queue.is_empty() | 960 | 0 | && desired_warp_sync_request.peek().is_none() | 961 | | { | 962 | 0 | either::Left( | 963 | 0 | self.runtime_calls | 964 | 0 | .iter() | 965 | 0 | .filter(|(_, v)| matches!(v, CallProof::NotStarted)) | 966 | 0 | .map(|(call, _)| DesiredRequest::RuntimeCallMerkleProof { | 967 | | block_hash: self.warped_header_hash, | 968 | | function_name: call.function_name().into(), | 969 | | parameter_vectored: Cow::Owned(call.parameter_vectored_vec()), | 970 | 0 | }) | 971 | 0 | .flat_map(move |request_detail| { | 972 | | // Sources are ordered by increasing finalized block height, in order to | 973 | | // have the highest chance for the block to not be pruned. | 974 | | let sources_with_block = self | 975 | | .sources_by_finalized_height | 976 | | .range((self.warped_header_number, SourceId(usize::MIN))..) | 977 | | .map(|(_, src_id)| src_id); | 978 | | | 979 | | sources_with_block.map(move |source_id| { | 980 | | ( | 981 | | *source_id, | 982 | | &self.sources[source_id.0].user_data, | 983 | | request_detail.clone(), | 984 | | ) | 985 | | }) | 986 | 0 | }), | 987 | 0 | ) | 988 | | } else { | 989 | 4 | either::Right(iter::empty()) | 990 | | }; | 991 | | | 992 | | // Chain all these demanded requests together. | 993 | 4 | desired_warp_sync_request | 994 | 4 | .chain(desired_runtime_parameters_get) | 995 | 4 | .chain(desired_body_download) | 996 | 4 | .chain(desired_call_proofs) | 997 | 4 | } |
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE16desired_requestsCscDgN54JpMGG_6author _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE16desired_requestsCsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 801 | 39 | pub fn desired_requests( | 802 | 39 | &'_ self, | 803 | 39 | ) -> impl Iterator<Item = (SourceId, &'_ TSrc, DesiredRequest)> + '_ { | 804 | | // If we are in the fragments download phase, return a fragments download request. | 805 | 39 | let mut desired_warp_sync_request = if self.warp_sync_fragments_download.is_none() { | 806 | 39 | if self.verify_queue.iter().fold(0, |sum, entry| { | 807 | | sum + entry.fragments.len() - entry.next_fragment_to_verify_index | 808 | 39 | }) < self.num_download_ahead_fragments | 809 | | { | 810 | | // Block hash to request. | 811 | 39 | let start_block_hash = self | 812 | 39 | .verify_queue | 813 | 39 | .back() | 814 | 39 | .and_then(|entry| entry.fragments.last()) | 815 | 39 | .map(|fragment| { | 816 | | header::hash_from_scale_encoded_header(&fragment.scale_encoded_header) | 817 | 39 | }) | 818 | 39 | .unwrap_or(self.warped_header_hash); | 819 | 39 | | 820 | 39 | // Calculate the block number at the tail of the verify queue. | 821 | 39 | // Contains `None` if the verify queue has a problem such as an indecodable header. | 822 | 39 | // In that situation, we don't start any new request and wait for the verify | 823 | 39 | // queue to empty itself. | 824 | 39 | let verify_queue_tail_block_number = self | 825 | 39 | .verify_queue | 826 | 39 | .back() | 827 | 39 | .map(|entry| { | 828 | | entry | 829 | | .fragments | 830 | | .last() | 831 | | .and_then(|fragment| { | 832 | | header::decode( | 833 | | &fragment.scale_encoded_header, | 834 | | self.block_number_bytes, | 835 | | ) | 836 | | .ok() | 837 | | }) | 838 | | .map(|header| header.number) | 839 | 39 | }) | 840 | 39 | .unwrap_or(Some(self.warped_header_number)); | 841 | 39 | let warp_sync_minimum_gap = self.warp_sync_minimum_gap; | 842 | | | 843 | 39 | if let Some(verify_queue_tail_block_number) = verify_queue_tail_block_number { | 844 | | // Combine the request with every single available source. | 845 | 39 | either::Left(self.sources.iter().filter_map(move |(src_id, src)| { | 846 | | if src.finalized_block_height | 847 | | <= verify_queue_tail_block_number.saturating_add( | 848 | | u64::try_from(warp_sync_minimum_gap).unwrap_or(u64::MAX), | 849 | | ) | 850 | | { | 851 | | return None; | 852 | | } | 853 | | | 854 | | Some(( | 855 | | SourceId(src_id), | 856 | | &src.user_data, | 857 | | DesiredRequest::WarpSyncRequest { | 858 | | block_hash: start_block_hash, | 859 | | }, | 860 | | )) | 861 | 39 | })) | 862 | | } else { | 863 | 0 | either::Right(iter::empty()) | 864 | | } | 865 | | } else { | 866 | 0 | either::Right(iter::empty()) | 867 | | } | 868 | | } else { | 869 | 0 | either::Right(iter::empty()) | 870 | | } | 871 | 39 | .peekable(); | 872 | | | 873 | | // If we are in the appropriate phase, and we are not currently downloading the runtime, | 874 | | // return a runtime download request. | 875 | 39 | let desired_runtime_parameters_get = if let ( | 876 | | WarpedBlockTy::Normal, | 877 | 0 | RuntimeDownload::NotStarted { hint_doesnt_match }, | 878 | | None, | 879 | | true, | 880 | | None, | 881 | 39 | ) = ( | 882 | 39 | &self.warped_block_ty, | 883 | 39 | &self.runtime_download, | 884 | 39 | self.warp_sync_fragments_download, | 885 | 39 | self.verify_queue.is_empty(), | 886 | 39 | desired_warp_sync_request.peek(), | 887 | 39 | ) { | 888 | 0 | let code_key_to_request = if let (false, Some(hint)) = | 889 | 0 | (*hint_doesnt_match, self.code_trie_node_hint.as_ref()) | 890 | | { | 891 | 0 | Cow::Owned( | 892 | 0 | trie::nibbles_to_bytes_truncate( | 893 | 0 | hint.closest_ancestor_excluding.iter().copied(), | 894 | 0 | ) | 895 | 0 | .collect::<Vec<_>>(), | 896 | 0 | ) | 897 | | } else { | 898 | 0 | Cow::Borrowed(&b":code"[..]) | 899 | | }; | 900 | | | 901 | | // Sources are ordered by increasing finalized block height, in order to | 902 | | // have the highest chance for the block to not be pruned. | 903 | 0 | let sources_with_block = self | 904 | 0 | .sources_by_finalized_height | 905 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) | 906 | 0 | .map(|(_, src_id)| src_id); | 907 | 0 |
| 908 | 0 | either::Left(sources_with_block.map(move |source_id| { | 909 | | ( | 910 | | *source_id, | 911 | | &self.sources[source_id.0].user_data, | 912 | | DesiredRequest::StorageGetMerkleProof { | 913 | | block_hash: self.warped_header_hash, | 914 | | state_trie_root: self.warped_header_state_root, | 915 | | keys: vec![code_key_to_request.to_vec(), b":heappages".to_vec()], | 916 | | }, | 917 | | ) | 918 | 0 | })) | 919 | | } else { | 920 | 39 | either::Right(iter::empty()) | 921 | | }; | 922 | | | 923 | | // If we are in the appropriate phase, and we are not currently downloading the body of | 924 | | // the block, return a runtime download request. | 925 | 39 | let desired_body_download = | 926 | 39 | if let (WarpedBlockTy::Normal, BodyDownload::NotStarted, None, true, None)0 = ( | 927 | 39 | &self.warped_block_ty, | 928 | 39 | &self.body_download, | 929 | 39 | self.warp_sync_fragments_download, | 930 | 39 | self.verify_queue.is_empty(), | 931 | 39 | desired_warp_sync_request.peek(), | 932 | 39 | ) { | 933 | | // Sources are ordered by increasing finalized block height, in order to | 934 | | // have the highest chance for the block to not be pruned. | 935 | 0 | let sources_with_block = self | 936 | 0 | .sources_by_finalized_height | 937 | 0 | .range((self.warped_header_number, SourceId(usize::MIN))..) | 938 | 0 | .map(|(_, src_id)| src_id); | 939 | 0 |
| 940 | 0 | either::Left(sources_with_block.map(move |source_id| { | 941 | | ( | 942 | | *source_id, | 943 | | &self.sources[source_id.0].user_data, | 944 | | DesiredRequest::BlockBodyDownload { | 945 | | block_hash: self.warped_header_hash, | 946 | | block_number: self.warped_header_number, | 947 | | extrinsics_root: self.warped_header_extrinsics_root, | 948 | | }, | 949 | | ) | 950 | 0 | })) | 951 | | } else { | 952 | 39 | either::Right(iter::empty()) | 953 | | }; | 954 | | | 955 | | // Return the list of runtime calls indicated by the chain information builder state | 956 | | // machine. | 957 | 39 | let desired_call_proofs = if matches!(self.warped_block_ty, WarpedBlockTy::Normal) | 958 | 0 | && self.warp_sync_fragments_download.is_none() | 959 | 0 | && self.verify_queue.is_empty() | 960 | 0 | && desired_warp_sync_request.peek().is_none() | 961 | | { | 962 | 0 | either::Left( | 963 | 0 | self.runtime_calls | 964 | 0 | .iter() | 965 | 0 | .filter(|(_, v)| matches!(v, CallProof::NotStarted)) | 966 | 0 | .map(|(call, _)| DesiredRequest::RuntimeCallMerkleProof { | 967 | | block_hash: self.warped_header_hash, | 968 | | function_name: call.function_name().into(), | 969 | | parameter_vectored: Cow::Owned(call.parameter_vectored_vec()), | 970 | 0 | }) | 971 | 0 | .flat_map(move |request_detail| { | 972 | | // Sources are ordered by increasing finalized block height, in order to | 973 | | // have the highest chance for the block to not be pruned. | 974 | | let sources_with_block = self | 975 | | .sources_by_finalized_height | 976 | | .range((self.warped_header_number, SourceId(usize::MIN))..) | 977 | | .map(|(_, src_id)| src_id); | 978 | | | 979 | | sources_with_block.map(move |source_id| { | 980 | | ( | 981 | | *source_id, | 982 | | &self.sources[source_id.0].user_data, | 983 | | request_detail.clone(), | 984 | | ) | 985 | | }) | 986 | 0 | }), | 987 | 0 | ) | 988 | | } else { | 989 | 39 | either::Right(iter::empty()) | 990 | | }; | 991 | | | 992 | | // Chain all these demanded requests together. | 993 | 39 | desired_warp_sync_request | 994 | 39 | .chain(desired_runtime_parameters_get) | 995 | 39 | .chain(desired_body_download) | 996 | 39 | .chain(desired_call_proofs) | 997 | 39 | } |
|
998 | | |
999 | | /// Inserts a new request in the data structure. |
1000 | | /// |
1001 | | /// > **Note**: The request doesn't necessarily have to match a request returned by |
1002 | | /// > [`WarpSync::desired_requests`]. |
1003 | | /// |
1004 | | /// # Panic |
1005 | | /// |
1006 | | /// Panics if the [`SourceId`] is out of range. |
1007 | | /// |
1008 | 0 | pub fn add_request( |
1009 | 0 | &mut self, |
1010 | 0 | source_id: SourceId, |
1011 | 0 | user_data: TRq, |
1012 | 0 | detail: RequestDetail, |
1013 | 0 | ) -> RequestId { |
1014 | 0 | assert!(self.sources.contains(source_id.0)); |
1015 | | |
1016 | 0 | let request_slot = self.in_progress_requests.vacant_entry(); |
1017 | 0 | let request_id = RequestId(request_slot.key()); |
1018 | 0 |
|
1019 | 0 | match (&detail, &mut self.runtime_download, &mut self.body_download) { |
1020 | 0 | (RequestDetail::WarpSyncRequest { block_hash }, _, _) |
1021 | 0 | if self.warp_sync_fragments_download.is_none() |
1022 | 0 | && *block_hash |
1023 | 0 | == self |
1024 | 0 | .verify_queue |
1025 | 0 | .back() |
1026 | 0 | .and_then(|entry| entry.fragments.last()) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_request0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_request0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_request0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_request0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_request0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_request0CsibGXYHQB8Ea_25json_rpc_general_requests |
1027 | 0 | .map(|fragment| { |
1028 | 0 | header::hash_from_scale_encoded_header( |
1029 | 0 | &fragment.scale_encoded_header, |
1030 | 0 | ) |
1031 | 0 | }) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1032 | 0 | .unwrap_or(self.warped_header_hash) => |
1033 | 0 | { |
1034 | 0 | self.warp_sync_fragments_download = Some(request_id); |
1035 | 0 | } |
1036 | | ( |
1037 | | RequestDetail::BlockBodyDownload { |
1038 | 0 | block_hash, |
1039 | 0 | block_number, |
1040 | 0 | }, |
1041 | 0 | _, |
1042 | 0 | BodyDownload::NotStarted, |
1043 | 0 | ) => { |
1044 | 0 | if self.sources[source_id.0].finalized_block_height >= self.warped_header_number |
1045 | 0 | && *block_number == self.warped_header_number |
1046 | 0 | && *block_hash == self.warped_header_hash |
1047 | 0 | { |
1048 | 0 | self.body_download = BodyDownload::Downloading { request_id }; |
1049 | 0 | } |
1050 | | } |
1051 | | ( |
1052 | 0 | RequestDetail::StorageGetMerkleProof { block_hash, keys }, |
1053 | 0 | RuntimeDownload::NotStarted { hint_doesnt_match }, |
1054 | | _, |
1055 | | ) => { |
1056 | 0 | let code_key_to_request = if let (false, Some(hint)) = |
1057 | 0 | (*hint_doesnt_match, self.code_trie_node_hint.as_ref()) |
1058 | | { |
1059 | 0 | Cow::Owned( |
1060 | 0 | trie::nibbles_to_bytes_truncate( |
1061 | 0 | hint.closest_ancestor_excluding.iter().copied(), |
1062 | 0 | ) |
1063 | 0 | .collect::<Vec<_>>(), |
1064 | 0 | ) |
1065 | | } else { |
1066 | 0 | Cow::Borrowed(&b":code"[..]) |
1067 | | }; |
1068 | | |
1069 | 0 | if self.sources[source_id.0].finalized_block_height >= self.warped_header_number |
1070 | 0 | && *block_hash == self.warped_header_hash |
1071 | 0 | && keys.iter().any(|k| *k == *code_key_to_request) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests0_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests0_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests0_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests0_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests0_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1072 | 0 | && keys.iter().any(|k| k == b":heappages") Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests1_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11add_requests1_0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests1_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests1_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11add_requests1_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1073 | 0 | { |
1074 | 0 | self.runtime_download = RuntimeDownload::Downloading { |
1075 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1076 | 0 | request_id, |
1077 | 0 | }; |
1078 | 0 | } |
1079 | | } |
1080 | | ( |
1081 | | RequestDetail::RuntimeCallMerkleProof { |
1082 | 0 | block_hash, |
1083 | 0 | function_name, |
1084 | 0 | parameter_vectored, |
1085 | | }, |
1086 | | _, |
1087 | | _, |
1088 | | ) => { |
1089 | 0 | for (info, status) in &mut self.runtime_calls { |
1090 | 0 | if matches!(status, CallProof::NotStarted) |
1091 | 0 | && self.sources[source_id.0].finalized_block_height |
1092 | 0 | >= self.warped_header_number |
1093 | 0 | && *block_hash == self.warped_header_hash |
1094 | 0 | && function_name == info.function_name() |
1095 | 0 | && parameters_equal(parameter_vectored, info.parameter_vectored()) |
1096 | | { |
1097 | 0 | *status = CallProof::Downloading(request_id); |
1098 | 0 | break; |
1099 | 0 | } |
1100 | | } |
1101 | | } |
1102 | 0 | _ => {} |
1103 | | } |
1104 | | |
1105 | 0 | request_slot.insert((source_id, user_data, detail)); |
1106 | 0 | let _was_inserted = self |
1107 | 0 | .in_progress_requests_by_source |
1108 | 0 | .insert((source_id, request_id)); |
1109 | 0 | debug_assert!(_was_inserted); |
1110 | 0 | request_id |
1111 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE11add_requestB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11add_requestCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE11add_requestB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11add_requestCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11add_requestCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11add_requestCsibGXYHQB8Ea_25json_rpc_general_requests |
1112 | | |
1113 | | /// Removes the given request from the state machine. Returns the user data that was associated |
1114 | | /// to it. |
1115 | | /// |
1116 | | /// > **Note**: The state machine might want to re-start the same request again. It is out of |
1117 | | /// > the scope of this module to keep track of requests that don't succeed. |
1118 | | /// |
1119 | | /// # Panic |
1120 | | /// |
1121 | | /// Panics if the [`RequestId`] is invalid. |
1122 | | /// |
1123 | 0 | pub fn remove_request(&mut self, id: RequestId) -> TRq { |
1124 | 0 | if self.warp_sync_fragments_download == Some(id) { |
1125 | 0 | self.warp_sync_fragments_download = None; |
1126 | 0 | } |
1127 | | |
1128 | 0 | for call in self.runtime_calls.values_mut() { |
1129 | 0 | if matches!(call, CallProof::Downloading(rq_id) if *rq_id == id) { |
1130 | 0 | *call = CallProof::NotStarted; |
1131 | 0 | } |
1132 | | } |
1133 | | |
1134 | | if let RuntimeDownload::Downloading { |
1135 | 0 | request_id, |
1136 | 0 | hint_doesnt_match, |
1137 | 0 | } = &mut self.runtime_download |
1138 | | { |
1139 | 0 | if *request_id == id { |
1140 | 0 | self.runtime_download = RuntimeDownload::NotStarted { |
1141 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1142 | 0 | } |
1143 | 0 | } |
1144 | 0 | } |
1145 | | |
1146 | 0 | if let BodyDownload::Downloading { request_id } = &mut self.body_download { |
1147 | 0 | if *request_id == id { |
1148 | 0 | self.body_download = BodyDownload::NotStarted; |
1149 | 0 | } |
1150 | 0 | } |
1151 | | |
1152 | 0 | let (source_id, user_data, _) = self.in_progress_requests.remove(id.0); |
1153 | 0 | let _was_removed = self.in_progress_requests_by_source.remove(&(source_id, id)); |
1154 | 0 | debug_assert!(_was_removed); |
1155 | 0 | user_data |
1156 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE14remove_requestB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE14remove_requestCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE14remove_requestB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE14remove_requestCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE14remove_requestCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE14remove_requestCsibGXYHQB8Ea_25json_rpc_general_requests |
1157 | | |
1158 | | /// Returns the [`SourceId`] that is expected to fulfill the given request. |
1159 | | /// |
1160 | | /// # Panic |
1161 | | /// |
1162 | | /// Panics if the [`RequestId`] is invalid. |
1163 | | /// |
1164 | 0 | pub fn request_source_id(&self, request_id: RequestId) -> SourceId { |
1165 | 0 | self.in_progress_requests[request_id.0].0 |
1166 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE17request_source_idB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE17request_source_idB8_ |
1167 | | |
1168 | | /// Injects a body download and removes the given request from the state machine. |
1169 | | /// Returns the user data that was associated to it. |
1170 | | /// |
1171 | | /// # Panic |
1172 | | /// |
1173 | | /// Panics if the [`RequestId`] is invalid. |
1174 | | /// Panics if the [`RequestId`] doesn't correspond to a body download request. |
1175 | | /// |
1176 | 0 | pub fn body_download_response(&mut self, id: RequestId, body: Vec<Vec<u8>>) -> TRq { |
1177 | | // Remove the request from the list, obtaining its user data. |
1178 | | // If the request corresponds to the runtime parameters we're looking for, the function |
1179 | | // continues below, otherwise we return early. |
1180 | 0 | let (source_id, user_data) = |
1181 | 0 | match (self.in_progress_requests.remove(id.0), &self.body_download) { |
1182 | 0 | ((source_id, user_data, _), BodyDownload::Downloading { request_id }) |
1183 | 0 | if *request_id == id => |
1184 | 0 | { |
1185 | 0 | (source_id, user_data) |
1186 | | } |
1187 | 0 | ((source_id, user_data, RequestDetail::BlockBodyDownload { .. }), _) => { |
1188 | 0 | let _was_removed = self.in_progress_requests_by_source.remove(&(source_id, id)); |
1189 | 0 | debug_assert!(_was_removed); |
1190 | 0 | return user_data; |
1191 | | } |
1192 | | ( |
1193 | | ( |
1194 | | _, |
1195 | | _, |
1196 | | RequestDetail::RuntimeCallMerkleProof { .. } |
1197 | | | RequestDetail::WarpSyncRequest { .. } |
1198 | | | RequestDetail::StorageGetMerkleProof { .. }, |
1199 | | ), |
1200 | | _, |
1201 | 0 | ) => panic!(), |
1202 | | }; |
1203 | | |
1204 | 0 | self.body_download = BodyDownload::Downloaded { |
1205 | 0 | downloaded_source: Some(source_id), |
1206 | 0 | body, |
1207 | 0 | }; |
1208 | 0 |
|
1209 | 0 | let _was_removed = self.in_progress_requests_by_source.remove(&(source_id, id)); |
1210 | 0 | debug_assert!(_was_removed); |
1211 | | |
1212 | 0 | user_data |
1213 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE22body_download_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE22body_download_responseCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE22body_download_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE22body_download_responseCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE22body_download_responseCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE22body_download_responseCsibGXYHQB8Ea_25json_rpc_general_requests |
1214 | | |
1215 | | /// Injects a Merkle proof and removes the given request from the state machine. |
1216 | | /// Returns the user data that was associated to it. |
1217 | | /// |
1218 | | /// # Panic |
1219 | | /// |
1220 | | /// Panics if the [`RequestId`] is invalid. |
1221 | | /// Panics if the [`RequestId`] doesn't correspond to a storage get request. |
1222 | | /// |
1223 | 0 | pub fn storage_get_response(&mut self, id: RequestId, merkle_proof: Vec<u8>) -> TRq { |
1224 | | // Remove the request from the list, obtaining its user data. |
1225 | | // If the request corresponds to the runtime parameters we're looking for, the function |
1226 | | // continues below, otherwise we return early. |
1227 | 0 | let (source_id, hint_doesnt_match, user_data) = match ( |
1228 | 0 | self.in_progress_requests.remove(id.0), |
1229 | 0 | &self.runtime_download, |
1230 | | ) { |
1231 | | ( |
1232 | 0 | (source_id, user_data, _), |
1233 | | RuntimeDownload::Downloading { |
1234 | 0 | request_id, |
1235 | 0 | hint_doesnt_match, |
1236 | 0 | }, |
1237 | 0 | ) if *request_id == id => (source_id, *hint_doesnt_match, user_data), |
1238 | 0 | ((source_id, user_data, RequestDetail::StorageGetMerkleProof { .. }), _) => { |
1239 | 0 | let _was_removed = self.in_progress_requests_by_source.remove(&(source_id, id)); |
1240 | 0 | debug_assert!(_was_removed); |
1241 | 0 | return user_data; |
1242 | | } |
1243 | | ( |
1244 | | ( |
1245 | | _, |
1246 | | _, |
1247 | | RequestDetail::RuntimeCallMerkleProof { .. } |
1248 | | | RequestDetail::WarpSyncRequest { .. } |
1249 | | | RequestDetail::BlockBodyDownload { .. }, |
1250 | | ), |
1251 | | _, |
1252 | 0 | ) => panic!(), |
1253 | | }; |
1254 | | |
1255 | 0 | self.runtime_download = RuntimeDownload::NotVerified { |
1256 | 0 | downloaded_source: Some(source_id), |
1257 | 0 | hint_doesnt_match, |
1258 | 0 | trie_proof: merkle_proof, |
1259 | 0 | }; |
1260 | 0 |
|
1261 | 0 | let _was_removed = self.in_progress_requests_by_source.remove(&(source_id, id)); |
1262 | 0 | debug_assert!(_was_removed); |
1263 | | |
1264 | 0 | user_data |
1265 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE20storage_get_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20storage_get_responseCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE20storage_get_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20storage_get_responseCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20storage_get_responseCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE20storage_get_responseCsibGXYHQB8Ea_25json_rpc_general_requests |
1266 | | |
1267 | | /// Injects a response and removes the given request from the state machine. Returns |
1268 | | /// the user data that was associated to it. |
1269 | | /// |
1270 | | /// # Panic |
1271 | | /// |
1272 | | /// Panics if the [`RequestId`] is invalid. |
1273 | | /// Panics if the [`RequestId`] doesn't correspond to a runtime Merkle call proof request. |
1274 | | /// |
1275 | 0 | pub fn runtime_call_merkle_proof_response( |
1276 | 0 | &mut self, |
1277 | 0 | request_id: RequestId, |
1278 | 0 | response: Vec<u8>, |
1279 | 0 | ) -> TRq { |
1280 | 0 | let (source_id, user_data, RequestDetail::RuntimeCallMerkleProof { .. }) = |
1281 | 0 | self.in_progress_requests.remove(request_id.0) |
1282 | | else { |
1283 | | // Wrong request type. |
1284 | 0 | panic!() |
1285 | | }; |
1286 | | |
1287 | 0 | for call in self.runtime_calls.values_mut() { |
1288 | 0 | if matches!(call, CallProof::Downloading(rq_id) if *rq_id == request_id) { |
1289 | 0 | *call = CallProof::Downloaded { |
1290 | 0 | downloaded_source: Some(source_id), |
1291 | 0 | proof: response, |
1292 | 0 | }; |
1293 | 0 | break; |
1294 | 0 | } |
1295 | | } |
1296 | | |
1297 | 0 | let _was_removed = self |
1298 | 0 | .in_progress_requests_by_source |
1299 | 0 | .remove(&(source_id, request_id)); |
1300 | 0 | debug_assert!(_was_removed); |
1301 | | |
1302 | 0 | user_data |
1303 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE34runtime_call_merkle_proof_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE34runtime_call_merkle_proof_responseCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE34runtime_call_merkle_proof_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE34runtime_call_merkle_proof_responseCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE34runtime_call_merkle_proof_responseCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE34runtime_call_merkle_proof_responseCsibGXYHQB8Ea_25json_rpc_general_requests |
1304 | | |
1305 | | /// Injects a response and removes the given request from the state machine. Returns |
1306 | | /// the user data that was associated to it. |
1307 | | /// |
1308 | | /// If the header of the last fragment of the response is decodable, this function updates |
1309 | | /// the finalized block of the source. |
1310 | | /// |
1311 | | /// # Panic |
1312 | | /// |
1313 | | /// Panics if the [`RequestId`] is invalid. |
1314 | | /// Panics if the [`RequestId`] doesn't correspond to a warp sync request. |
1315 | | /// |
1316 | | // TODO: more zero cost API w.r.t. the fragments |
1317 | 0 | pub fn warp_sync_request_response( |
1318 | 0 | &mut self, |
1319 | 0 | request_id: RequestId, |
1320 | 0 | fragments: Vec<WarpSyncFragment>, |
1321 | 0 | final_set_of_fragments: bool, |
1322 | 0 | ) -> TRq { |
1323 | 0 | let (rq_source_id, user_data) = match self.in_progress_requests.remove(request_id.0) { |
1324 | 0 | (rq_source_id, user_data, RequestDetail::WarpSyncRequest { .. }) => { |
1325 | 0 | (rq_source_id, user_data) |
1326 | | } |
1327 | 0 | (_, _, _) => panic!(), |
1328 | | }; |
1329 | | |
1330 | 0 | debug_assert!(self.sources.contains(rq_source_id.0)); |
1331 | | |
1332 | | // Since we send requests only to sources with an appropriate finalized block, we make |
1333 | | // sure that the finalized block of the source that sent the response matches the |
1334 | | // fragments that it sent. |
1335 | | // If we didn't do that, it would be possible for example to warp sync to block 200 while |
1336 | | // believing that the source is only at block 199, and thus the warp syncing would stall. |
1337 | 0 | if let Some(last_header) = fragments |
1338 | 0 | .last() |
1339 | 0 | .and_then(|h| header::decode(&h.scale_encoded_header, self.block_number_bytes).ok()) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE26warp_sync_request_response0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE26warp_sync_request_response0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE26warp_sync_request_response0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE26warp_sync_request_response0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE26warp_sync_request_response0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE26warp_sync_request_response0CsibGXYHQB8Ea_25json_rpc_general_requests |
1340 | | { |
1341 | 0 | let src_finalized_height = &mut self.sources[rq_source_id.0].finalized_block_height; |
1342 | | |
1343 | 0 | let new_height = if final_set_of_fragments { |
1344 | | // If the source indicated that this is the last fragment, then we know that |
1345 | | // it's also equal to their finalized block. |
1346 | 0 | last_header.number |
1347 | | } else { |
1348 | | // If this is not the last fragment, we know that the finalized block of the |
1349 | | // source is *at least* the one provided. |
1350 | | // TODO: could maybe do + gap or something? |
1351 | 0 | cmp::max(*src_finalized_height, last_header.number.saturating_add(1)) |
1352 | | }; |
1353 | | |
1354 | 0 | if *src_finalized_height != new_height { |
1355 | 0 | let _was_in = self |
1356 | 0 | .sources_by_finalized_height |
1357 | 0 | .remove(&(*src_finalized_height, rq_source_id)); |
1358 | 0 | debug_assert!(_was_in); |
1359 | | |
1360 | 0 | *src_finalized_height = new_height; |
1361 | 0 |
|
1362 | 0 | let _inserted = self |
1363 | 0 | .sources_by_finalized_height |
1364 | 0 | .insert((*src_finalized_height, rq_source_id)); |
1365 | 0 | debug_assert!(_inserted); |
1366 | 0 | } |
1367 | 0 | } |
1368 | | |
1369 | 0 | if self.warp_sync_fragments_download == Some(request_id) { |
1370 | 0 | self.warp_sync_fragments_download = None; |
1371 | 0 |
|
1372 | 0 | self.verify_queue.push_back(PendingVerify { |
1373 | 0 | final_set_of_fragments, |
1374 | 0 | downloaded_source: Some(rq_source_id), |
1375 | 0 | fragments, |
1376 | 0 | next_fragment_to_verify_index: 0, |
1377 | 0 | }); |
1378 | 0 | } |
1379 | | |
1380 | 0 | let _was_removed = self |
1381 | 0 | .in_progress_requests_by_source |
1382 | 0 | .remove(&(rq_source_id, request_id)); |
1383 | 0 | debug_assert!(_was_removed); |
1384 | | |
1385 | 0 | user_data |
1386 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE26warp_sync_request_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE26warp_sync_request_responseCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE26warp_sync_request_responseB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE26warp_sync_request_responseCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE26warp_sync_request_responseCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE26warp_sync_request_responseCsibGXYHQB8Ea_25json_rpc_general_requests |
1387 | | |
1388 | | /// Start processing one CPU operation. |
1389 | | /// |
1390 | | /// This function takes ownership of `self` and yields it back after the operation is finished. |
1391 | | // TODO: take a `&mut self` instead of `self` ; requires many changes in all.rs |
1392 | 21 | pub fn process_one(self) -> ProcessOne<TSrc, TRq> { |
1393 | | // If we've downloaded everything that was needed, switch to "build chain information" |
1394 | | // mode. |
1395 | 21 | if matches!(self.runtime_download, RuntimeDownload::Verified { .. }) |
1396 | 0 | && matches!( |
1397 | 0 | self.body_download, |
1398 | | BodyDownload::NotNeeded | BodyDownload::Downloaded { .. } |
1399 | | ) |
1400 | 0 | && self |
1401 | 0 | .runtime_calls |
1402 | 0 | .values() |
1403 | 0 | .all(|c| matches!(c, CallProof::Downloaded { .. })) Unexecuted instantiation: _RNCNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11process_one0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11process_one0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncppE11process_one0Ba_ Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11process_one0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11process_one0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB6_8WarpSyncNtNtB8_3all19WarpSyncSourceExtraNtB12_20WarpSyncRequestExtraE11process_one0CsibGXYHQB8Ea_25json_rpc_general_requests |
1404 | | { |
1405 | 0 | return ProcessOne::BuildChainInformation(BuildChainInformation { inner: self }); |
1406 | 21 | } |
1407 | 21 | |
1408 | 21 | if let RuntimeDownload::NotVerified { .. } = &self.runtime_download { |
1409 | 0 | return ProcessOne::BuildRuntime(BuildRuntime { inner: self }); |
1410 | 21 | } |
1411 | 21 | |
1412 | 21 | if !self.verify_queue.is_empty() { |
1413 | 0 | return ProcessOne::VerifyWarpSyncFragment(VerifyWarpSyncFragment { inner: self }); |
1414 | 21 | } |
1415 | 21 | |
1416 | 21 | ProcessOne::Idle(self) |
1417 | 21 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB4_8WarpSyncppE11process_oneB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11process_oneCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncppE11process_oneB8_ _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11process_oneCsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 1392 | 2 | pub fn process_one(self) -> ProcessOne<TSrc, TRq> { | 1393 | | // If we've downloaded everything that was needed, switch to "build chain information" | 1394 | | // mode. | 1395 | 2 | if matches!(self.runtime_download, RuntimeDownload::Verified { .. }) | 1396 | 0 | && matches!( | 1397 | 0 | self.body_download, | 1398 | | BodyDownload::NotNeeded | BodyDownload::Downloaded { .. } | 1399 | | ) | 1400 | 0 | && self | 1401 | 0 | .runtime_calls | 1402 | 0 | .values() | 1403 | 0 | .all(|c| matches!(c, CallProof::Downloaded { .. })) | 1404 | | { | 1405 | 0 | return ProcessOne::BuildChainInformation(BuildChainInformation { inner: self }); | 1406 | 2 | } | 1407 | 2 | | 1408 | 2 | if let RuntimeDownload::NotVerified { .. } = &self.runtime_download { | 1409 | 0 | return ProcessOne::BuildRuntime(BuildRuntime { inner: self }); | 1410 | 2 | } | 1411 | 2 | | 1412 | 2 | if !self.verify_queue.is_empty() { | 1413 | 0 | return ProcessOne::VerifyWarpSyncFragment(VerifyWarpSyncFragment { inner: self }); | 1414 | 2 | } | 1415 | 2 | | 1416 | 2 | ProcessOne::Idle(self) | 1417 | 2 | } |
Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11process_oneCscDgN54JpMGG_6author _RNvMs_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB4_8WarpSyncNtNtB6_3all19WarpSyncSourceExtraNtB10_20WarpSyncRequestExtraE11process_oneCsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 1392 | 19 | pub fn process_one(self) -> ProcessOne<TSrc, TRq> { | 1393 | | // If we've downloaded everything that was needed, switch to "build chain information" | 1394 | | // mode. | 1395 | 19 | if matches!(self.runtime_download, RuntimeDownload::Verified { .. }) | 1396 | 0 | && matches!( | 1397 | 0 | self.body_download, | 1398 | | BodyDownload::NotNeeded | BodyDownload::Downloaded { .. } | 1399 | | ) | 1400 | 0 | && self | 1401 | 0 | .runtime_calls | 1402 | 0 | .values() | 1403 | 0 | .all(|c| matches!(c, CallProof::Downloaded { .. })) | 1404 | | { | 1405 | 0 | return ProcessOne::BuildChainInformation(BuildChainInformation { inner: self }); | 1406 | 19 | } | 1407 | 19 | | 1408 | 19 | if let RuntimeDownload::NotVerified { .. } = &self.runtime_download { | 1409 | 0 | return ProcessOne::BuildRuntime(BuildRuntime { inner: self }); | 1410 | 19 | } | 1411 | 19 | | 1412 | 19 | if !self.verify_queue.is_empty() { | 1413 | 0 | return ProcessOne::VerifyWarpSyncFragment(VerifyWarpSyncFragment { inner: self }); | 1414 | 19 | } | 1415 | 19 | | 1416 | 19 | ProcessOne::Idle(self) | 1417 | 19 | } |
|
1418 | | } |
1419 | | |
1420 | | impl<TSrc, TRq> ops::Index<SourceId> for WarpSync<TSrc, TRq> { |
1421 | | type Output = TSrc; |
1422 | | |
1423 | | #[track_caller] |
1424 | 0 | fn index(&self, source_id: SourceId) -> &TSrc { |
1425 | 0 | debug_assert!(self.sources.contains(source_id.0)); |
1426 | 0 | &self.sources[source_id.0].user_data |
1427 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncs0_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexB9_ Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_8WarpSyncNtNtB7_3all19WarpSyncSourceExtraNtB11_20WarpSyncRequestExtraEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot4sync9warp_syncs0_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexB9_ Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_8WarpSyncNtNtB7_3all19WarpSyncSourceExtraNtB11_20WarpSyncRequestExtraEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_8WarpSyncNtNtB7_3all19WarpSyncSourceExtraNtB11_20WarpSyncRequestExtraEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexCscDgN54JpMGG_6author Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_8WarpSyncNtNtB7_3all19WarpSyncSourceExtraNtB11_20WarpSyncRequestExtraEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_8SourceIdE5indexCsibGXYHQB8Ea_25json_rpc_general_requests |
1428 | | } |
1429 | | |
1430 | | impl<TSrc, TRq> ops::IndexMut<SourceId> for WarpSync<TSrc, TRq> { |
1431 | | #[track_caller] |
1432 | 0 | fn index_mut(&mut self, source_id: SourceId) -> &mut TSrc { |
1433 | 0 | debug_assert!(self.sources.contains(source_id.0)); |
1434 | 0 | &mut self.sources[source_id.0].user_data |
1435 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncs1_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtB5_8SourceIdE9index_mutB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot4sync9warp_syncs1_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtB5_8SourceIdE9index_mutB9_ |
1436 | | } |
1437 | | |
1438 | | impl<TSrc, TRq> ops::Index<RequestId> for WarpSync<TSrc, TRq> { |
1439 | | type Output = TRq; |
1440 | | |
1441 | | #[track_caller] |
1442 | 0 | fn index(&self, request_id: RequestId) -> &TRq { |
1443 | 0 | debug_assert!(self.in_progress_requests.contains(request_id.0)); |
1444 | 0 | &self.in_progress_requests[request_id.0].1 |
1445 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncs2_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_9RequestIdE5indexB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot4sync9warp_syncs2_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtB5_9RequestIdE5indexB9_ |
1446 | | } |
1447 | | |
1448 | | impl<TSrc, TRq> ops::IndexMut<RequestId> for WarpSync<TSrc, TRq> { |
1449 | | #[track_caller] |
1450 | 0 | fn index_mut(&mut self, request_id: RequestId) -> &mut TRq { |
1451 | 0 | debug_assert!(self.in_progress_requests.contains(request_id.0)); |
1452 | 0 | &mut self.in_progress_requests[request_id.0].1 |
1453 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncs3_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtB5_9RequestIdE9index_mutB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot4sync9warp_syncs3_0ppEINtB5_8WarpSyncppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtB5_9RequestIdE9index_mutB9_ |
1454 | | } |
1455 | | |
1456 | | /// Information about a request that the warp sync state machine would like to start. |
1457 | | /// |
1458 | | /// See [`WarpSync::desired_requests`]. |
1459 | | #[derive(Debug, Clone)] |
1460 | | pub enum DesiredRequest { |
1461 | | /// A warp sync request should be started. |
1462 | | WarpSyncRequest { |
1463 | | /// Starting point of the warp syncing. The first fragment of the response should be the |
1464 | | /// of the epoch that the starting point is in. |
1465 | | block_hash: [u8; 32], |
1466 | | }, |
1467 | | /// A block body download should be started. |
1468 | | BlockBodyDownload { |
1469 | | /// Hash of the block whose body to download. |
1470 | | block_hash: [u8; 32], |
1471 | | /// Height of the block whose body to download. |
1472 | | block_number: u64, |
1473 | | /// Extrinsics trie root hash found in the header of the block. |
1474 | | extrinsics_root: [u8; 32], |
1475 | | }, |
1476 | | /// A storage request of the runtime code and heap pages should be started. |
1477 | | StorageGetMerkleProof { |
1478 | | /// Hash of the block to request the parameters against. |
1479 | | block_hash: [u8; 32], |
1480 | | /// State trie root hash found in the header of the block. |
1481 | | state_trie_root: [u8; 32], |
1482 | | /// Keys whose values are requested. |
1483 | | // TODO: consider Cow<'static, [u8]> instead |
1484 | | keys: Vec<Vec<u8>>, |
1485 | | }, |
1486 | | /// A call proof should be started. |
1487 | | RuntimeCallMerkleProof { |
1488 | | /// Hash of the header of the block the call should be made against. |
1489 | | block_hash: [u8; 32], |
1490 | | /// Name of the function of the call proof. |
1491 | | function_name: Cow<'static, str>, |
1492 | | /// Parameters of the call. |
1493 | | parameter_vectored: Cow<'static, [u8]>, |
1494 | | }, |
1495 | | } |
1496 | | |
1497 | | /// Information about a request to add to the state machine. |
1498 | | /// |
1499 | | /// See [`WarpSync::add_request`]. |
1500 | | #[derive(Debug, Clone)] |
1501 | | pub enum RequestDetail { |
1502 | | /// See [`DesiredRequest::WarpSyncRequest`]. |
1503 | | WarpSyncRequest { |
1504 | | /// See [`DesiredRequest::WarpSyncRequest::block_hash`]. |
1505 | | block_hash: [u8; 32], |
1506 | | }, |
1507 | | /// See [`DesiredRequest::BlockBodyDownload`]. |
1508 | | BlockBodyDownload { |
1509 | | /// See [`DesiredRequest::BlockBodyDownload::block_hash`]. |
1510 | | block_hash: [u8; 32], |
1511 | | /// See [`DesiredRequest::BlockBodyDownload::block_number`]. |
1512 | | // TODO: remove this field as it's inappropriate, but this causes issues in all.rs |
1513 | | block_number: u64, |
1514 | | }, |
1515 | | /// See [`DesiredRequest::StorageGetMerkleProof`]. |
1516 | | StorageGetMerkleProof { |
1517 | | /// See [`DesiredRequest::StorageGetMerkleProof::block_hash`]. |
1518 | | block_hash: [u8; 32], |
1519 | | /// See [`DesiredRequest::StorageGetMerkleProof::keys`]. |
1520 | | keys: Vec<Vec<u8>>, |
1521 | | }, |
1522 | | /// See [`DesiredRequest::RuntimeCallMerkleProof`]. |
1523 | | RuntimeCallMerkleProof { |
1524 | | /// See [`DesiredRequest::RuntimeCallMerkleProof::block_hash`]. |
1525 | | block_hash: [u8; 32], |
1526 | | /// See [`DesiredRequest::RuntimeCallMerkleProof::function_name`]. |
1527 | | function_name: Cow<'static, str>, |
1528 | | /// See [`DesiredRequest::RuntimeCallMerkleProof::parameter_vectored`]. |
1529 | | parameter_vectored: Cow<'static, [u8]>, |
1530 | | }, |
1531 | | } |
1532 | | |
1533 | | /// Identifier for a request in the warp sync state machine. |
1534 | | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] |
1535 | | pub struct RequestId(usize); |
1536 | | |
1537 | | /// Return value of [`WarpSync::process_one`]. |
1538 | | pub enum ProcessOne<TSrc, TRq> { |
1539 | | /// Nothing to verify at the moment. The state machine is yielded back. |
1540 | | Idle(WarpSync<TSrc, TRq>), |
1541 | | /// Ready to verify a warp sync fragment. |
1542 | | /// |
1543 | | /// > **Note**: In case where a source has sent an empty list of fragment, which is invalid, |
1544 | | /// > this variant will "verify" the list and produce an error. |
1545 | | VerifyWarpSyncFragment(VerifyWarpSyncFragment<TSrc, TRq>), |
1546 | | /// Ready to build the runtime of the chain.. |
1547 | | BuildRuntime(BuildRuntime<TSrc, TRq>), |
1548 | | /// Ready to verify the parameters of the chain against the finalized block. |
1549 | | BuildChainInformation(BuildChainInformation<TSrc, TRq>), |
1550 | | } |
1551 | | |
1552 | | /// Ready to verify a warp sync fragment. |
1553 | | /// |
1554 | | /// > **Note**: In case where a source has sent an empty list of fragment, which is invalid, |
1555 | | /// > this variant will "verify" the list and produce an error. |
1556 | | pub struct VerifyWarpSyncFragment<TSrc, TRq> { |
1557 | | inner: WarpSync<TSrc, TRq>, |
1558 | | } |
1559 | | |
1560 | | impl<TSrc, TRq> VerifyWarpSyncFragment<TSrc, TRq> { |
1561 | | /// Returns the source that has sent the fragments that we are about to verify, and its user |
1562 | | /// data. |
1563 | | /// |
1564 | | /// Returns `None` if the source has been removed since the fragments have been downloaded. |
1565 | 0 | pub fn proof_sender(&self) -> Option<(SourceId, &TSrc)> { |
1566 | 0 | let entry_to_verify = self.inner.verify_queue.front().unwrap(); |
1567 | 0 | let source_id = entry_to_verify.downloaded_source?; |
1568 | 0 | Some((source_id, &self.inner.sources[source_id.0].user_data)) |
1569 | 0 | } Unexecuted instantiation: _RNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentppE12proof_senderB9_ Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE12proof_senderCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentppE12proof_senderB9_ Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE12proof_senderCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE12proof_senderCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE12proof_senderCsibGXYHQB8Ea_25json_rpc_general_requests |
1570 | | |
1571 | | /// Verify one warp sync fragment. |
1572 | | /// |
1573 | | /// Must be passed a randomly-generated value that is used by the verification process. Note |
1574 | | /// that the verification is still deterministic. |
1575 | | /// |
1576 | | /// On success, returns the block hash and height that have been verified as being part of |
1577 | | /// the chain. |
1578 | | /// On error, returns why the verification has failed. The warp syncing process still |
1579 | | /// continues. |
1580 | 0 | pub fn verify( |
1581 | 0 | mut self, |
1582 | 0 | randomness_seed: [u8; 32], |
1583 | 0 | ) -> ( |
1584 | 0 | WarpSync<TSrc, TRq>, |
1585 | 0 | Result<([u8; 32], u64), VerifyFragmentError>, |
1586 | 0 | ) { |
1587 | 0 | // A `VerifyWarpSyncFragment` is only ever created if `verify_queue` is non-empty. |
1588 | 0 | debug_assert!(!self.inner.verify_queue.is_empty()); |
1589 | 0 | let fragments_to_verify = self |
1590 | 0 | .inner |
1591 | 0 | .verify_queue |
1592 | 0 | .front_mut() |
1593 | 0 | .unwrap_or_else(|| unreachable!()); Unexecuted instantiation: _RNCNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verify0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verify0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verify0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verify0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verify0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verify0CsibGXYHQB8Ea_25json_rpc_general_requests |
1594 | 0 |
|
1595 | 0 | // The source has sent an empty list of fragments. This is invalid. |
1596 | 0 | if fragments_to_verify.fragments.is_empty() { |
1597 | 0 | self.inner.verify_queue.pop_front().unwrap(); |
1598 | 0 | return (self.inner, Err(VerifyFragmentError::EmptyProof)); |
1599 | 0 | } |
1600 | 0 |
|
1601 | 0 | // Given that the list of fragments is non-empty, we are assuming that there are still |
1602 | 0 | // fragments to verify, otherwise this entry should have been removed in a previous |
1603 | 0 | // iteration. |
1604 | 0 | let fragment_to_verify = fragments_to_verify |
1605 | 0 | .fragments |
1606 | 0 | .get(fragments_to_verify.next_fragment_to_verify_index) |
1607 | 0 | .unwrap_or_else(|| unreachable!()); Unexecuted instantiation: _RNCNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1608 | | |
1609 | | // It has been checked at the warp sync initialization that the finality algorithm is |
1610 | | // indeed Grandpa. |
1611 | | let chain_information::ChainInformationFinality::Grandpa { |
1612 | 0 | after_finalized_block_authorities_set_id, |
1613 | 0 | finalized_triggered_authorities, |
1614 | | .. // TODO: support finalized_scheduled_change? difficult to implement |
1615 | 0 | } = &mut self.inner.warped_finality |
1616 | | else { |
1617 | 0 | unreachable!() |
1618 | | }; |
1619 | | |
1620 | | // Decode the header and justification of the fragment. |
1621 | 0 | let fragment_header_hash = |
1622 | 0 | header::hash_from_scale_encoded_header(&fragment_to_verify.scale_encoded_header); |
1623 | 0 | let fragment_decoded_header = match header::decode( |
1624 | 0 | &fragment_to_verify.scale_encoded_header, |
1625 | 0 | self.inner.block_number_bytes, |
1626 | 0 | ) { |
1627 | 0 | Ok(j) => j, |
1628 | 0 | Err(err) => { |
1629 | 0 | self.inner.verify_queue.clear(); |
1630 | 0 | self.inner.warp_sync_fragments_download = None; |
1631 | 0 | return (self.inner, Err(VerifyFragmentError::InvalidHeader(err))); |
1632 | | } |
1633 | | }; |
1634 | 0 | let fragment_decoded_justification = match decode::decode_grandpa_justification( |
1635 | 0 | &fragment_to_verify.scale_encoded_justification, |
1636 | 0 | self.inner.block_number_bytes, |
1637 | 0 | ) { |
1638 | 0 | Ok(j) => j, |
1639 | 0 | Err(err) => { |
1640 | 0 | self.inner.verify_queue.clear(); |
1641 | 0 | self.inner.warp_sync_fragments_download = None; |
1642 | 0 | return ( |
1643 | 0 | self.inner, |
1644 | 0 | Err(VerifyFragmentError::InvalidJustification(err)), |
1645 | 0 | ); |
1646 | | } |
1647 | | }; |
1648 | | |
1649 | | // Make sure that the header would actually advance the warp sync process forward. |
1650 | 0 | if fragment_decoded_header.number <= self.inner.warped_header_number { |
1651 | 0 | self.inner.verify_queue.clear(); |
1652 | 0 | self.inner.warp_sync_fragments_download = None; |
1653 | 0 | return ( |
1654 | 0 | self.inner, |
1655 | 0 | Err(VerifyFragmentError::BlockNumberNotIncrementing), |
1656 | 0 | ); |
1657 | 0 | } |
1658 | 0 |
|
1659 | 0 | // Make sure that the justification indeed corresponds to the header. |
1660 | 0 | if *fragment_decoded_justification.target_hash != fragment_header_hash |
1661 | 0 | || fragment_decoded_justification.target_number != fragment_decoded_header.number |
1662 | | { |
1663 | 0 | let error = VerifyFragmentError::TargetHashMismatch { |
1664 | 0 | justification_target_hash: *fragment_decoded_justification.target_hash, |
1665 | 0 | justification_target_height: fragment_decoded_justification.target_number, |
1666 | 0 | header_hash: fragment_header_hash, |
1667 | 0 | header_height: fragment_decoded_header.number, |
1668 | 0 | }; |
1669 | 0 | self.inner.verify_queue.clear(); |
1670 | 0 | self.inner.warp_sync_fragments_download = None; |
1671 | 0 | return (self.inner, Err(error)); |
1672 | 0 | } |
1673 | | |
1674 | | // Check whether the justification is valid. |
1675 | 0 | if let Err(err) = verify::verify_justification(verify::JustificationVerifyConfig { |
1676 | 0 | justification: &fragment_to_verify.scale_encoded_justification, |
1677 | 0 | block_number_bytes: self.inner.block_number_bytes, |
1678 | 0 | authorities_list: finalized_triggered_authorities |
1679 | 0 | .iter() |
1680 | 0 | .map(|a| &a.public_key[..]), Unexecuted instantiation: _RNCNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys0_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys0_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys0_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys0_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys0_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1681 | 0 | authorities_set_id: *after_finalized_block_authorities_set_id, |
1682 | 0 | randomness_seed, |
1683 | 0 | }) { |
1684 | 0 | self.inner.verify_queue.clear(); |
1685 | 0 | self.inner.warp_sync_fragments_download = None; |
1686 | 0 | return ( |
1687 | 0 | self.inner, |
1688 | 0 | Err(VerifyFragmentError::JustificationVerify(err)), |
1689 | 0 | ); |
1690 | 0 | } |
1691 | 0 |
|
1692 | 0 | // Try to grab the new list of authorities from the header. |
1693 | 0 | let new_authorities_list = fragment_decoded_header |
1694 | 0 | .digest |
1695 | 0 | .logs() |
1696 | 0 | .find_map(|log_item| match log_item { |
1697 | 0 | header::DigestItemRef::GrandpaConsensus(grandpa_log_item) => match grandpa_log_item |
1698 | | { |
1699 | 0 | header::GrandpaConsensusLogRef::ScheduledChange(change) |
1700 | 0 | | header::GrandpaConsensusLogRef::ForcedChange { change, .. } => { |
1701 | 0 | Some(change.next_authorities) |
1702 | | } |
1703 | 0 | _ => None, |
1704 | | }, |
1705 | 0 | _ => None, |
1706 | 0 | }) Unexecuted instantiation: _RNCNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys1_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys1_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys1_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys1_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys1_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1707 | 0 | .map(|next_authorities| { |
1708 | 0 | next_authorities |
1709 | 0 | .map(header::GrandpaAuthority::from) |
1710 | 0 | .collect() |
1711 | 0 | }); Unexecuted instantiation: _RNCNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys2_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys2_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentppE6verifys2_0Bb_ Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys2_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys2_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_22VerifyWarpSyncFragmentNtNtB9_3all19WarpSyncSourceExtraNtB1i_20WarpSyncRequestExtraE6verifys2_0CsibGXYHQB8Ea_25json_rpc_general_requests |
1712 | 0 |
|
1713 | 0 | // Fragments must only include headers containing an update to the list of authorities, |
1714 | 0 | // unless it's the very head of the chain. |
1715 | 0 | if new_authorities_list.is_none() |
1716 | 0 | && (!fragments_to_verify.final_set_of_fragments |
1717 | 0 | || fragments_to_verify.next_fragment_to_verify_index |
1718 | 0 | != fragments_to_verify.fragments.len() - 1) |
1719 | | { |
1720 | 0 | self.inner.verify_queue.clear(); |
1721 | 0 | self.inner.warp_sync_fragments_download = None; |
1722 | 0 | return (self.inner, Err(VerifyFragmentError::NonMinimalProof)); |
1723 | 0 | } |
1724 | 0 |
|
1725 | 0 | // Verification of the fragment has succeeded 🎉. We can now update `self`. |
1726 | 0 | fragments_to_verify.next_fragment_to_verify_index += 1; |
1727 | 0 | self.inner.warped_header_number = fragment_decoded_header.number; |
1728 | 0 | self.inner.warped_header_state_root = *fragment_decoded_header.state_root; |
1729 | 0 | self.inner.warped_header_extrinsics_root = *fragment_decoded_header.extrinsics_root; |
1730 | 0 | self.inner.warped_header_hash = fragment_header_hash; |
1731 | 0 | self.inner.warped_header = fragment_to_verify.scale_encoded_header.clone(); // TODO: figure out how to remove this clone() |
1732 | 0 | self.inner.warped_block_ty = WarpedBlockTy::Normal; |
1733 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1734 | 0 | hint_doesnt_match: false, |
1735 | 0 | }; |
1736 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
1737 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
1738 | 0 | } |
1739 | 0 | self.inner.runtime_calls = |
1740 | 0 | runtime_calls_default_value(self.inner.verified_chain_information.as_ref().consensus); |
1741 | 0 | if let Some(new_authorities_list) = new_authorities_list { |
1742 | 0 | *finalized_triggered_authorities = new_authorities_list; |
1743 | 0 | *after_finalized_block_authorities_set_id += 1; |
1744 | 0 | } |
1745 | 0 | if fragments_to_verify.next_fragment_to_verify_index == fragments_to_verify.fragments.len() |
1746 | 0 | { |
1747 | 0 | self.inner.verify_queue.pop_front().unwrap(); |
1748 | 0 | } |
1749 | | |
1750 | | // Returning. |
1751 | 0 | let result = Ok(( |
1752 | 0 | self.inner.warped_header_hash, |
1753 | 0 | self.inner.warped_header_number, |
1754 | 0 | )); |
1755 | 0 | (self.inner, result) |
1756 | 0 | } Unexecuted instantiation: _RNvMs4_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentppE6verifyB9_ Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE6verifyCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentppE6verifyB9_ Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE6verifyCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE6verifyCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs4_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_22VerifyWarpSyncFragmentNtNtB7_3all19WarpSyncSourceExtraNtB1g_20WarpSyncRequestExtraE6verifyCsibGXYHQB8Ea_25json_rpc_general_requests |
1757 | | } |
1758 | | |
1759 | | /// Error potentially returned by [`VerifyWarpSyncFragment::verify`]. |
1760 | | #[derive(Debug)] |
1761 | | pub enum VerifyFragmentError { |
1762 | | /// Justification found within the fragment is invalid. |
1763 | | JustificationVerify(verify::JustificationVerifyError), |
1764 | | /// Mismatch between the block targeted by the justification and the header. |
1765 | | TargetHashMismatch { |
1766 | | /// Hash of the block the justification targets. |
1767 | | justification_target_hash: [u8; 32], |
1768 | | /// Height of the block the justification targets. |
1769 | | justification_target_height: u64, |
1770 | | /// Hash of the header. |
1771 | | header_hash: [u8; 32], |
1772 | | /// Height of the header. |
1773 | | header_height: u64, |
1774 | | }, |
1775 | | /// Warp sync fragment doesn't contain an authorities list change when it should. |
1776 | | NonMinimalProof, |
1777 | | /// Header does not actually advance the warp syncing process. This means that a source has |
1778 | | /// sent a header below the requested hash. |
1779 | | BlockNumberNotIncrementing, |
1780 | | /// Warp sync proof is empty. |
1781 | | EmptyProof, |
1782 | | /// Failed to decode header. |
1783 | | InvalidHeader(header::Error), |
1784 | | /// Failed to decode justification. |
1785 | | InvalidJustification(decode::JustificationDecodeError), |
1786 | | } |
1787 | | |
1788 | | impl fmt::Display for VerifyFragmentError { |
1789 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1790 | 0 | match self { |
1791 | 0 | VerifyFragmentError::JustificationVerify(err) => fmt::Display::fmt(err, f), |
1792 | | VerifyFragmentError::TargetHashMismatch { |
1793 | 0 | justification_target_hash, |
1794 | 0 | justification_target_height, |
1795 | 0 | header_hash, |
1796 | 0 | header_height, |
1797 | 0 | } => { |
1798 | 0 | write!( |
1799 | 0 | f, |
1800 | 0 | "Justification target (hash: {}, height: {}) doesn't match the associated header (hash: {}, height: {})", |
1801 | 0 | HashDisplay(justification_target_hash), |
1802 | 0 | justification_target_height, |
1803 | 0 | HashDisplay(header_hash), |
1804 | 0 | header_height, |
1805 | 0 | ) |
1806 | | } |
1807 | 0 | VerifyFragmentError::NonMinimalProof => write!( |
1808 | 0 | f, |
1809 | 0 | "Warp sync proof fragment doesn't contain an authorities list change" |
1810 | 0 | ), |
1811 | 0 | VerifyFragmentError::BlockNumberNotIncrementing => write!( |
1812 | 0 | f, |
1813 | 0 | "Warp sync proof header doesn't advance the warp syncing process" |
1814 | 0 | ), |
1815 | 0 | VerifyFragmentError::EmptyProof => write!(f, "Warp sync proof is empty"), |
1816 | 0 | VerifyFragmentError::InvalidHeader(err) => write!(f, "Failed to decode header: {err}"), |
1817 | 0 | VerifyFragmentError::InvalidJustification(err) => { |
1818 | 0 | write!(f, "Failed to decode justification: {err}") |
1819 | | } |
1820 | | } |
1821 | 0 | } Unexecuted instantiation: _RNvXs5_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_19VerifyFragmentErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs5_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_19VerifyFragmentErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
1822 | | } |
1823 | | |
1824 | | /// Problem encountered during a call to [`BuildRuntime::build`] or |
1825 | | /// [`BuildChainInformation::build`] that can be attributed to the source sending invalid data. |
1826 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsG_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_17SourceMisbehaviorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsG_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_17SourceMisbehaviorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
1827 | | #[display(fmt = "{error}")] |
1828 | | pub struct SourceMisbehavior { |
1829 | | /// Source that committed the felony. `None` if the source has been removed between the moment |
1830 | | /// when the request has succeeded and when it has been verified. |
1831 | | pub source_id: Option<SourceId>, |
1832 | | /// Error that the source made. |
1833 | | pub error: SourceMisbehaviorTy, |
1834 | | } |
1835 | | |
1836 | | /// See [`SourceMisbehavior::error`]. |
1837 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsI_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_19SourceMisbehaviorTyNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsI_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_19SourceMisbehaviorTyNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
1838 | | pub enum SourceMisbehaviorTy { |
1839 | | /// Failed to verify Merkle proof. |
1840 | | InvalidMerkleProof(proof_decode::Error), |
1841 | | /// Merkle proof is missing the necessary entries. |
1842 | | MerkleProofEntriesMissing, |
1843 | | /// Downloaded block body doesn't match the expected extrinsics root. |
1844 | | BlockBodyExtrinsicsRootMismatch, |
1845 | | } |
1846 | | |
1847 | | /// Problem encountered during a call to [`BuildRuntime::build`]. |
1848 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsK_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_17BuildRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsK_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_17BuildRuntimeErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
1849 | | pub enum BuildRuntimeError { |
1850 | | /// The chain doesn't include any storage item at `:code`. |
1851 | | #[display(fmt = "The chain doesn't include any storage item at `:code`")] |
1852 | | MissingCode, |
1853 | | /// The storage item at `:heappages` is in an incorrect format. |
1854 | | #[display(fmt = "Invalid heap pages value: {_0}")] |
1855 | | InvalidHeapPages(executor::InvalidHeapPagesError), |
1856 | | /// Error building the runtime of the chain. |
1857 | | #[display(fmt = "Error building the runtime: {_0}")] |
1858 | | RuntimeBuild(executor::host::NewErr), |
1859 | | /// Source that has sent a proof didn't behave properly. |
1860 | | SourceMisbehavior(SourceMisbehavior), |
1861 | | } |
1862 | | |
1863 | | /// Ready to build the runtime of the finalized chain. |
1864 | | pub struct BuildRuntime<TSrc, TRq> { |
1865 | | inner: WarpSync<TSrc, TRq>, |
1866 | | } |
1867 | | |
1868 | | impl<TSrc, TRq> BuildRuntime<TSrc, TRq> { |
1869 | | /// Build the runtime of the chain. |
1870 | | /// |
1871 | | /// Must be passed parameters used for the construction of the runtime: a hint as to whether |
1872 | | /// the runtime is trusted and/or will be executed again, and whether unresolved function |
1873 | | /// imports are allowed. |
1874 | 0 | pub fn build( |
1875 | 0 | mut self, |
1876 | 0 | exec_hint: ExecHint, |
1877 | 0 | allow_unresolved_imports: bool, |
1878 | 0 | ) -> (WarpSync<TSrc, TRq>, Result<(), BuildRuntimeError>) { |
1879 | | let RuntimeDownload::NotVerified { |
1880 | 0 | downloaded_source, |
1881 | 0 | hint_doesnt_match, |
1882 | 0 | trie_proof, |
1883 | 0 | } = &mut self.inner.runtime_download |
1884 | | else { |
1885 | 0 | unreachable!() |
1886 | | }; |
1887 | | |
1888 | 0 | let downloaded_runtime = mem::take(trie_proof); |
1889 | 0 | let decoded_downloaded_runtime = |
1890 | 0 | match proof_decode::decode_and_verify_proof(proof_decode::Config { |
1891 | 0 | proof: &downloaded_runtime[..], |
1892 | 0 | }) { |
1893 | 0 | Ok(p) => p, |
1894 | 0 | Err(err) => { |
1895 | 0 | let downloaded_source = *downloaded_source; |
1896 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1897 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1898 | 0 | }; |
1899 | 0 | return ( |
1900 | 0 | self.inner, |
1901 | 0 | Err(BuildRuntimeError::SourceMisbehavior(SourceMisbehavior { |
1902 | 0 | source_id: downloaded_source, |
1903 | 0 | error: SourceMisbehaviorTy::InvalidMerkleProof(err), |
1904 | 0 | })), |
1905 | 0 | ); |
1906 | | } |
1907 | | }; |
1908 | | |
1909 | | let ( |
1910 | 0 | finalized_storage_code_merkle_value, |
1911 | 0 | finalized_storage_code_closest_ancestor_excluding, |
1912 | | ) = { |
1913 | 0 | let code_nibbles = trie::bytes_to_nibbles(b":code".iter().copied()).collect::<Vec<_>>(); |
1914 | 0 | match decoded_downloaded_runtime.closest_ancestor_in_proof( |
1915 | 0 | &self.inner.warped_header_state_root, |
1916 | 0 | code_nibbles.iter().take(code_nibbles.len() - 1).copied(), |
1917 | 0 | ) { |
1918 | 0 | Ok(Some(closest_ancestor_key)) => { |
1919 | 0 | let closest_ancestor_key = closest_ancestor_key.collect::<Vec<_>>(); |
1920 | 0 | let next_nibble = code_nibbles[closest_ancestor_key.len()]; |
1921 | 0 | let merkle_value = decoded_downloaded_runtime |
1922 | 0 | .trie_node_info( |
1923 | 0 | &self.inner.warped_header_state_root, |
1924 | 0 | closest_ancestor_key.iter().copied(), |
1925 | 0 | ) |
1926 | 0 | .unwrap() |
1927 | 0 | .children |
1928 | 0 | .child(next_nibble) |
1929 | 0 | .merkle_value(); |
1930 | 0 |
|
1931 | 0 | match merkle_value { |
1932 | 0 | Some(mv) => (mv.to_owned(), closest_ancestor_key), |
1933 | | None => { |
1934 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
1935 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1936 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1937 | 0 | }; |
1938 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
1939 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
1940 | 0 | } |
1941 | 0 | return (self.inner, Err(BuildRuntimeError::MissingCode)); |
1942 | | } |
1943 | | } |
1944 | | } |
1945 | | Ok(None) => { |
1946 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
1947 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1948 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1949 | 0 | }; |
1950 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
1951 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
1952 | 0 | } |
1953 | 0 | return (self.inner, Err(BuildRuntimeError::MissingCode)); |
1954 | | } |
1955 | | Err(proof_decode::IncompleteProofError { .. }) => { |
1956 | 0 | let downloaded_source = *downloaded_source; |
1957 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1958 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1959 | 0 | }; |
1960 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
1961 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
1962 | 0 | } |
1963 | 0 | return ( |
1964 | 0 | self.inner, |
1965 | 0 | Err(BuildRuntimeError::SourceMisbehavior(SourceMisbehavior { |
1966 | 0 | source_id: downloaded_source, |
1967 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
1968 | 0 | })), |
1969 | 0 | ); |
1970 | | } |
1971 | | } |
1972 | | }; |
1973 | | |
1974 | 0 | let finalized_storage_code = if let (false, Some(hint)) = |
1975 | 0 | (*hint_doesnt_match, self.inner.code_trie_node_hint.as_ref()) |
1976 | | { |
1977 | 0 | if hint.merkle_value == finalized_storage_code_merkle_value { |
1978 | 0 | &hint.storage_value |
1979 | | } else { |
1980 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1981 | 0 | hint_doesnt_match: true, |
1982 | 0 | }; |
1983 | 0 | return (self.inner, Ok(())); |
1984 | | } |
1985 | | } else { |
1986 | 0 | match decoded_downloaded_runtime |
1987 | 0 | .storage_value(&self.inner.warped_header_state_root, b":code") |
1988 | | { |
1989 | 0 | Ok(Some((code, _))) => code, |
1990 | | Ok(None) => { |
1991 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
1992 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
1993 | 0 | hint_doesnt_match: *hint_doesnt_match, |
1994 | 0 | }; |
1995 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
1996 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
1997 | 0 | } |
1998 | 0 | return (self.inner, Err(BuildRuntimeError::MissingCode)); |
1999 | | } |
2000 | | Err(proof_decode::IncompleteProofError { .. }) => { |
2001 | 0 | let downloaded_source = *downloaded_source; |
2002 | 0 | return ( |
2003 | 0 | self.inner, |
2004 | 0 | Err(BuildRuntimeError::SourceMisbehavior(SourceMisbehavior { |
2005 | 0 | source_id: downloaded_source, |
2006 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
2007 | 0 | })), |
2008 | 0 | ); |
2009 | | } |
2010 | | } |
2011 | | }; |
2012 | | |
2013 | 0 | let finalized_storage_heappages = match decoded_downloaded_runtime |
2014 | 0 | .storage_value(&self.inner.warped_header_state_root, b":heappages") |
2015 | | { |
2016 | 0 | Ok(val) => val.map(|(v, _)| v), Unexecuted instantiation: _RNCNvMs6_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_12BuildRuntimeppE5build0Bb_ Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5build0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeppE5build0Bb_ Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5build0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5build0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5build0CsibGXYHQB8Ea_25json_rpc_general_requests |
2017 | | Err(proof_decode::IncompleteProofError { .. }) => { |
2018 | 0 | let downloaded_source = *downloaded_source; |
2019 | 0 | return ( |
2020 | 0 | self.inner, |
2021 | 0 | Err(BuildRuntimeError::SourceMisbehavior(SourceMisbehavior { |
2022 | 0 | source_id: downloaded_source, |
2023 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
2024 | 0 | })), |
2025 | 0 | ); |
2026 | | } |
2027 | | }; |
2028 | | |
2029 | 0 | let decoded_heap_pages = |
2030 | 0 | match executor::storage_heap_pages_to_value(finalized_storage_heappages) { |
2031 | 0 | Ok(hp) => hp, |
2032 | 0 | Err(err) => { |
2033 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
2034 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
2035 | 0 | hint_doesnt_match: *hint_doesnt_match, |
2036 | 0 | }; |
2037 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
2038 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
2039 | 0 | } |
2040 | 0 | return (self.inner, Err(BuildRuntimeError::InvalidHeapPages(err))); |
2041 | | } |
2042 | | }; |
2043 | | |
2044 | 0 | let runtime = match HostVmPrototype::new(host::Config { |
2045 | 0 | module: &finalized_storage_code, |
2046 | 0 | heap_pages: decoded_heap_pages, |
2047 | 0 | exec_hint, |
2048 | 0 | allow_unresolved_imports, |
2049 | 0 | }) { |
2050 | 0 | Ok(runtime) => runtime, |
2051 | 0 | Err(err) => { |
2052 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
2053 | 0 | self.inner.runtime_download = RuntimeDownload::NotStarted { |
2054 | 0 | hint_doesnt_match: *hint_doesnt_match, |
2055 | 0 | }; |
2056 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
2057 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
2058 | 0 | } |
2059 | 0 | return (self.inner, Err(BuildRuntimeError::RuntimeBuild(err))); |
2060 | | } |
2061 | | }; |
2062 | | |
2063 | 0 | let chain_info_builder = chain_information::build::ChainInformationBuild::new( |
2064 | | chain_information::build::Config { |
2065 | | finalized_block_header: chain_information::build::ConfigFinalizedBlockHeader::Any { |
2066 | 0 | scale_encoded_header: self.inner.warped_header.clone(), |
2067 | 0 | known_finality: if self.inner.download_all_chain_information_storage_proofs { |
2068 | 0 | None |
2069 | | } else { |
2070 | 0 | Some(self.inner.warped_finality.clone()) |
2071 | | }, |
2072 | | }, |
2073 | 0 | block_number_bytes: self.inner.block_number_bytes, |
2074 | 0 | runtime, |
2075 | | }, |
2076 | | ); |
2077 | | |
2078 | 0 | if let chain_information::build::ChainInformationBuild::InProgress(in_progress) = |
2079 | 0 | &chain_info_builder |
2080 | | { |
2081 | 0 | for call in in_progress.remaining_calls() { |
2082 | 0 | if let hashbrown::hash_map::Entry::Vacant(entry) = |
2083 | 0 | self.inner.runtime_calls.entry(call) |
2084 | 0 | { |
2085 | 0 | entry.insert(CallProof::NotStarted); |
2086 | 0 | } |
2087 | | } |
2088 | 0 | } |
2089 | | |
2090 | 0 | self.inner.runtime_download = RuntimeDownload::Verified { |
2091 | 0 | downloaded_runtime: DownloadedRuntime { |
2092 | 0 | storage_code: Some(finalized_storage_code.to_vec()), |
2093 | 0 | storage_heap_pages: finalized_storage_heappages.map(|v| v.to_vec()), Unexecuted instantiation: _RNCNvMs6_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_12BuildRuntimeppE5builds_0Bb_ Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5builds_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeppE5builds_0Bb_ Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5builds_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5builds_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_12BuildRuntimeNtNtB9_3all19WarpSyncSourceExtraNtB18_20WarpSyncRequestExtraE5builds_0CsibGXYHQB8Ea_25json_rpc_general_requests |
2094 | 0 | code_merkle_value: Some(finalized_storage_code_merkle_value), |
2095 | 0 | closest_ancestor_excluding: Some(finalized_storage_code_closest_ancestor_excluding), |
2096 | 0 | }, |
2097 | 0 | chain_info_builder, |
2098 | 0 | }; |
2099 | 0 |
|
2100 | 0 | (self.inner, Ok(())) |
2101 | 0 | } Unexecuted instantiation: _RNvMs6_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB5_12BuildRuntimeppE5buildB9_ Unexecuted instantiation: _RNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_12BuildRuntimeNtNtB7_3all19WarpSyncSourceExtraNtB16_20WarpSyncRequestExtraE5buildCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_12BuildRuntimeppE5buildB9_ Unexecuted instantiation: _RNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_12BuildRuntimeNtNtB7_3all19WarpSyncSourceExtraNtB16_20WarpSyncRequestExtraE5buildCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_12BuildRuntimeNtNtB7_3all19WarpSyncSourceExtraNtB16_20WarpSyncRequestExtraE5buildCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs6_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_12BuildRuntimeNtNtB7_3all19WarpSyncSourceExtraNtB16_20WarpSyncRequestExtraE5buildCsibGXYHQB8Ea_25json_rpc_general_requests |
2102 | | } |
2103 | | |
2104 | | /// Problem encountered during a call to [`BuildChainInformation::build`]. |
2105 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsM_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncNtB5_26BuildChainInformationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsM_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncNtB5_26BuildChainInformationErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
2106 | | pub enum BuildChainInformationError { |
2107 | | /// Error building the chain information. |
2108 | | #[display(fmt = "Error building the chain information: {_0}")] |
2109 | | ChainInformationBuild(chain_information::build::Error), |
2110 | | /// Source that has sent a proof didn't behave properly. |
2111 | | SourceMisbehavior(SourceMisbehavior), |
2112 | | } |
2113 | | |
2114 | | /// Ready to verify the parameters of the chain against the finalized block. |
2115 | | pub struct BuildChainInformation<TSrc, TRq> { |
2116 | | inner: WarpSync<TSrc, TRq>, |
2117 | | } |
2118 | | |
2119 | | impl<TSrc, TRq> BuildChainInformation<TSrc, TRq> { |
2120 | | /// Build the information about the chain. |
2121 | 0 | pub fn build( |
2122 | 0 | mut self, |
2123 | 0 | ) -> ( |
2124 | 0 | WarpSync<TSrc, TRq>, |
2125 | 0 | Result<RuntimeInformation, BuildChainInformationError>, |
2126 | 0 | ) { |
2127 | 0 | let downloaded_body = match &mut self.inner.body_download { |
2128 | 0 | BodyDownload::NotNeeded => None, |
2129 | | BodyDownload::Downloaded { |
2130 | 0 | downloaded_source, |
2131 | 0 | body, |
2132 | 0 | } => { |
2133 | 0 | if header::extrinsics_root(body) != self.inner.warped_header_extrinsics_root { |
2134 | 0 | let source_id = *downloaded_source; |
2135 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
2136 | 0 | return ( |
2137 | 0 | self.inner, |
2138 | 0 | Err(BuildChainInformationError::SourceMisbehavior( |
2139 | 0 | SourceMisbehavior { |
2140 | 0 | source_id, |
2141 | 0 | error: SourceMisbehaviorTy::BlockBodyExtrinsicsRootMismatch, |
2142 | 0 | }, |
2143 | 0 | )), |
2144 | 0 | ); |
2145 | 0 | } |
2146 | 0 |
|
2147 | 0 | Some(body) |
2148 | | } |
2149 | 0 | _ => unreachable!(), |
2150 | | }; |
2151 | | |
2152 | | let RuntimeDownload::Verified { |
2153 | 0 | mut chain_info_builder, |
2154 | 0 | downloaded_runtime, |
2155 | | .. |
2156 | 0 | } = mem::replace( |
2157 | 0 | &mut self.inner.runtime_download, |
2158 | 0 | RuntimeDownload::NotStarted { |
2159 | 0 | hint_doesnt_match: false, |
2160 | 0 | }, |
2161 | 0 | ) |
2162 | | else { |
2163 | 0 | unreachable!() |
2164 | | }; |
2165 | | |
2166 | 0 | let runtime_calls = mem::take(&mut self.inner.runtime_calls); |
2167 | 0 |
|
2168 | 0 | debug_assert!(runtime_calls |
2169 | 0 | .values() |
2170 | 0 | .all(|c| matches!(c, CallProof::Downloaded { .. }))); Unexecuted instantiation: _RNCNvMs7_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_21BuildChainInformationppE5builds_0Bb_ Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5builds_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationppE5builds_0Bb_ Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5builds_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5builds_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5builds_0CsibGXYHQB8Ea_25json_rpc_general_requests |
2171 | | |
2172 | | // Decode all the Merkle proofs that have been received. |
2173 | 0 | let calls = { |
2174 | 0 | let mut decoded_proofs = hashbrown::HashMap::with_capacity_and_hasher( |
2175 | 0 | runtime_calls.len(), |
2176 | 0 | fnv::FnvBuildHasher::default(), |
2177 | 0 | ); |
2178 | | |
2179 | 0 | for (call, proof) in runtime_calls { |
2180 | | let CallProof::Downloaded { |
2181 | 0 | proof, |
2182 | 0 | downloaded_source, |
2183 | 0 | } = proof |
2184 | | else { |
2185 | 0 | unreachable!() |
2186 | | }; |
2187 | | |
2188 | 0 | let decoded_proof = |
2189 | 0 | match proof_decode::decode_and_verify_proof(proof_decode::Config { |
2190 | 0 | proof: proof.into_iter(), |
2191 | 0 | }) { |
2192 | 0 | Ok(d) => d, |
2193 | 0 | Err(err) => { |
2194 | 0 | return ( |
2195 | 0 | self.inner, |
2196 | 0 | Err(BuildChainInformationError::SourceMisbehavior( |
2197 | 0 | SourceMisbehavior { |
2198 | 0 | source_id: downloaded_source, |
2199 | 0 | error: SourceMisbehaviorTy::InvalidMerkleProof(err), |
2200 | 0 | }, |
2201 | 0 | )), |
2202 | 0 | ); |
2203 | | } |
2204 | | }; |
2205 | | |
2206 | 0 | decoded_proofs.insert(call, (decoded_proof, downloaded_source)); |
2207 | | } |
2208 | | |
2209 | 0 | decoded_proofs |
2210 | | }; |
2211 | | |
2212 | | loop { |
2213 | 0 | let in_progress = match chain_info_builder { |
2214 | | chain_information::build::ChainInformationBuild::Finished { |
2215 | 0 | result: Ok(chain_information), |
2216 | 0 | virtual_machine, |
2217 | 0 | } => { |
2218 | 0 | // This `if` is necessary as in principle we might have continued warp syncing |
2219 | 0 | // after downloading everything needed but before building the chain |
2220 | 0 | // information. |
2221 | 0 | if self.inner.warped_header_number |
2222 | 0 | == chain_information.as_ref().finalized_block_header.number |
2223 | 0 | { |
2224 | 0 | self.inner.warped_block_ty = WarpedBlockTy::AlreadyVerified; |
2225 | 0 | } |
2226 | | |
2227 | 0 | let finalized_body = downloaded_body.map(mem::take); |
2228 | 0 | if !matches!(self.inner.body_download, BodyDownload::NotNeeded) { |
2229 | 0 | self.inner.body_download = BodyDownload::NotStarted; |
2230 | 0 | } |
2231 | | |
2232 | 0 | self.inner.verified_chain_information = chain_information; |
2233 | 0 | self.inner.runtime_calls = runtime_calls_default_value( |
2234 | 0 | self.inner.verified_chain_information.as_ref().consensus, |
2235 | 0 | ); |
2236 | 0 | return ( |
2237 | 0 | self.inner, |
2238 | 0 | Ok(RuntimeInformation { |
2239 | 0 | finalized_runtime: virtual_machine, |
2240 | 0 | finalized_body, |
2241 | 0 | finalized_storage_code: downloaded_runtime.storage_code, |
2242 | 0 | finalized_storage_heap_pages: downloaded_runtime.storage_heap_pages, |
2243 | 0 | finalized_storage_code_merkle_value: downloaded_runtime |
2244 | 0 | .code_merkle_value, |
2245 | 0 | finalized_storage_code_closest_ancestor_excluding: downloaded_runtime |
2246 | 0 | .closest_ancestor_excluding, |
2247 | 0 | }), |
2248 | 0 | ); |
2249 | | } |
2250 | | chain_information::build::ChainInformationBuild::Finished { |
2251 | 0 | result: Err(err), |
2252 | 0 | .. |
2253 | 0 | } => { |
2254 | 0 | self.inner.warped_block_ty = WarpedBlockTy::KnownBad; |
2255 | 0 | return ( |
2256 | 0 | self.inner, |
2257 | 0 | Err(BuildChainInformationError::ChainInformationBuild(err)), |
2258 | 0 | ); |
2259 | | } |
2260 | 0 | chain_information::build::ChainInformationBuild::InProgress(in_progress) => { |
2261 | 0 | in_progress |
2262 | | } |
2263 | | }; |
2264 | | |
2265 | 0 | chain_info_builder = match in_progress { |
2266 | 0 | chain_information::build::InProgress::StorageGet(get) => { |
2267 | 0 | // TODO: child tries not supported |
2268 | 0 | let (proof, downloaded_source) = calls.get(&get.call_in_progress()).unwrap(); |
2269 | 0 | let value = match proof |
2270 | 0 | .storage_value(&self.inner.warped_header_state_root, get.key().as_ref()) |
2271 | | { |
2272 | 0 | Ok(v) => v, |
2273 | | Err(proof_decode::IncompleteProofError { .. }) => { |
2274 | 0 | return ( |
2275 | 0 | self.inner, |
2276 | 0 | Err(BuildChainInformationError::SourceMisbehavior( |
2277 | 0 | SourceMisbehavior { |
2278 | 0 | source_id: *downloaded_source, |
2279 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
2280 | 0 | }, |
2281 | 0 | )), |
2282 | 0 | ); |
2283 | | } |
2284 | | }; |
2285 | | |
2286 | 0 | get.inject_value(value.map(|(val, ver)| (iter::once(val), ver))) Unexecuted instantiation: _RNCNvMs7_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB7_21BuildChainInformationppE5build0Bb_ Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5build0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationppE5build0Bb_ Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5build0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5build0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB7_21BuildChainInformationNtNtB9_3all19WarpSyncSourceExtraNtB1h_20WarpSyncRequestExtraE5build0CsibGXYHQB8Ea_25json_rpc_general_requests |
2287 | | } |
2288 | 0 | chain_information::build::InProgress::NextKey(nk) => { |
2289 | 0 | // TODO: child tries not supported |
2290 | 0 | let (proof, downloaded_source) = calls.get(&nk.call_in_progress()).unwrap(); |
2291 | 0 | let value = match proof.next_key( |
2292 | 0 | &self.inner.warped_header_state_root, |
2293 | 0 | nk.key(), |
2294 | 0 | nk.or_equal(), |
2295 | 0 | nk.prefix(), |
2296 | 0 | nk.branch_nodes(), |
2297 | 0 | ) { |
2298 | 0 | Ok(v) => v, |
2299 | | Err(proof_decode::IncompleteProofError { .. }) => { |
2300 | 0 | return ( |
2301 | 0 | self.inner, |
2302 | 0 | Err(BuildChainInformationError::SourceMisbehavior( |
2303 | 0 | SourceMisbehavior { |
2304 | 0 | source_id: *downloaded_source, |
2305 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
2306 | 0 | }, |
2307 | 0 | )), |
2308 | 0 | ); |
2309 | | } |
2310 | | }; |
2311 | 0 | nk.inject_key(value) |
2312 | | } |
2313 | 0 | chain_information::build::InProgress::ClosestDescendantMerkleValue(mv) => { |
2314 | 0 | // TODO: child tries not supported |
2315 | 0 | let (proof, downloaded_source) = calls.get(&mv.call_in_progress()).unwrap(); |
2316 | 0 | let value = match proof.closest_descendant_merkle_value( |
2317 | 0 | &self.inner.warped_header_state_root, |
2318 | 0 | mv.key(), |
2319 | 0 | ) { |
2320 | 0 | Ok(v) => v, |
2321 | | Err(proof_decode::IncompleteProofError { .. }) => { |
2322 | 0 | return ( |
2323 | 0 | self.inner, |
2324 | 0 | Err(BuildChainInformationError::SourceMisbehavior( |
2325 | 0 | SourceMisbehavior { |
2326 | 0 | source_id: *downloaded_source, |
2327 | 0 | error: SourceMisbehaviorTy::MerkleProofEntriesMissing, |
2328 | 0 | }, |
2329 | 0 | )), |
2330 | 0 | ); |
2331 | | } |
2332 | | }; |
2333 | 0 | mv.inject_merkle_value(value) |
2334 | | } |
2335 | | }; |
2336 | | } |
2337 | 0 | } Unexecuted instantiation: _RNvMs7_NtNtCsN16ciHI6Qf_7smoldot4sync9warp_syncINtB5_21BuildChainInformationppE5buildB9_ Unexecuted instantiation: _RNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_21BuildChainInformationNtNtB7_3all19WarpSyncSourceExtraNtB1f_20WarpSyncRequestExtraE5buildCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_21BuildChainInformationppE5buildB9_ Unexecuted instantiation: _RNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_21BuildChainInformationNtNtB7_3all19WarpSyncSourceExtraNtB1f_20WarpSyncRequestExtraE5buildCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_21BuildChainInformationNtNtB7_3all19WarpSyncSourceExtraNtB1f_20WarpSyncRequestExtraE5buildCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMs7_NtNtCseuYC0Zibziv_7smoldot4sync9warp_syncINtB5_21BuildChainInformationNtNtB7_3all19WarpSyncSourceExtraNtB1f_20WarpSyncRequestExtraE5buildCsibGXYHQB8Ea_25json_rpc_general_requests |
2338 | | } |
2339 | | |
2340 | | /// Returns `true` if `a` and `b` are equal. |
2341 | 0 | fn parameters_equal(mut a: &[u8], b: impl Iterator<Item = impl AsRef<[u8]>>) -> bool { |
2342 | 0 | for slice in b { |
2343 | 0 | let slice = slice.as_ref(); |
2344 | 0 |
|
2345 | 0 | if a.len() < slice.len() { |
2346 | 0 | return false; |
2347 | 0 | } |
2348 | 0 |
|
2349 | 0 | if &a[..slice.len()] != slice { |
2350 | 0 | return false; |
2351 | 0 | } |
2352 | 0 |
|
2353 | 0 | a = &a[slice.len()..]; |
2354 | | } |
2355 | | |
2356 | 0 | true |
2357 | 0 | } Unexecuted instantiation: _RINvNtNtCsN16ciHI6Qf_7smoldot4sync9warp_sync16parameters_equalppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync16parameters_equalINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyBZ_EECsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync16parameters_equalppEB6_ Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync16parameters_equalINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyBZ_EECsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync16parameters_equalINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyBZ_EECscDgN54JpMGG_6author Unexecuted instantiation: _RINvNtNtCseuYC0Zibziv_7smoldot4sync9warp_sync16parameters_equalINtNtCsdZExvAaxgia_5alloc3vec3VechEINtNtNtNtCsaYZPK01V26L_4core4iter7sources5empty5EmptyBZ_EECsibGXYHQB8Ea_25json_rpc_general_requests |