Coverage Report

Created: 2024-05-16 12:16

/__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