/__w/smoldot/smoldot/repo/lib/src/chain/async_tree.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 | | //! Performing asynchronous operations on blocks. |
19 | | //! |
20 | | //! # Summary |
21 | | //! |
22 | | //! This module contains the [`AsyncTree`] data structure. |
23 | | //! |
24 | | //! When a block is inserted in the data structure, it is added to the so-called "input tree" and |
25 | | //! its status is marked as pending. The data structure then starts, for each block marked as |
26 | | //! pending, an asynchronous operation (what this operation consists of is decided by the API |
27 | | //! user). Once an asynchronous operation is successful, the status of the block is switched to |
28 | | //! "finished". The data structure then puts the blocks in the so-called "output tree". |
29 | | //! |
30 | | //! The output tree is consistent, meaning that if the asynchronous operation of a child finishes |
31 | | //! before the one of its parent, the child will be added to the output tree only after its |
32 | | //! parent has finished its operation. |
33 | | //! Similarly, if a block is finalized in the input tree, it only gets finalized in the output |
34 | | //! tree after all of its ancestors have all finished their asynchronous operations. |
35 | | //! |
36 | | //! An example use case is: you insert block headers, then for each block you download its body, |
37 | | //! and thus obtain as output a tree of block headers and bodies. |
38 | | //! |
39 | | //! # Details |
40 | | //! |
41 | | //! The [`AsyncTree`] data structure contains two trees of blocks: one input tree and one output |
42 | | //! tree. The output tree is a subset of the input tree. |
43 | | //! |
44 | | //! Each of the two trees (input and output) has the following properties: |
45 | | //! |
46 | | //! - A finalized block. |
47 | | //! - A tree of non-finalized blocks that all descend from the finalized block. |
48 | | //! - A best block that can be either the finalized block or one of the non-finalized blocks. |
49 | | //! |
50 | | //! Furthermore, each block has the following properties: |
51 | | //! |
52 | | //! - An opaque user data. |
53 | | //! - A status: pending, in progress, or finished. Once finished, an "asynchronous user data" is |
54 | | //! also attached to the block. All the blocks of the output tree are always in the "finished" |
55 | | //! state. |
56 | | //! |
57 | | //! At initialization, both the input and output trees are initialized to the same finalized |
58 | | //! block (that is also the best block), and don't have any non-finalized block. |
59 | | //! |
60 | | //! # Example |
61 | | //! |
62 | | //! ``` |
63 | | //! use smoldot::chain::async_tree; |
64 | | //! use std::time::{Instant, Duration}; |
65 | | //! |
66 | | //! let mut tree = async_tree::AsyncTree::new(async_tree::Config { |
67 | | //! finalized_async_user_data: "hello", |
68 | | //! retry_after_failed: Duration::from_secs(5), |
69 | | //! blocks_capacity: 32, |
70 | | //! }); |
71 | | //! |
72 | | //! // Insert a new best block, child of the finalized block. |
73 | | //! // When doing so, we insert a "user data", a value opaque to the tree and that can be |
74 | | //! // retreived later. Here we pass "my block". |
75 | | //! let _my_block_index = tree.input_insert_block("my block", None, false, true); |
76 | | //! |
77 | | //! // When calling `next_necessary_async_op`, the tree now generates a new asynchronous |
78 | | //! // operation id. |
79 | | //! let async_op_id = match tree.next_necessary_async_op(&Instant::now()) { |
80 | | //! async_tree::NextNecessaryAsyncOp::Ready(params) => { |
81 | | //! assert_eq!(params.block_index, _my_block_index); |
82 | | //! assert_eq!(tree[params.block_index], "my block"); |
83 | | //! params.id |
84 | | //! } |
85 | | //! async_tree::NextNecessaryAsyncOp::NotReady { when: _ } => { |
86 | | //! // In this example, this variant can't be returned. In practice, however, you need |
87 | | //! // to call `next_necessary_async_op` again after `when`. |
88 | | //! panic!(); |
89 | | //! } |
90 | | //! }; |
91 | | //! |
92 | | //! // The user is now responsible for performing this asynchronous operation. |
93 | | //! // When it is finished, call `async_op_finished`. |
94 | | //! // Just like when inserting a new block, we insert another "user data" in all the blocks that |
95 | | //! // have this asynchronous operation associated to them. |
96 | | //! tree.async_op_finished(async_op_id, "world"); |
97 | | //! |
98 | | //! // You can now advance the best and finalized block of the tree. Calling this function tries |
99 | | //! // to update the tree to match the best and finalized block of the input, except that only |
100 | | //! // blocks whose asynchronous operation is finished are considered. |
101 | | //! match tree.try_advance_output() { |
102 | | //! Some(async_tree::OutputUpdate::Block(block)) => { |
103 | | //! assert_eq!(block.index, _my_block_index); |
104 | | //! assert!(block.is_new_best); |
105 | | //! } |
106 | | //! _ => unreachable!() // Unreachable in this example. |
107 | | //! } |
108 | | //! ``` |
109 | | |
110 | | use crate::chain::fork_tree; |
111 | | use alloc::vec::Vec; |
112 | | use core::{cmp, mem, ops, time::Duration}; |
113 | | |
114 | | pub use fork_tree::NodeIndex; |
115 | | |
116 | | /// Identifier for an asynchronous operation in the [`AsyncTree`]. |
117 | | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] |
118 | | pub struct AsyncOpId(u64); |
119 | | |
120 | | #[derive(Debug)] |
121 | | pub enum NextNecessaryAsyncOp<TNow> { |
122 | | Ready(AsyncOpParams), |
123 | | NotReady { when: Option<TNow> }, |
124 | | } |
125 | | |
126 | | /// Information about an operation that must be started. |
127 | | #[derive(Debug)] |
128 | | pub struct AsyncOpParams { |
129 | | /// Identifier to later provide when calling [`AsyncTree::async_op_finished`] or |
130 | | /// [`AsyncTree::async_op_failure`]. |
131 | | pub id: AsyncOpId, |
132 | | |
133 | | /// Index of the block to perform the operation against. |
134 | | pub block_index: NodeIndex, |
135 | | } |
136 | | |
137 | | /// Configuration for [`AsyncTree::new`]. |
138 | | pub struct Config<TAsync> { |
139 | | /// Outcome of the asynchronous operation of the finalized block. |
140 | | pub finalized_async_user_data: TAsync, |
141 | | |
142 | | /// After an asynchronous operation fails, retry after this given duration. |
143 | | pub retry_after_failed: Duration, |
144 | | |
145 | | /// Number of elements to initially allocate to store blocks. |
146 | | /// |
147 | | /// This is not a cap to the number of blocks, but merely the amount of memory to initially |
148 | | /// reserve. |
149 | | /// |
150 | | /// This covers all blocks from the moment they're added as input to the moment they're |
151 | | /// finalized in the output. |
152 | | /// |
153 | | /// It is legal to pass 0, in which case no memory is pre-allocated. |
154 | | pub blocks_capacity: usize, |
155 | | } |
156 | | |
157 | | /// See [the module-level documentation](..). |
158 | | pub struct AsyncTree<TNow, TBl, TAsync> { |
159 | | /// State of all the output non-finalized blocks, which includes all the input blocks. |
160 | | non_finalized_blocks: fork_tree::ForkTree<Block<TNow, TBl, TAsync>>, |
161 | | |
162 | | /// Outcome of the asynchronous operation for the finalized block. |
163 | | output_finalized_async_user_data: TAsync, |
164 | | |
165 | | /// Index within [`AsyncTree::non_finalized_blocks`] of the current "output" best block. |
166 | | /// `None` if the output best block is the output finalized block. |
167 | | /// |
168 | | /// The value of [`Block::async_op`] for this block is guaranteed to be |
169 | | /// [`AsyncOpState::Finished`]. |
170 | | output_best_block_index: Option<fork_tree::NodeIndex>, |
171 | | |
172 | | /// Index within [`AsyncTree::non_finalized_blocks`] of the finalized block according to |
173 | | /// the input. `None` if the input finalized block is the same as the output finalized block. |
174 | | /// |
175 | | /// The value of [`Block::async_op`] for this block is guaranteed to **not** be |
176 | | /// [`AsyncOpState::Finished`]. |
177 | | input_finalized_index: Option<fork_tree::NodeIndex>, |
178 | | |
179 | | /// Index within [`AsyncTree::non_finalized_blocks`] of the current "input" best block. |
180 | | /// `None` if the input best block is the output finalized block. |
181 | | input_best_block_index: Option<fork_tree::NodeIndex>, |
182 | | |
183 | | /// Incremented by one and stored within [`Block::input_best_block_weight`]. |
184 | | input_best_block_next_weight: u32, |
185 | | |
186 | | /// Weight that would be stored in [`Block::input_best_block_weight`] for the output finalized |
187 | | /// block. |
188 | | output_finalized_block_weight: u32, |
189 | | |
190 | | /// Identifier to assign to the next asynchronous operation. |
191 | | next_async_op_id: AsyncOpId, |
192 | | |
193 | | /// See [`Config::retry_after_failed`]. |
194 | | retry_after_failed: Duration, |
195 | | } |
196 | | |
197 | | impl<TNow, TBl, TAsync> AsyncTree<TNow, TBl, TAsync> |
198 | | where |
199 | | TNow: Clone + ops::Add<Duration, Output = TNow> + Ord, |
200 | | TAsync: Clone, |
201 | | { |
202 | | /// Returns a new empty [`AsyncTree`]. |
203 | 0 | pub fn new(config: Config<TAsync>) -> Self { |
204 | 0 | AsyncTree { |
205 | 0 | output_best_block_index: None, |
206 | 0 | output_finalized_async_user_data: config.finalized_async_user_data, |
207 | 0 | non_finalized_blocks: fork_tree::ForkTree::with_capacity(config.blocks_capacity), |
208 | 0 | input_finalized_index: None, |
209 | 0 | input_best_block_index: None, |
210 | 0 | input_best_block_next_weight: 2, |
211 | 0 | output_finalized_block_weight: 1, // `0` is reserved for blocks who are never best. |
212 | 0 | next_async_op_id: AsyncOpId(0), |
213 | 0 | retry_after_failed: config.retry_after_failed, |
214 | 0 | } |
215 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE3newB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE3newCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE3newCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE3newCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE3newB6_ |
216 | | |
217 | | /// Returns the number of non-finalized blocks. |
218 | | /// |
219 | | /// This is equal to the number of items yielded by [`AsyncTree::input_output_iter_unordered`]. |
220 | 0 | pub fn num_input_non_finalized_blocks(&self) -> usize { |
221 | 0 | self.non_finalized_blocks.len() |
222 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE30num_input_non_finalized_blocksB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE30num_input_non_finalized_blocksCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE30num_input_non_finalized_blocksCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE30num_input_non_finalized_blocksB6_ |
223 | | |
224 | | /// Replaces all asynchronous operation user data with new values. |
225 | | /// |
226 | | /// The returned tree keeps the same [`NodeIndex`]es as `self`. |
227 | 0 | pub fn map_async_op_user_data<TAsync2>( |
228 | 0 | self, |
229 | 0 | mut map: impl FnMut(TAsync) -> TAsync2, |
230 | 0 | ) -> AsyncTree<TNow, TBl, TAsync2> { |
231 | 0 | AsyncTree { |
232 | 0 | output_best_block_index: self.output_best_block_index, |
233 | 0 | output_finalized_async_user_data: map(self.output_finalized_async_user_data), |
234 | 0 | non_finalized_blocks: self.non_finalized_blocks.map(move |block| Block { |
235 | 0 | async_op: match block.async_op { |
236 | | AsyncOpState::Finished { |
237 | 0 | user_data, |
238 | 0 | reported, |
239 | 0 | } => AsyncOpState::Finished { |
240 | 0 | user_data: map(user_data), |
241 | 0 | reported, |
242 | 0 | }, |
243 | | AsyncOpState::InProgress { |
244 | 0 | async_op_id, |
245 | 0 | timeout, |
246 | 0 | } => AsyncOpState::InProgress { |
247 | 0 | async_op_id, |
248 | 0 | timeout, |
249 | 0 | }, |
250 | | AsyncOpState::Pending { |
251 | 0 | same_as_parent, |
252 | 0 | timeout, |
253 | 0 | } => AsyncOpState::Pending { |
254 | 0 | same_as_parent, |
255 | 0 | timeout, |
256 | 0 | }, |
257 | | }, |
258 | 0 | input_best_block_weight: block.input_best_block_weight, |
259 | 0 | user_data: block.user_data, |
260 | 0 | }), Unexecuted instantiation: _RNCINvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB5_9AsyncTreepppE22map_async_op_user_datappE0B9_ Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB5_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB17_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1G_7RuntimeEEE22map_async_op_user_dataB2V_NCNCINvB1G_14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0si_0E0B4H_ Unexecuted instantiation: _RNCINvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB5_9AsyncTreepppE22map_async_op_user_datappE0B9_ |
261 | 0 | input_finalized_index: self.input_finalized_index, |
262 | 0 | input_best_block_index: self.input_best_block_index, |
263 | 0 | input_best_block_next_weight: self.input_best_block_next_weight, |
264 | 0 | output_finalized_block_weight: self.output_finalized_block_weight, |
265 | 0 | next_async_op_id: self.next_async_op_id, |
266 | 0 | retry_after_failed: self.retry_after_failed, |
267 | 0 | } |
268 | 0 | } Unexecuted instantiation: _RINvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB3_9AsyncTreepppE22map_async_op_user_datappEB7_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB3_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB15_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1E_7RuntimeEEE22map_async_op_user_dataB2T_NCNCINvB1E_14run_backgroundNtNtCsDDUKWWCHAU_18smoldot_light_wasm8platform11PlatformRefE0si_0EB4F_ Unexecuted instantiation: _RINvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB3_9AsyncTreepppE22map_async_op_user_datappEB7_ |
269 | | |
270 | | /// Returns the [`NodeIndex`] of the current "output" best block. |
271 | | /// |
272 | | /// Returns `None` if there is no best block. In terms of logic, this means that the best block |
273 | | /// is the finalized block, which is out of scope of this data structure. |
274 | 0 | pub fn output_best_block_index(&self) -> Option<(NodeIndex, &'_ TAsync)> { |
275 | 0 | self.output_best_block_index.map(|best_block_index| { |
276 | 0 | ( |
277 | 0 | best_block_index, |
278 | 0 | match &self |
279 | 0 | .non_finalized_blocks |
280 | 0 | .get(best_block_index) |
281 | 0 | .unwrap() |
282 | 0 | .async_op |
283 | | { |
284 | | AsyncOpState::Finished { |
285 | | reported: true, |
286 | 0 | user_data, |
287 | 0 | } => user_data, |
288 | 0 | _ => unreachable!(), |
289 | | }, |
290 | | ) |
291 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23output_best_block_index0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE23output_best_block_index0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE23output_best_block_index0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE23output_best_block_index0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23output_best_block_index0B8_ |
292 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23output_best_block_indexB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE23output_best_block_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE23output_best_block_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE23output_best_block_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23output_best_block_indexB6_ |
293 | | |
294 | | /// Returns the outcome of the asynchronous operation for the output finalized block. |
295 | | /// |
296 | | /// This is the value that was passed at initialization, or is updated after |
297 | | /// [`AsyncTree::try_advance_output`] has returned [`OutputUpdate::Finalized`]. |
298 | 0 | pub fn output_finalized_async_user_data(&self) -> &TAsync { |
299 | 0 | &self.output_finalized_async_user_data |
300 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32output_finalized_async_user_dataB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE32output_finalized_async_user_dataCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE32output_finalized_async_user_dataCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32output_finalized_async_user_dataB6_ |
301 | | |
302 | | /// Returns the asynchronous operation user data associated to the given block. |
303 | | /// |
304 | | /// Returns `None` if the asynchronous operation isn't complete for this block yet. |
305 | | /// |
306 | | /// # Panic |
307 | | /// |
308 | | /// Panics if the [`NodeIndex`] is invalid. |
309 | | /// |
310 | 0 | pub fn block_async_user_data(&self, node_index: NodeIndex) -> Option<&TAsync> { |
311 | 0 | match &self.non_finalized_blocks.get(node_index).unwrap().async_op { |
312 | 0 | AsyncOpState::Finished { user_data, .. } => Some(user_data), |
313 | 0 | _ => None, |
314 | | } |
315 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE21block_async_user_dataB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE21block_async_user_dataCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE21block_async_user_dataCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE21block_async_user_dataB6_ |
316 | | |
317 | | /// Returns the asynchronous operation user data associated to the given block. |
318 | | /// |
319 | | /// Returns `None` if the asynchronous operation isn't complete for this block yet. |
320 | | /// |
321 | | /// # Panic |
322 | | /// |
323 | | /// Panics if the [`NodeIndex`] is invalid. |
324 | | /// |
325 | 0 | pub fn block_async_user_data_mut(&mut self, node_index: NodeIndex) -> Option<&mut TAsync> { |
326 | 0 | match &mut self |
327 | 0 | .non_finalized_blocks |
328 | 0 | .get_mut(node_index) |
329 | 0 | .unwrap() |
330 | 0 | .async_op |
331 | | { |
332 | 0 | AsyncOpState::Finished { user_data, .. } => Some(user_data), |
333 | 0 | _ => None, |
334 | | } |
335 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE25block_async_user_data_mutB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE25block_async_user_data_mutB6_ |
336 | | |
337 | | /// Returns the parent of the given node. Returns `None` if the node doesn't have any parent, |
338 | | /// meaning that its parent is the finalized node. |
339 | | /// |
340 | | /// # Panic |
341 | | /// |
342 | | /// Panics if the [`NodeIndex`] is invalid. |
343 | | /// |
344 | 0 | pub fn parent(&self, node: NodeIndex) -> Option<NodeIndex> { |
345 | 0 | self.non_finalized_blocks.parent(node) |
346 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE6parentB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE6parentCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE6parentCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE6parentB6_ |
347 | | |
348 | | /// Returns the ancestors of the given node. The iterator stops when it reaches the finalized |
349 | | /// block. The iterator is empty if the parent of the node is the finalized block. |
350 | | /// |
351 | | /// # Panic |
352 | | /// |
353 | | /// Panics if the [`NodeIndex`] is invalid. |
354 | | /// |
355 | 0 | pub fn ancestors(&'_ self, node: NodeIndex) -> impl Iterator<Item = NodeIndex> + '_ { |
356 | 0 | self.non_finalized_blocks.ancestors(node) |
357 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE9ancestorsB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE9ancestorsCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE9ancestorsB6_ |
358 | | |
359 | | /// Returns the list of children that have the given node as parent. |
360 | | /// |
361 | | /// # Panic |
362 | | /// |
363 | | /// Panics if the [`NodeIndex`] is invalid. |
364 | | /// |
365 | 0 | pub fn children(&'_ self, node: Option<NodeIndex>) -> impl Iterator<Item = NodeIndex> + '_ { |
366 | 0 | self.non_finalized_blocks.children(node) |
367 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE8childrenB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE8childrenB6_ |
368 | | |
369 | | /// Returns the [`NodeIndex`] of the current "input" best block. |
370 | | /// |
371 | | /// Returns `None` if there is no best block. In terms of logic, this means that the best block |
372 | | /// is the output finalized block, which is out of scope of this data structure. |
373 | 0 | pub fn input_best_block_index(&self) -> Option<NodeIndex> { |
374 | 0 | self.input_best_block_index |
375 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE22input_best_block_indexB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE22input_best_block_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE22input_best_block_indexB6_ |
376 | | |
377 | | /// Returns the list of all non-finalized blocks that have been inserted, both input and |
378 | | /// output. |
379 | | /// |
380 | | /// Does not include the finalized output block itself, but includes all descendants of it. |
381 | | /// |
382 | | /// Similar to [`AsyncTree::input_output_iter_unordered`], except that the returned items are |
383 | | /// guaranteed to be in an order in which the parents are found before their children. |
384 | 0 | pub fn input_output_iter_ancestry_order( |
385 | 0 | &'_ self, |
386 | 0 | ) -> impl Iterator<Item = InputIterItem<'_, TBl, TAsync>> + '_ { |
387 | 0 | self.non_finalized_blocks |
388 | 0 | .iter_ancestry_order() |
389 | 0 | .map(move |(id, b)| { |
390 | 0 | let async_op_user_data = match &b.async_op { |
391 | | AsyncOpState::Finished { |
392 | | reported: true, |
393 | 0 | user_data, |
394 | 0 | } => Some(user_data), |
395 | 0 | _ => None, |
396 | | }; |
397 | | |
398 | 0 | InputIterItem { |
399 | 0 | id, |
400 | 0 | user_data: &b.user_data, |
401 | 0 | async_op_user_data, |
402 | 0 | is_output_best: self.output_best_block_index == Some(id), |
403 | 0 | } |
404 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE32input_output_iter_ancestry_order0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE32input_output_iter_ancestry_order0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE32input_output_iter_ancestry_order0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE32input_output_iter_ancestry_order0B8_ |
405 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32input_output_iter_ancestry_orderB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE32input_output_iter_ancestry_orderCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE32input_output_iter_ancestry_orderCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32input_output_iter_ancestry_orderB6_ |
406 | | |
407 | | /// Returns the list of all non-finalized blocks that have been inserted, both input and |
408 | | /// output, in no particular order. |
409 | | /// |
410 | | /// Does not include the finalized output block itself, but includes all descendants of it. |
411 | 0 | pub fn input_output_iter_unordered( |
412 | 0 | &'_ self, |
413 | 0 | ) -> impl Iterator<Item = InputIterItem<'_, TBl, TAsync>> + '_ { |
414 | 0 | self.non_finalized_blocks |
415 | 0 | .iter_unordered() |
416 | 0 | .map(move |(id, b)| { |
417 | 0 | let async_op_user_data = match &b.async_op { |
418 | | AsyncOpState::Finished { |
419 | | reported: true, |
420 | 0 | user_data, |
421 | 0 | } => Some(user_data), |
422 | 0 | _ => None, |
423 | | }; |
424 | | |
425 | 0 | InputIterItem { |
426 | 0 | id, |
427 | 0 | user_data: &b.user_data, |
428 | 0 | async_op_user_data, |
429 | 0 | is_output_best: self.output_best_block_index == Some(id), |
430 | 0 | } |
431 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE27input_output_iter_unordered0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE27input_output_iter_unordered0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE27input_output_iter_unordered0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE27input_output_iter_unordered0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE27input_output_iter_unordered0B8_ |
432 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE27input_output_iter_unorderedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE27input_output_iter_unorderedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE27input_output_iter_unorderedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE27input_output_iter_unorderedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE27input_output_iter_unorderedB6_ |
433 | | |
434 | | /// Returns the blocks targeted by this asynchronous operation. |
435 | 0 | pub fn async_op_blocks(&self, async_op_id: AsyncOpId) -> impl Iterator<Item = &TBl> { |
436 | 0 | self.non_finalized_blocks |
437 | 0 | .iter_unordered() |
438 | 0 | .map(|(_, b)| b) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blocks0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE15async_op_blocks0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE15async_op_blocks0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE15async_op_blocks0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blocks0B8_ |
439 | 0 | .filter(move |b| { |
440 | 0 | matches!(b.async_op, AsyncOpState::InProgress { async_op_id: id, .. } if id == async_op_id) |
441 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE15async_op_blockss_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE15async_op_blockss_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE15async_op_blockss_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss_0B8_ |
442 | 0 | .map(|b| &b.user_data) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss0_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE15async_op_blockss0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE15async_op_blockss0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE15async_op_blockss0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss0_0B8_ |
443 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE15async_op_blocksB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE15async_op_blocksCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE15async_op_blocksCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE15async_op_blocksCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE15async_op_blocksB6_ |
444 | | |
445 | | /// Injects into the state of the data structure a completed operation. |
446 | | /// |
447 | | /// This "destroys" the [`AsyncOpId`]. |
448 | | /// |
449 | | /// Returns the list of blocks whose state was affected by this asynchronous operation. This |
450 | | /// can be zero blocks, or be more than one block if blocks were inserted with |
451 | | /// `same_async_op_as_parent` as `true`. |
452 | | /// |
453 | | /// # Panic |
454 | | /// |
455 | | /// Panics if the [`AsyncOpId`] is invalid. |
456 | | /// |
457 | 0 | pub fn async_op_finished(&mut self, async_op_id: AsyncOpId, user_data: TAsync) -> Vec<NodeIndex> |
458 | 0 | where |
459 | 0 | TAsync: Clone, |
460 | 0 | { |
461 | 0 | // TODO: O(n) and allocation |
462 | 0 |
|
463 | 0 | // Find the list of blocks that are bound to this operation. |
464 | 0 | let list = self |
465 | 0 | .non_finalized_blocks |
466 | 0 | .iter_unordered() |
467 | 0 | .filter(|(_, b)| { |
468 | 0 | matches!(b.async_op, |
469 | | AsyncOpState::InProgress { |
470 | 0 | async_op_id: id, .. |
471 | 0 | } if id == async_op_id) |
472 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finished0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE17async_op_finished0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE17async_op_finished0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE17async_op_finished0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finished0B8_ |
473 | 0 | .map(|(b, _)| b) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finisheds_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE17async_op_finisheds_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE17async_op_finisheds_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE17async_op_finisheds_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finisheds_0B8_ |
474 | 0 | .collect::<Vec<_>>(); |
475 | | |
476 | | // Update the blocks that were performing this operation to become `Finished`. |
477 | 0 | for index in &list { |
478 | 0 | let block = self.non_finalized_blocks.get_mut(*index).unwrap(); |
479 | 0 | match block.async_op { |
480 | | AsyncOpState::InProgress { |
481 | 0 | async_op_id: id, .. |
482 | 0 | } if id == async_op_id => { |
483 | 0 | block.async_op = AsyncOpState::Finished { |
484 | 0 | user_data: user_data.clone(), |
485 | 0 | reported: false, |
486 | 0 | }; |
487 | 0 | } |
488 | 0 | _ => {} |
489 | | } |
490 | | } |
491 | | |
492 | 0 | list |
493 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE17async_op_finishedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE17async_op_finishedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE17async_op_finishedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE17async_op_finishedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE17async_op_finishedB6_ |
494 | | |
495 | | /// Injects into the state of the state machine a failed operation. |
496 | | /// |
497 | | /// This same operation will not be repeated for the next few seconds. Thanks to this, it is |
498 | | /// possible to immediately call this function in response to a new necessary operation |
499 | | /// without worrying about loops. |
500 | | /// |
501 | | /// This "destroys" the [`AsyncOpId`]. |
502 | | /// |
503 | | /// # Panic |
504 | | /// |
505 | | /// Panics if the [`AsyncOpId`] is invalid. |
506 | | /// |
507 | 0 | pub fn async_op_failure(&mut self, async_op_id: AsyncOpId, now: &TNow) { |
508 | 0 | let new_timeout = now.clone() + self.retry_after_failed; |
509 | | |
510 | | // Update the blocks that were performing this operation. |
511 | | // The blocks are iterated from child to parent, so that we can check, for each node, |
512 | | // whether its parent has the same asynchronous operation id. |
513 | | // TODO: O(n) and allocation |
514 | 0 | for index in self |
515 | 0 | .non_finalized_blocks |
516 | 0 | .iter_ancestry_order() |
517 | 0 | .map(|(index, _)| index) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failure0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE16async_op_failure0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE16async_op_failure0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE16async_op_failure0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failure0B8_ |
518 | 0 | .collect::<Vec<_>>() |
519 | 0 | .into_iter() |
520 | 0 | .rev() |
521 | 0 | { |
522 | 0 | let new_timeout = match self.non_finalized_blocks.get_mut(index).unwrap().async_op { |
523 | | AsyncOpState::InProgress { |
524 | 0 | async_op_id: id, |
525 | 0 | timeout: Some(ref timeout), |
526 | 0 | } if id == async_op_id => Some(cmp::min(timeout.clone(), new_timeout.clone())), |
527 | | AsyncOpState::InProgress { |
528 | 0 | async_op_id: id, |
529 | | timeout: None, |
530 | 0 | } if id == async_op_id => Some(new_timeout.clone()), |
531 | 0 | _ => continue, |
532 | | }; |
533 | | |
534 | 0 | let same_as_parent = self |
535 | 0 | .non_finalized_blocks |
536 | 0 | .parent(index) |
537 | 0 | .map_or(false, |idx| { |
538 | 0 | match self.non_finalized_blocks.get(idx).unwrap().async_op { |
539 | | AsyncOpState::InProgress { |
540 | 0 | async_op_id: id, .. |
541 | 0 | } => id == async_op_id, |
542 | 0 | _ => false, |
543 | | } |
544 | 0 | }); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failures_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE16async_op_failures_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE16async_op_failures_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE16async_op_failures_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failures_0B8_ |
545 | 0 |
|
546 | 0 | self.non_finalized_blocks.get_mut(index).unwrap().async_op = AsyncOpState::Pending { |
547 | 0 | same_as_parent, |
548 | 0 | timeout: new_timeout, |
549 | 0 | }; |
550 | | } |
551 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE16async_op_failureB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE16async_op_failureCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE16async_op_failureCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE16async_op_failureCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE16async_op_failureB6_ |
552 | | |
553 | | /// Examines the state of `self` and, if a block's asynchronous operation should be started, |
554 | | /// changes the state of the block to "in progress" and returns the parameters of the |
555 | | /// operation. |
556 | | /// |
557 | | /// The order in which operations are started is: |
558 | | /// |
559 | | /// - The input finalized block. |
560 | | /// - The input best block. |
561 | | /// - Any other block. |
562 | | /// |
563 | 0 | pub fn next_necessary_async_op(&mut self, now: &TNow) -> NextNecessaryAsyncOp<TNow> { |
564 | 0 | let mut when_not_ready = None; |
565 | | |
566 | | // Finalized block according to the blocks input. |
567 | 0 | if let Some(idx) = self.input_finalized_index { |
568 | 0 | match self.start_necessary_async_op(idx, now) { |
569 | 0 | NextNecessaryAsyncOpInternal::Ready(async_op_id, block_index) => { |
570 | 0 | return NextNecessaryAsyncOp::Ready(AsyncOpParams { |
571 | 0 | id: async_op_id, |
572 | 0 | block_index, |
573 | 0 | }) |
574 | | } |
575 | 0 | NextNecessaryAsyncOpInternal::NotReady { when } => { |
576 | 0 | when_not_ready = match (when, when_not_ready.take()) { |
577 | 0 | (None, None) => None, |
578 | 0 | (Some(a), None) => Some(a), |
579 | 0 | (None, Some(b)) => Some(b), |
580 | 0 | (Some(a), Some(b)) => Some(cmp::min(a, b)), |
581 | | }; |
582 | | } |
583 | | } |
584 | 0 | } |
585 | | |
586 | | // Best block according to the blocks input. |
587 | 0 | if let Some((idx, _)) = self |
588 | 0 | .non_finalized_blocks |
589 | 0 | .iter_unordered() |
590 | 0 | .max_by_key(|(_, b)| b.input_best_block_weight) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23next_necessary_async_op0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE23next_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE23next_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE23next_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23next_necessary_async_op0B8_ |
591 | | { |
592 | 0 | match self.start_necessary_async_op(idx, now) { |
593 | 0 | NextNecessaryAsyncOpInternal::Ready(async_op_id, block_index) => { |
594 | 0 | return NextNecessaryAsyncOp::Ready(AsyncOpParams { |
595 | 0 | id: async_op_id, |
596 | 0 | block_index, |
597 | 0 | }) |
598 | | } |
599 | 0 | NextNecessaryAsyncOpInternal::NotReady { when } => { |
600 | 0 | when_not_ready = match (when, when_not_ready.take()) { |
601 | 0 | (None, None) => None, |
602 | 0 | (Some(a), None) => Some(a), |
603 | 0 | (None, Some(b)) => Some(b), |
604 | 0 | (Some(a), Some(b)) => Some(cmp::min(a, b)), |
605 | | }; |
606 | | } |
607 | | } |
608 | 0 | } |
609 | | |
610 | | // Other blocks. |
611 | 0 | for idx in self |
612 | 0 | .non_finalized_blocks |
613 | 0 | .iter_unordered() |
614 | 0 | .map(|(idx, _)| idx) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23next_necessary_async_ops_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE23next_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE23next_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE23next_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23next_necessary_async_ops_0B8_ |
615 | 0 | .collect::<Vec<_>>() |
616 | | { |
617 | 0 | match self.start_necessary_async_op(idx, now) { |
618 | 0 | NextNecessaryAsyncOpInternal::Ready(async_op_id, block_index) => { |
619 | 0 | return NextNecessaryAsyncOp::Ready(AsyncOpParams { |
620 | 0 | id: async_op_id, |
621 | 0 | block_index, |
622 | 0 | }) |
623 | | } |
624 | 0 | NextNecessaryAsyncOpInternal::NotReady { when } => { |
625 | 0 | when_not_ready = match (when, when_not_ready.take()) { |
626 | 0 | (None, None) => None, |
627 | 0 | (Some(a), None) => Some(a), |
628 | 0 | (None, Some(b)) => Some(b), |
629 | 0 | (Some(a), Some(b)) => Some(cmp::min(a, b)), |
630 | | }; |
631 | | } |
632 | | } |
633 | | } |
634 | | |
635 | 0 | NextNecessaryAsyncOp::NotReady { |
636 | 0 | when: when_not_ready, |
637 | 0 | } |
638 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23next_necessary_async_opB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE23next_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE23next_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE23next_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23next_necessary_async_opB6_ |
639 | | |
640 | | /// Starts the operation of the block with the given index, if necessary. |
641 | 0 | fn start_necessary_async_op( |
642 | 0 | &mut self, |
643 | 0 | block_index: NodeIndex, |
644 | 0 | now: &TNow, |
645 | 0 | ) -> NextNecessaryAsyncOpInternal<TNow> { |
646 | 0 | match self |
647 | 0 | .non_finalized_blocks |
648 | 0 | .get_mut(block_index) |
649 | 0 | .unwrap() |
650 | | .async_op |
651 | | { |
652 | | AsyncOpState::Pending { |
653 | | same_as_parent: false, |
654 | 0 | ref timeout, |
655 | 0 | .. |
656 | 0 | } if timeout.as_ref().map_or(true, |t| t <= now) => {} Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_op0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE24start_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_op0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_op0B8_ |
657 | | AsyncOpState::Pending { |
658 | | same_as_parent: false, |
659 | 0 | ref timeout, |
660 | 0 | .. |
661 | 0 | } => { |
662 | 0 | return NextNecessaryAsyncOpInternal::NotReady { |
663 | 0 | when: timeout.clone(), |
664 | 0 | } |
665 | | } |
666 | 0 | _ => return NextNecessaryAsyncOpInternal::NotReady { when: None }, |
667 | | }; |
668 | | |
669 | | // A new asynchronous operation can be started. |
670 | 0 | let async_op_id = self.next_async_op_id; |
671 | 0 | self.next_async_op_id.0 += 1; |
672 | 0 |
|
673 | 0 | // Gather `block_index` and all its descendants in `to_update`, provided the chain between |
674 | 0 | // `block_index` and the node only contains `Pending { same_as_parent: true }`. |
675 | 0 | // TODO: allocation and O(n) :-/ |
676 | 0 | let mut to_update = Vec::new(); |
677 | 0 | for (child_index, _) in self.non_finalized_blocks.iter_unordered() { |
678 | 0 | if !self |
679 | 0 | .non_finalized_blocks |
680 | 0 | .is_ancestor(block_index, child_index) |
681 | | { |
682 | 0 | continue; |
683 | 0 | } |
684 | 0 |
|
685 | 0 | if !self |
686 | 0 | .non_finalized_blocks |
687 | 0 | .node_to_root_path(child_index) |
688 | 0 | .take_while(|idx| *idx != block_index) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE24start_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops_0B8_ |
689 | 0 | .all(|idx| { |
690 | 0 | matches!( |
691 | 0 | self.non_finalized_blocks.get(idx).unwrap().async_op, |
692 | | AsyncOpState::Pending { |
693 | | same_as_parent: true, |
694 | | .. |
695 | | } |
696 | | ) |
697 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops0_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE24start_necessary_async_ops0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops0_0B8_ |
698 | | { |
699 | 0 | continue; |
700 | 0 | } |
701 | 0 |
|
702 | 0 | to_update.push(child_index); |
703 | | } |
704 | | |
705 | 0 | debug_assert!(to_update.iter().any(|idx| *idx == block_index)); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops1_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE24start_necessary_async_ops1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops1_0B8_ |
706 | 0 | for to_update in to_update { |
707 | 0 | self.non_finalized_blocks |
708 | 0 | .get_mut(to_update) |
709 | 0 | .unwrap() |
710 | 0 | .async_op = AsyncOpState::InProgress { |
711 | 0 | async_op_id, |
712 | 0 | timeout: None, |
713 | 0 | }; |
714 | 0 | } |
715 | | |
716 | 0 | NextNecessaryAsyncOpInternal::Ready(async_op_id, block_index) |
717 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE24start_necessary_async_opB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE24start_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE24start_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE24start_necessary_async_opCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE24start_necessary_async_opB6_ |
718 | | |
719 | | /// Inserts a new block in the state machine. |
720 | | /// |
721 | | /// If `same_async_op_as_parent` is `true`, then the asynchronous operation user data is |
722 | | /// shared with the parent of the block. This "sharing" is done by emitting only one |
723 | | /// asynchronous operation for both blocks, and/or by cloning the `TAsyncOp`. |
724 | | /// |
725 | | /// # Panic |
726 | | /// |
727 | | /// Panics if `parent_index` is an invalid node. |
728 | | /// |
729 | 0 | pub fn input_insert_block( |
730 | 0 | &mut self, |
731 | 0 | block: TBl, |
732 | 0 | parent_index: Option<NodeIndex>, |
733 | 0 | same_async_op_as_parent: bool, |
734 | 0 | is_new_best: bool, |
735 | 0 | ) -> NodeIndex { |
736 | | // When this block is inserted, value to use for `input_best_block_weight`. |
737 | 0 | let input_best_block_weight = if is_new_best { |
738 | 0 | let id = self.input_best_block_next_weight; |
739 | 0 | debug_assert!(self |
740 | 0 | .non_finalized_blocks |
741 | 0 | .iter_unordered() |
742 | 0 | .all(|(_, b)| b.input_best_block_weight < id)); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18input_insert_block0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18input_insert_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE18input_insert_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE18input_insert_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18input_insert_block0B8_ |
743 | 0 | self.input_best_block_next_weight += 1; |
744 | 0 | id |
745 | | } else { |
746 | 0 | 0 |
747 | | }; |
748 | | |
749 | 0 | let async_op = match (same_async_op_as_parent, parent_index) { |
750 | 0 | (true, Some(parent_index)) => { |
751 | 0 | match &self |
752 | 0 | .non_finalized_blocks |
753 | 0 | .get(parent_index) |
754 | 0 | .unwrap() |
755 | 0 | .async_op |
756 | | { |
757 | 0 | AsyncOpState::InProgress { async_op_id, .. } => AsyncOpState::InProgress { |
758 | 0 | async_op_id: *async_op_id, |
759 | 0 | timeout: None, |
760 | 0 | }, |
761 | 0 | AsyncOpState::Finished { user_data, .. } => AsyncOpState::Finished { |
762 | 0 | user_data: user_data.clone(), |
763 | 0 | reported: false, |
764 | 0 | }, |
765 | 0 | AsyncOpState::Pending { .. } => AsyncOpState::Pending { |
766 | 0 | same_as_parent: true, |
767 | 0 | timeout: None, |
768 | 0 | }, |
769 | | } |
770 | | } |
771 | 0 | (true, None) => AsyncOpState::Finished { |
772 | 0 | user_data: self.output_finalized_async_user_data.clone(), |
773 | 0 | reported: false, |
774 | 0 | }, |
775 | 0 | (false, _) => AsyncOpState::Pending { |
776 | 0 | same_as_parent: false, |
777 | 0 | timeout: None, |
778 | 0 | }, |
779 | | }; |
780 | | |
781 | | // Insert the new block. |
782 | 0 | let new_index = self.non_finalized_blocks.insert( |
783 | 0 | parent_index, |
784 | 0 | Block { |
785 | 0 | user_data: block, |
786 | 0 | async_op, |
787 | 0 | input_best_block_weight, |
788 | 0 | }, |
789 | 0 | ); |
790 | 0 |
|
791 | 0 | self.input_best_block_index = Some(new_index); |
792 | 0 |
|
793 | 0 | new_index |
794 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18input_insert_blockB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18input_insert_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE18input_insert_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE18input_insert_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18input_insert_blockB6_ |
795 | | |
796 | | /// Updates the state machine to take into account that the best block of the input has been |
797 | | /// modified. |
798 | | /// |
799 | | /// Pass `None` if the input best block is now the same as the output finalized block. |
800 | | /// |
801 | | /// # Panic |
802 | | /// |
803 | | /// Panics if `new_best_block` isn't a valid node. |
804 | | /// Panics if `new_best_block` isn't equal or a descendant of the input finalized block. |
805 | | /// |
806 | 0 | pub fn input_set_best_block(&mut self, new_best_block: Option<NodeIndex>) { |
807 | 0 | // Make sure that `new_best_block` is a descendant of the current input finalized block, |
808 | 0 | // otherwise the state of the tree will be corrupted. |
809 | 0 | // This is checked with an `assert!` rather than a `debug_assert!`, as this constraint |
810 | 0 | // is part of the public API of this method. |
811 | 0 | assert!(match (self.input_finalized_index, new_best_block) { |
812 | 0 | (Some(f), Some(b)) => self.non_finalized_blocks.is_ancestor(f, b), |
813 | 0 | (Some(_), None) => false, |
814 | 0 | (None, Some(b)) => { |
815 | 0 | assert!(self.non_finalized_blocks.contains(b)); |
816 | 0 | true |
817 | | } |
818 | 0 | (None, None) => true, |
819 | | }); |
820 | | |
821 | 0 | self.input_best_block_index = new_best_block; |
822 | 0 |
|
823 | 0 | // If necessary, update the weight of the block. |
824 | 0 | match new_best_block |
825 | 0 | .map(|new_best_block| { |
826 | 0 | &mut self |
827 | 0 | .non_finalized_blocks |
828 | 0 | .get_mut(new_best_block) |
829 | 0 | .unwrap() |
830 | 0 | .input_best_block_weight |
831 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_block0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE20input_set_best_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE20input_set_best_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE20input_set_best_block0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_block0B8_ |
832 | 0 | .unwrap_or(&mut self.output_finalized_block_weight) |
833 | | { |
834 | 0 | w if *w == self.input_best_block_next_weight - 1 => {} |
835 | 0 | w => { |
836 | 0 | *w = self.input_best_block_next_weight; |
837 | 0 | self.input_best_block_next_weight += 1; |
838 | 0 | } |
839 | | } |
840 | | |
841 | | // Minor sanity checks. |
842 | 0 | debug_assert!(self |
843 | 0 | .non_finalized_blocks |
844 | 0 | .iter_unordered() |
845 | 0 | .all(|(_, b)| b.input_best_block_weight < self.input_best_block_next_weight)); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_blocks_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE20input_set_best_blocks_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE20input_set_best_blocks_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE20input_set_best_blocks_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_blocks_0B8_ |
846 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE20input_set_best_blockB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE20input_set_best_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE20input_set_best_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE20input_set_best_blockCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE20input_set_best_blockB6_ |
847 | | |
848 | | /// Updates the state machine to take into account that the input of blocks has finalized the |
849 | | /// given block. |
850 | | /// |
851 | | /// `new_best_block` is the best block after the finalization. |
852 | | /// |
853 | | /// > **Note**: Finalizing a block might have to modify the current best block if the block |
854 | | /// > being finalized isn't an ancestor of the current best block. |
855 | | /// |
856 | | /// # Panic |
857 | | /// |
858 | | /// Panics if `node_to_finalize` isn't a valid node. |
859 | | /// Panics if the current input best block is not a descendant of `node_to_finalize`. |
860 | | /// |
861 | 0 | pub fn input_finalize(&mut self, node_to_finalize: NodeIndex) { |
862 | 0 | // Make sure that `new_best_block` is a descendant of `node_to_finalize`, |
863 | 0 | // otherwise the state of the tree will be corrupted. |
864 | 0 | // This is checked with an `assert!` rather than a `debug_assert!`, as this constraint |
865 | 0 | // is part of the public API of this method. |
866 | 0 | assert!(self |
867 | 0 | .input_best_block_index |
868 | 0 | .map_or(false, |current_input_best| self |
869 | 0 | .non_finalized_blocks |
870 | 0 | .is_ancestor(node_to_finalize, current_input_best))); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE14input_finalize0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE14input_finalize0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE14input_finalize0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE14input_finalize0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE14input_finalize0B8_ |
871 | | |
872 | 0 | self.input_finalized_index = Some(node_to_finalize); |
873 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE14input_finalizeB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE14input_finalizeCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE14input_finalizeCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE14input_finalizeCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE14input_finalizeB6_ |
874 | | |
875 | | /// Tries to update the output blocks to follow the input. |
876 | | /// |
877 | | /// Should be called after inserting a new block, finalizing a block, or when an asynchronous |
878 | | /// operation is finished. |
879 | | /// |
880 | | /// Returns `None` if the state machine doesn't have any update. This method should be called |
881 | | /// repeatedly until it returns `None`. Each call can perform an additional update. |
882 | | // TODO: should cache the information about whether an update is ready, so that calling this method becomes cheap |
883 | 0 | pub fn try_advance_output(&mut self) -> Option<OutputUpdate<TBl, TAsync>> { |
884 | | // Try to advance the output finalized block. |
885 | | // `input_finalized_index` is `Some` if the input finalized is not already equal to the |
886 | | // output finalized. |
887 | 0 | if let Some(input_finalized_index) = self.input_finalized_index { |
888 | | // Finding a new finalized block. |
889 | | // We always take the first node on the path towards `input_finalized_index`, in |
890 | | // order to finalized blocks one by one. |
891 | 0 | let new_finalized = { |
892 | 0 | self.non_finalized_blocks |
893 | 0 | .root_to_node_path(input_finalized_index) |
894 | 0 | .take(1) |
895 | 0 | .find(|node_index| { |
896 | 0 | matches!( |
897 | 0 | self.non_finalized_blocks.get(*node_index).unwrap().async_op, |
898 | | AsyncOpState::Finished { reported: true, .. } |
899 | | ) |
900 | 0 | }) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_output0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18try_advance_output0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_output0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_output0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_output0B8_ |
901 | | }; |
902 | | |
903 | 0 | if let Some(new_finalized) = new_finalized { |
904 | | // Update `input_finalized_index` and `input_best_block_index`. |
905 | 0 | if self.input_finalized_index == Some(new_finalized) { |
906 | 0 | self.input_finalized_index = None; |
907 | 0 | } |
908 | 0 | if self.input_best_block_index == Some(new_finalized) { |
909 | 0 | self.input_best_block_index = None; |
910 | 0 | } |
911 | | |
912 | 0 | let mut pruned_blocks = Vec::new(); |
913 | 0 | let mut pruned_finalized = None; |
914 | 0 | let mut best_output_block_updated = false; |
915 | | |
916 | 0 | for pruned in self.non_finalized_blocks.prune_ancestors(new_finalized) { |
917 | 0 | debug_assert_ne!(Some(pruned.index), self.input_finalized_index); |
918 | | |
919 | | // If the best block would be pruned, reset it to the finalized block. The |
920 | | // best block is updated later down this function. |
921 | 0 | if self |
922 | 0 | .output_best_block_index |
923 | 0 | .map_or(false, |b| b == pruned.index) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18try_advance_outputs_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_outputs_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_outputs_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs_0B8_ |
924 | 0 | { |
925 | 0 | self.output_best_block_index = None; |
926 | 0 | best_output_block_updated = true; |
927 | 0 | } |
928 | | |
929 | | // Update `self.finalized_block_weight`. |
930 | 0 | if pruned.index == new_finalized { |
931 | 0 | self.output_finalized_block_weight = |
932 | 0 | pruned.user_data.input_best_block_weight; |
933 | 0 | pruned_finalized = Some(pruned); |
934 | 0 | continue; |
935 | 0 | } |
936 | | |
937 | 0 | let async_op = match pruned.user_data.async_op { |
938 | | AsyncOpState::Finished { |
939 | 0 | user_data, |
940 | 0 | reported, |
941 | 0 | .. |
942 | 0 | } => { |
943 | 0 | // Here's a small corner case: the async operation was finished, but |
944 | 0 | // this block wasn't reported yet. |
945 | 0 | // This is actually problematic because the `TAsync` is thrown away |
946 | 0 | // silently while the public API gives the impression that all |
947 | 0 | // `TAsync`s are always returned. |
948 | 0 | // TODO: solve that |
949 | 0 | if reported { |
950 | 0 | Some(user_data) |
951 | | } else { |
952 | 0 | None |
953 | | } |
954 | | } |
955 | 0 | _ => None, |
956 | | }; |
957 | | |
958 | 0 | pruned_blocks.push((pruned.index, pruned.user_data.user_data, async_op)); |
959 | | } |
960 | | |
961 | | // Try to advance the output best block to the `Finished` block with the highest |
962 | | // weight. |
963 | | // Weight of the current output best block. |
964 | 0 | let mut current_runtime_service_best_block_weight = |
965 | 0 | match self.output_best_block_index { |
966 | 0 | None => self.output_finalized_block_weight, |
967 | 0 | Some(idx) => { |
968 | 0 | self.non_finalized_blocks |
969 | 0 | .get(idx) |
970 | 0 | .unwrap() |
971 | 0 | .input_best_block_weight |
972 | | } |
973 | | }; |
974 | | |
975 | 0 | for (node_index, block) in self.non_finalized_blocks.iter_unordered() { |
976 | | // Check uniqueness of weights. |
977 | 0 | debug_assert!( |
978 | 0 | block.input_best_block_weight != current_runtime_service_best_block_weight |
979 | 0 | || block.input_best_block_weight == 0 |
980 | 0 | || self.output_best_block_index == Some(node_index) |
981 | | ); |
982 | | |
983 | 0 | if block.input_best_block_weight <= current_runtime_service_best_block_weight { |
984 | 0 | continue; |
985 | 0 | } |
986 | | |
987 | 0 | if !matches!( |
988 | 0 | block.async_op, |
989 | | AsyncOpState::Finished { reported: true, .. } |
990 | | ) { |
991 | 0 | continue; |
992 | 0 | } |
993 | 0 |
|
994 | 0 | // Input best can be updated to the block being iterated. |
995 | 0 | current_runtime_service_best_block_weight = block.input_best_block_weight; |
996 | 0 | self.output_best_block_index = Some(node_index); |
997 | 0 | best_output_block_updated = true; |
998 | | |
999 | | // Continue looping, as there might be another block with an even |
1000 | | // higher weight. |
1001 | | } |
1002 | | |
1003 | 0 | let pruned_finalized = pruned_finalized.unwrap(); |
1004 | 0 | let former_finalized_async_op_user_data = match pruned_finalized.user_data.async_op |
1005 | | { |
1006 | 0 | AsyncOpState::Finished { user_data, .. } => { |
1007 | 0 | mem::replace(&mut self.output_finalized_async_user_data, user_data) |
1008 | | } |
1009 | 0 | _ => unreachable!(), |
1010 | | }; |
1011 | | |
1012 | 0 | return Some(OutputUpdate::Finalized { |
1013 | 0 | former_index: new_finalized, |
1014 | 0 | user_data: pruned_finalized.user_data.user_data, |
1015 | 0 | former_finalized_async_op_user_data, |
1016 | 0 | pruned_blocks, |
1017 | 0 | best_output_block_updated, |
1018 | 0 | }); |
1019 | 0 | } |
1020 | 0 | } |
1021 | | |
1022 | | // Now try to report blocks that haven't been reported yet. |
1023 | | // TODO: O(n) complexity and allocations |
1024 | 0 | for node_index in self |
1025 | 0 | .non_finalized_blocks |
1026 | 0 | .iter_unordered() |
1027 | 0 | .map(|(idx, _)| idx) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs0_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18try_advance_outputs0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_outputs0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_outputs0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs0_0B8_ |
1028 | 0 | .collect::<Vec<_>>() |
1029 | | { |
1030 | | // Skip this block if its parent isn't reported yet. |
1031 | 0 | if let Some(parent) = self.non_finalized_blocks.parent(node_index) { |
1032 | 0 | if !matches!( |
1033 | 0 | self.non_finalized_blocks.get(parent).unwrap().async_op, |
1034 | | AsyncOpState::Finished { reported: true, .. } |
1035 | | ) { |
1036 | 0 | continue; |
1037 | 0 | } |
1038 | 0 | } |
1039 | | |
1040 | | // Skip this block if it's already been reported. Otherwise, mark it as reported. |
1041 | 0 | match &mut self |
1042 | 0 | .non_finalized_blocks |
1043 | 0 | .get_mut(node_index) |
1044 | 0 | .unwrap() |
1045 | | .async_op |
1046 | | { |
1047 | 0 | AsyncOpState::Finished { reported, .. } if !*reported => { |
1048 | 0 | *reported = true; |
1049 | 0 | } |
1050 | 0 | _ => continue, |
1051 | | } |
1052 | | |
1053 | | // Try to mark the best we're about to report as best block, if possible. |
1054 | 0 | let is_new_best = self |
1055 | 0 | .non_finalized_blocks |
1056 | 0 | .get(node_index) |
1057 | 0 | .unwrap() |
1058 | 0 | .input_best_block_weight |
1059 | 0 | > self |
1060 | 0 | .output_best_block_index |
1061 | 0 | .map_or(self.output_finalized_block_weight, |idx| { |
1062 | 0 | self.non_finalized_blocks |
1063 | 0 | .get(idx) |
1064 | 0 | .unwrap() |
1065 | 0 | .input_best_block_weight |
1066 | 0 | }); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs1_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18try_advance_outputs1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_outputs1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_outputs1_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs1_0B8_ |
1067 | 0 | if is_new_best { |
1068 | 0 | debug_assert_ne!(self.output_best_block_index, Some(node_index)); |
1069 | 0 | self.output_best_block_index = Some(node_index); |
1070 | 0 | } |
1071 | | |
1072 | | // Report the new block. |
1073 | 0 | return Some(OutputUpdate::Block(OutputUpdateBlock { |
1074 | 0 | index: node_index, |
1075 | 0 | is_new_best, |
1076 | 0 | })); |
1077 | | } |
1078 | | |
1079 | | // Try to advance the output best block. |
1080 | | { |
1081 | 0 | let mut best_block_updated = false; |
1082 | | |
1083 | | // Try to advance the output best block to the `Finished` block with the highest |
1084 | | // weight. |
1085 | | // Weight of the current output best block. |
1086 | 0 | let mut current_runtime_service_best_block_weight = match self.output_best_block_index { |
1087 | 0 | None => self.output_finalized_block_weight, |
1088 | 0 | Some(idx) => { |
1089 | 0 | self.non_finalized_blocks |
1090 | 0 | .get(idx) |
1091 | 0 | .unwrap() |
1092 | 0 | .input_best_block_weight |
1093 | | } |
1094 | | }; |
1095 | | |
1096 | 0 | for (node_index, block) in self.non_finalized_blocks.iter_unordered() { |
1097 | | // Check uniqueness of weights. |
1098 | 0 | debug_assert!( |
1099 | 0 | block.input_best_block_weight != current_runtime_service_best_block_weight |
1100 | 0 | || block.input_best_block_weight == 0 |
1101 | 0 | || self.output_best_block_index == Some(node_index) |
1102 | | ); |
1103 | | |
1104 | 0 | if block.input_best_block_weight <= current_runtime_service_best_block_weight { |
1105 | 0 | continue; |
1106 | 0 | } |
1107 | | |
1108 | 0 | if !matches!( |
1109 | 0 | block.async_op, |
1110 | | AsyncOpState::Finished { reported: true, .. } |
1111 | | ) { |
1112 | 0 | continue; |
1113 | 0 | } |
1114 | 0 |
|
1115 | 0 | // Input best can be updated to the block being iterated. |
1116 | 0 | current_runtime_service_best_block_weight = block.input_best_block_weight; |
1117 | 0 | self.output_best_block_index = Some(node_index); |
1118 | 0 | best_block_updated = true; |
1119 | | |
1120 | | // Continue looping, as there might be another block with an even |
1121 | | // higher weight. |
1122 | | } |
1123 | | |
1124 | 0 | if best_block_updated { |
1125 | 0 | return Some(OutputUpdate::BestBlockChanged { |
1126 | 0 | best_block_index: self.output_best_block_index, |
1127 | 0 | }); |
1128 | 0 | } |
1129 | 0 | } |
1130 | 0 |
|
1131 | 0 | // Nothing to do. |
1132 | 0 | None |
1133 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18try_advance_outputB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEE18try_advance_outputCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEEE18try_advance_outputCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1D_7RuntimeEE18try_advance_outputCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18try_advance_outputB6_ |
1134 | | } |
1135 | | |
1136 | | impl<TNow, TBl, TAsync> ops::Index<NodeIndex> for AsyncTree<TNow, TBl, TAsync> { |
1137 | | type Output = TBl; |
1138 | | |
1139 | 0 | fn index(&self, node_index: NodeIndex) -> &Self::Output { |
1140 | 0 | &self.non_finalized_blocks.get(node_index).unwrap().user_data |
1141 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot5chain10async_trees_0pppEINtB5_9AsyncTreepppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtNtB7_9fork_tree9NodeIndexE5indexB9_ Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc3vec3VechEEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXs_NtNtCseuYC0Zibziv_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCsaYZPK01V26L_4core4time8DurationNtNtCsih6EgvAwZF2_13smoldot_light15runtime_service5BlockINtNtCsdZExvAaxgia_5alloc4sync3ArcNtB1F_7RuntimeEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot5chain10async_trees_0pppEINtB5_9AsyncTreepppEINtNtNtCsaYZPK01V26L_4core3ops5index5IndexNtNtB7_9fork_tree9NodeIndexE5indexB9_ |
1142 | | } |
1143 | | |
1144 | | impl<TNow, TBl, TAsync> ops::IndexMut<NodeIndex> for AsyncTree<TNow, TBl, TAsync> { |
1145 | 0 | fn index_mut(&mut self, node_index: NodeIndex) -> &mut Self::Output { |
1146 | 0 | &mut self |
1147 | 0 | .non_finalized_blocks |
1148 | 0 | .get_mut(node_index) |
1149 | 0 | .unwrap() |
1150 | 0 | .user_data |
1151 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot5chain10async_trees0_0pppEINtB5_9AsyncTreepppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtNtB7_9fork_tree9NodeIndexE9index_mutB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot5chain10async_trees0_0pppEINtB5_9AsyncTreepppEINtNtNtCsaYZPK01V26L_4core3ops5index8IndexMutNtNtB7_9fork_tree9NodeIndexE9index_mutB9_ |
1152 | | } |
1153 | | |
1154 | | /// See [`AsyncTree::input_output_iter_unordered`] and |
1155 | | /// [`AsyncTree::input_output_iter_ancestry_order`]. |
1156 | | #[derive(Debug, Clone, PartialEq, Eq)] |
1157 | | pub struct InputIterItem<'a, TBl, TAsync> { |
1158 | | /// Index of the block. |
1159 | | pub id: NodeIndex, |
1160 | | |
1161 | | /// User data associated to this block that was passed to [`AsyncTree::input_insert_block`]. |
1162 | | pub user_data: &'a TBl, |
1163 | | |
1164 | | /// User data of the asynchronous operation of this block. |
1165 | | /// |
1166 | | /// `Some` if and only if the block has been reported in a [`OutputUpdate`] before. |
1167 | | pub async_op_user_data: Option<&'a TAsync>, |
1168 | | |
1169 | | /// Whether this block is considered as the best block of the output. |
1170 | | /// |
1171 | | /// Either 0 or 1 blocks will have the "is output best" boolean set to true. If no blocks have |
1172 | | /// this boolean set, then the best block is the finalized block. |
1173 | | pub is_output_best: bool, |
1174 | | } |
1175 | | |
1176 | | /// See [`AsyncTree::try_advance_output`]. |
1177 | | #[derive(Debug, Clone, PartialEq, Eq)] |
1178 | | pub enum OutputUpdate<TBl, TAsync> { |
1179 | | /// A non-finalized block has been finalized in the output. |
1180 | | /// |
1181 | | /// This block is no longer part of the data structure. |
1182 | | /// |
1183 | | /// Blocks are guaranteed to be finalized one after the other, without any gap. |
1184 | | Finalized { |
1185 | | /// Index of the node within the data structure. This index is no longer valid and is |
1186 | | /// here for reference. |
1187 | | former_index: NodeIndex, |
1188 | | |
1189 | | /// User data associated to this block. |
1190 | | user_data: TBl, |
1191 | | |
1192 | | /// User data associated to the `async` operation of the previous finalized block. |
1193 | | former_finalized_async_op_user_data: TAsync, |
1194 | | |
1195 | | /// `true` if the finalization has updated the best output block. |
1196 | | best_output_block_updated: bool, |
1197 | | |
1198 | | /// Blocks that were a descendant of the former finalized block but not of the new |
1199 | | /// finalized block. These blocks are no longer part of the data structure. |
1200 | | /// |
1201 | | /// If the `Option<TAsync>` is `Some`, then that block was part of the output. Otherwise |
1202 | | /// it wasn't. |
1203 | | pruned_blocks: Vec<(NodeIndex, TBl, Option<TAsync>)>, |
1204 | | }, |
1205 | | |
1206 | | /// A new block has been added to the list of output unfinalized blocks. |
1207 | | Block(OutputUpdateBlock), |
1208 | | |
1209 | | /// The output best block has been modified. |
1210 | | BestBlockChanged { |
1211 | | /// Index of the best block after the finalization. `None` if the best block is the |
1212 | | /// output finalized block. |
1213 | | best_block_index: Option<NodeIndex>, |
1214 | | }, |
1215 | | } |
1216 | | |
1217 | | /// See [`OutputUpdate`]. |
1218 | | #[derive(Debug, Clone, PartialEq, Eq)] |
1219 | | pub struct OutputUpdateBlock { |
1220 | | /// Index of the node within the data structure. |
1221 | | pub index: NodeIndex, |
1222 | | |
1223 | | /// True if this block is considered as the best block of the chain. |
1224 | | pub is_new_best: bool, |
1225 | | } |
1226 | | |
1227 | | struct Block<TNow, TBl, TAsync> { |
1228 | | /// User data associated with that block. |
1229 | | user_data: TBl, |
1230 | | |
1231 | | /// Operation information of that block. Shared amongst multiple different blocks. |
1232 | | async_op: AsyncOpState<TNow, TAsync>, |
1233 | | |
1234 | | /// A block with a higher value here has been reported by the input as the best block |
1235 | | /// more recently than a block with a lower value. `0` means never reported as best block. |
1236 | | input_best_block_weight: u32, |
1237 | | } |
1238 | | |
1239 | | enum AsyncOpState<TNow, TAsync> { |
1240 | | /// Operation has finished and was successful. |
1241 | | Finished { |
1242 | | /// User data chose by the user. |
1243 | | user_data: TAsync, |
1244 | | |
1245 | | /// `true` if this block has already been reported in the output. |
1246 | | reported: bool, |
1247 | | }, |
1248 | | |
1249 | | /// Operation is currently in progress. |
1250 | | InProgress { |
1251 | | /// Identifier for this operation in the public API. |
1252 | | /// Attributed from [`AsyncTree::next_async_op_id`]. Multiple different blocks can |
1253 | | /// point to the same `async_op_id` when it is known that they point to the same operation. |
1254 | | async_op_id: AsyncOpId, |
1255 | | |
1256 | | /// Do not start any operation before `TNow`. Used to avoid repeatedly trying to perform |
1257 | | /// the operation on the same block over and over again when it's constantly failing. |
1258 | | timeout: Option<TNow>, |
1259 | | }, |
1260 | | |
1261 | | /// Operation hasn't started. |
1262 | | Pending { |
1263 | | /// `true` if this operation should be the same as its parent's. |
1264 | | /// If `true`, it is illegal for the parent to be in the state |
1265 | | /// [`AsyncOpState::Finished`] or [`AsyncOpState::InProgress`]. |
1266 | | /// |
1267 | | /// When in doubt, `false`. |
1268 | | same_as_parent: bool, |
1269 | | |
1270 | | /// Do not start any operation before `TNow`. Used to avoid repeatedly trying to perform |
1271 | | /// the same operation over and over again when it's constantly failing. |
1272 | | timeout: Option<TNow>, |
1273 | | }, |
1274 | | } |
1275 | | |
1276 | | /// Equivalent to [`NextNecessaryAsyncOp`] but private and doesn't use lifetimes. Necessary in |
1277 | | /// order to bypass borrow checker issues. |
1278 | | #[derive(Debug)] |
1279 | | enum NextNecessaryAsyncOpInternal<TNow> { |
1280 | | Ready(AsyncOpId, NodeIndex), |
1281 | | NotReady { when: Option<TNow> }, |
1282 | | } |
1283 | | |
1284 | | // TODO: needs tests |