Coverage Report

Created: 2025-07-01 09:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/__w/smoldot/smoldot/repo/lib/src/chain/async_tree.rs
Line
Count
Source
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! 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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE3newB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE3newB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE3newCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE3newCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE3newCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE30num_input_non_finalized_blocksB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE30num_input_non_finalized_blocksB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE30num_input_non_finalized_blocksCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE30num_input_non_finalized_blocksCs7snhGEhbuap_18smoldot_light_wasm
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
        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: _RNCINvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB5_9AsyncTreepppE22map_async_op_user_datappE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB5_9AsyncTreepppE22map_async_op_user_datappE0B9_
Unexecuted instantiation: _RNCINvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB5_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB17_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1G_7RuntimeEEE22map_async_op_user_dataB2V_NCNCINvB1G_14run_backgroundNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0si_0E0B4H_
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
        }
268
0
    }
Unexecuted instantiation: _RINvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB3_9AsyncTreepppE22map_async_op_user_datappEB7_
Unexecuted instantiation: _RINvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB3_9AsyncTreepppE22map_async_op_user_datappEB7_
Unexecuted instantiation: _RINvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB3_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB15_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1E_7RuntimeEEE22map_async_op_user_dataB2T_NCNCINvB1E_14run_backgroundNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefE0si_0EB4F_
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
            (
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23output_best_block_index0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE23output_best_block_index0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE23output_best_block_index0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE23output_best_block_index0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE23output_best_block_index0Cs7snhGEhbuap_18smoldot_light_wasm
292
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23output_best_block_indexB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23output_best_block_indexB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE23output_best_block_indexCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE23output_best_block_indexCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE23output_best_block_indexCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32output_finalized_async_user_dataB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32output_finalized_async_user_dataB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE32output_finalized_async_user_dataCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE32output_finalized_async_user_dataCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE21block_async_user_dataB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE21block_async_user_dataB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE21block_async_user_dataCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE21block_async_user_dataCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE25block_async_user_data_mutB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE6parentB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE6parentB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE6parentCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE6parentCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE9ancestorsB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE9ancestorsB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE9ancestorsCs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE8childrenB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE22input_best_block_indexB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE22input_best_block_indexB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE22input_best_block_indexCs7snhGEhbuap_18smoldot_light_wasm
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE32input_output_iter_ancestry_order0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE32input_output_iter_ancestry_order0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE32input_output_iter_ancestry_order0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE32input_output_iter_ancestry_order0Cs7snhGEhbuap_18smoldot_light_wasm
405
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32input_output_iter_ancestry_orderB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE32input_output_iter_ancestry_orderB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE32input_output_iter_ancestry_orderCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE32input_output_iter_ancestry_orderCs7snhGEhbuap_18smoldot_light_wasm
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE27input_output_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE27input_output_iter_unordered0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE27input_output_iter_unordered0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE27input_output_iter_unordered0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE27input_output_iter_unordered0Cs7snhGEhbuap_18smoldot_light_wasm
432
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE27input_output_iter_unorderedB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE27input_output_iter_unorderedB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE27input_output_iter_unorderedCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE27input_output_iter_unorderedCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE27input_output_iter_unorderedCs7snhGEhbuap_18smoldot_light_wasm
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)
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE15async_op_blockss_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE15async_op_blockss_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE15async_op_blockss_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE15async_op_blockss_0Cs7snhGEhbuap_18smoldot_light_wasm
442
0
            .map(|b| &b.user_data)
443
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE15async_op_blocksB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE15async_op_blocksB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE15async_op_blocksCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE15async_op_blocksCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE15async_op_blocksCs7snhGEhbuap_18smoldot_light_wasm
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
    {
461
        // TODO: O(n) and allocation
462
463
        // 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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finished0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE17async_op_finished0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE17async_op_finished0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE17async_op_finished0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE17async_op_finished0Cs7snhGEhbuap_18smoldot_light_wasm
473
0
            .map(|(b, _)| b)
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE17async_op_finishedB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE17async_op_finishedB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE17async_op_finishedCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE17async_op_finishedCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE17async_op_finishedCs7snhGEhbuap_18smoldot_light_wasm
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)
518
0
            .collect::<Vec<_>>()
519
0
            .into_iter()
520
0
            .rev()
521
        {
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failures_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE16async_op_failures_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE16async_op_failures_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE16async_op_failures_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE16async_op_failures_0Cs7snhGEhbuap_18smoldot_light_wasm
545
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE16async_op_failureB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE16async_op_failureB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE16async_op_failureCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE16async_op_failureCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE16async_op_failureCs7snhGEhbuap_18smoldot_light_wasm
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)
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)
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23next_necessary_async_opB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE23next_necessary_async_opB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE23next_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE23next_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE23next_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
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
                ..
656
0
            } if timeout.as_ref().map_or(true, |t| t <= now) => {}
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_op0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_op0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE24start_necessary_async_op0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_op0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_op0Cs7snhGEhbuap_18smoldot_light_wasm
657
            AsyncOpState::Pending {
658
                same_as_parent: false,
659
0
                ref timeout,
660
                ..
661
            } => {
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
673
        // Gather `block_index` and all its descendants in `to_update`, provided the chain between
674
        // `block_index` and the node only contains `Pending { same_as_parent: true }`.
675
        // 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
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE24start_necessary_async_ops_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops_0Cs7snhGEhbuap_18smoldot_light_wasm
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: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops0_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE24start_necessary_async_ops0_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops0_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops0_0Cs7snhGEhbuap_18smoldot_light_wasm
698
            {
699
0
                continue;
700
0
            }
701
702
0
            to_update.push(child_index);
703
        }
704
705
0
        debug_assert!(to_update.iter().any(|idx| *idx == block_index));
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE24start_necessary_async_ops1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE24start_necessary_async_ops1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE24start_necessary_async_ops1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE24start_necessary_async_ops1_0Cs7snhGEhbuap_18smoldot_light_wasm
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: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE24start_necessary_async_opB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE24start_necessary_async_opB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE24start_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE24start_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE24start_necessary_async_opCs7snhGEhbuap_18smoldot_light_wasm
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!(
740
0
                self.non_finalized_blocks
741
0
                    .iter_unordered()
742
0
                    .all(|(_, b)| b.input_best_block_weight < id)
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18input_insert_block0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18input_insert_block0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18input_insert_block0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE18input_insert_block0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE18input_insert_block0Cs7snhGEhbuap_18smoldot_light_wasm
743
            );
744
0
            self.input_best_block_next_weight += 1;
745
0
            id
746
        } else {
747
0
            0
748
        };
749
750
0
        let async_op = match (same_async_op_as_parent, parent_index) {
751
0
            (true, Some(parent_index)) => {
752
0
                match &self
753
0
                    .non_finalized_blocks
754
0
                    .get(parent_index)
755
0
                    .unwrap()
756
0
                    .async_op
757
                {
758
0
                    AsyncOpState::InProgress { async_op_id, .. } => AsyncOpState::InProgress {
759
0
                        async_op_id: *async_op_id,
760
0
                        timeout: None,
761
0
                    },
762
0
                    AsyncOpState::Finished { user_data, .. } => AsyncOpState::Finished {
763
0
                        user_data: user_data.clone(),
764
0
                        reported: false,
765
0
                    },
766
0
                    AsyncOpState::Pending { .. } => AsyncOpState::Pending {
767
0
                        same_as_parent: true,
768
0
                        timeout: None,
769
0
                    },
770
                }
771
            }
772
0
            (true, None) => AsyncOpState::Finished {
773
0
                user_data: self.output_finalized_async_user_data.clone(),
774
0
                reported: false,
775
0
            },
776
0
            (false, _) => AsyncOpState::Pending {
777
0
                same_as_parent: false,
778
0
                timeout: None,
779
0
            },
780
        };
781
782
        // Insert the new block.
783
0
        let new_index = self.non_finalized_blocks.insert(
784
0
            parent_index,
785
0
            Block {
786
0
                user_data: block,
787
0
                async_op,
788
0
                input_best_block_weight,
789
0
            },
790
        );
791
792
0
        if is_new_best {
793
0
            self.input_best_block_index = Some(new_index);
794
0
        }
795
796
0
        new_index
797
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18input_insert_blockB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18input_insert_blockB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18input_insert_blockCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE18input_insert_blockCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE18input_insert_blockCs7snhGEhbuap_18smoldot_light_wasm
798
799
    /// Updates the state machine to take into account that the best block of the input has been
800
    /// modified.
801
    ///
802
    /// Pass `None` if the input best block is now the same as the output finalized block.
803
    ///
804
    /// # Panic
805
    ///
806
    /// Panics if `new_best_block` isn't a valid node.
807
    /// Panics if `new_best_block` isn't equal or a descendant of the input finalized block.
808
    ///
809
0
    pub fn input_set_best_block(&mut self, new_best_block: Option<NodeIndex>) {
810
        // Make sure that `new_best_block` is a descendant of the current input finalized block,
811
        // otherwise the state of the tree will be corrupted.
812
        // This is checked with an `assert!` rather than a `debug_assert!`, as this constraint
813
        // is part of the public API of this method.
814
0
        assert!(match (self.input_finalized_index, new_best_block) {
815
0
            (Some(f), Some(b)) => self.non_finalized_blocks.is_ancestor(f, b),
816
0
            (Some(_), None) => false,
817
0
            (None, Some(b)) => {
818
0
                assert!(self.non_finalized_blocks.contains(b));
819
0
                true
820
            }
821
0
            (None, None) => true,
822
        });
823
824
0
        self.input_best_block_index = new_best_block;
825
826
        // If necessary, update the weight of the block.
827
0
        match new_best_block
828
0
            .map(|new_best_block| {
829
0
                &mut self
830
0
                    .non_finalized_blocks
831
0
                    .get_mut(new_best_block)
832
0
                    .unwrap()
833
0
                    .input_best_block_weight
834
0
            })
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_block0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_block0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE20input_set_best_block0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE20input_set_best_block0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE20input_set_best_block0Cs7snhGEhbuap_18smoldot_light_wasm
835
0
            .unwrap_or(&mut self.output_finalized_block_weight)
836
        {
837
0
            w if *w == self.input_best_block_next_weight - 1 => {}
838
0
            w => {
839
0
                *w = self.input_best_block_next_weight;
840
0
                self.input_best_block_next_weight += 1;
841
0
            }
842
        }
843
844
        // Minor sanity checks.
845
0
        debug_assert!(
846
0
            self.non_finalized_blocks
847
0
                .iter_unordered()
848
0
                .all(|(_, b)| b.input_best_block_weight < self.input_best_block_next_weight)
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_blocks_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE20input_set_best_blocks_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE20input_set_best_blocks_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE20input_set_best_blocks_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE20input_set_best_blocks_0Cs7snhGEhbuap_18smoldot_light_wasm
849
        );
850
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE20input_set_best_blockB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE20input_set_best_blockB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE20input_set_best_blockCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE20input_set_best_blockCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE20input_set_best_blockCs7snhGEhbuap_18smoldot_light_wasm
851
852
    /// Updates the state machine to take into account that the input of blocks has finalized the
853
    /// given block.
854
    ///
855
    /// `new_best_block` is the best block after the finalization.
856
    ///
857
    /// > **Note**: Finalizing a block might have to modify the current best block if the block
858
    /// >           being finalized isn't an ancestor of the current best block.
859
    ///
860
    /// # Panic
861
    ///
862
    /// Panics if `node_to_finalize` isn't a valid node.
863
    /// Panics if the current input best block is not a descendant of `node_to_finalize`.
864
    ///
865
0
    pub fn input_finalize(&mut self, node_to_finalize: NodeIndex) {
866
        // Make sure that `new_best_block` is a descendant of `node_to_finalize`,
867
        // otherwise the state of the tree will be corrupted.
868
        // This is checked with an `assert!` rather than a `debug_assert!`, as this constraint
869
        // is part of the public API of this method.
870
0
        assert!(
871
0
            self.input_best_block_index
872
0
                .map_or(false, |current_input_best| self
873
0
                    .non_finalized_blocks
874
0
                    .is_ancestor(node_to_finalize, current_input_best))
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE14input_finalize0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE14input_finalize0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE14input_finalize0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE14input_finalize0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE14input_finalize0Cs7snhGEhbuap_18smoldot_light_wasm
875
        );
876
877
0
        self.input_finalized_index = Some(node_to_finalize);
878
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE14input_finalizeB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE14input_finalizeB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE14input_finalizeCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE14input_finalizeCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE14input_finalizeCs7snhGEhbuap_18smoldot_light_wasm
879
880
    /// Tries to update the output blocks to follow the input.
881
    ///
882
    /// Should be called after inserting a new block, finalizing a block, or when an asynchronous
883
    /// operation is finished.
884
    ///
885
    /// Returns `None` if the state machine doesn't have any update. This method should be called
886
    /// repeatedly until it returns `None`. Each call can perform an additional update.
887
    // TODO: should cache the information about whether an update is ready, so that calling this method becomes cheap
888
0
    pub fn try_advance_output(&mut self) -> Option<OutputUpdate<TBl, TAsync>> {
889
        // Try to advance the output finalized block.
890
        // `input_finalized_index` is `Some` if the input finalized is not already equal to the
891
        // output finalized.
892
0
        if let Some(input_finalized_index) = self.input_finalized_index {
893
            // Finding a new finalized block.
894
            // We always take the first node on the path towards `input_finalized_index`, in
895
            // order to finalize blocks one by one.
896
0
            let new_finalized = {
897
0
                self.non_finalized_blocks
898
0
                    .root_to_node_path(input_finalized_index)
899
0
                    .take(1)
900
0
                    .find(|node_index| {
901
0
                        matches!(
902
0
                            self.non_finalized_blocks.get(*node_index).unwrap().async_op,
903
                            AsyncOpState::Finished { reported: true, .. }
904
                        )
905
0
                    })
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_output0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_output0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18try_advance_output0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_output0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_output0Cs7snhGEhbuap_18smoldot_light_wasm
906
            };
907
908
0
            if let Some(new_finalized) = new_finalized {
909
                // Update `input_finalized_index` and `input_best_block_index`.
910
0
                if self.input_finalized_index == Some(new_finalized) {
911
0
                    self.input_finalized_index = None;
912
0
                }
913
0
                if self.input_best_block_index == Some(new_finalized) {
914
0
                    self.input_best_block_index = None;
915
0
                }
916
917
0
                let mut pruned_blocks = Vec::new();
918
0
                let mut pruned_finalized = None;
919
0
                let mut best_output_block_updated = false;
920
921
                // Since we change the finalized block, if the output best block is equal to this
922
                // finalized block, that means it is modified, even though its value might remain
923
                // at `None`.
924
0
                if self.output_best_block_index.is_none() {
925
0
                    best_output_block_updated = true;
926
0
                }
927
928
0
                for pruned in self.non_finalized_blocks.prune_ancestors(new_finalized) {
929
0
                    debug_assert_ne!(Some(pruned.index), self.input_finalized_index);
930
931
                    // If the best block would be pruned, reset it to the finalized block. The
932
                    // best block is updated later down this function.
933
0
                    if self
934
0
                        .output_best_block_index
935
0
                        .map_or(false, |b| b == pruned.index)
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18try_advance_outputs_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_outputs_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_outputs_0Cs7snhGEhbuap_18smoldot_light_wasm
936
0
                    {
937
0
                        self.output_best_block_index = None;
938
0
                        best_output_block_updated = true;
939
0
                    }
940
941
                    // Update `self.finalized_block_weight`.
942
0
                    if pruned.index == new_finalized {
943
0
                        self.output_finalized_block_weight =
944
0
                            pruned.user_data.input_best_block_weight;
945
0
                        pruned_finalized = Some(pruned);
946
0
                        continue;
947
0
                    }
948
949
0
                    let async_op = match pruned.user_data.async_op {
950
                        AsyncOpState::Finished {
951
0
                            user_data,
952
0
                            reported,
953
                            ..
954
                        } => {
955
                            // Here's a small corner case: the async operation was finished, but
956
                            // this block wasn't reported yet.
957
                            // This is actually problematic because the `TAsync` is thrown away
958
                            // silently while the public API gives the impression that all
959
                            // `TAsync`s are always returned.
960
                            // TODO: solve that
961
0
                            if reported { Some(user_data) } else { None }
962
                        }
963
0
                        _ => None,
964
                    };
965
966
0
                    pruned_blocks.push((pruned.index, pruned.user_data.user_data, async_op));
967
                }
968
969
                // Try to advance the output best block to the `Finished` block with the highest
970
                // weight.
971
                // Weight of the current output best block.
972
0
                let mut previously_reported_best_block_weight = match self.output_best_block_index {
973
0
                    None => self.output_finalized_block_weight,
974
0
                    Some(idx) => {
975
0
                        self.non_finalized_blocks
976
0
                            .get(idx)
977
0
                            .unwrap()
978
0
                            .input_best_block_weight
979
                    }
980
                };
981
982
0
                for (node_index, block) in self.non_finalized_blocks.iter_unordered() {
983
                    // Check uniqueness of weights.
984
0
                    debug_assert!(
985
0
                        block.input_best_block_weight != previously_reported_best_block_weight
986
0
                            || block.input_best_block_weight == 0
987
0
                            || self.output_best_block_index == Some(node_index)
988
                    );
989
990
0
                    if block.input_best_block_weight <= previously_reported_best_block_weight {
991
0
                        continue;
992
0
                    }
993
994
0
                    if !matches!(
995
0
                        block.async_op,
996
                        AsyncOpState::Finished { reported: true, .. }
997
                    ) {
998
0
                        continue;
999
0
                    }
1000
1001
                    // Input best can be updated to the block being iterated.
1002
0
                    previously_reported_best_block_weight = block.input_best_block_weight;
1003
0
                    self.output_best_block_index = Some(node_index);
1004
0
                    best_output_block_updated = true;
1005
1006
                    // Continue looping, as there might be another block with an even
1007
                    // higher weight.
1008
                }
1009
1010
0
                let pruned_finalized = pruned_finalized.unwrap();
1011
0
                let former_finalized_async_op_user_data = match pruned_finalized.user_data.async_op
1012
                {
1013
0
                    AsyncOpState::Finished { user_data, .. } => {
1014
0
                        mem::replace(&mut self.output_finalized_async_user_data, user_data)
1015
                    }
1016
0
                    _ => unreachable!(),
1017
                };
1018
1019
0
                return Some(OutputUpdate::Finalized {
1020
0
                    former_index: new_finalized,
1021
0
                    user_data: pruned_finalized.user_data.user_data,
1022
0
                    former_finalized_async_op_user_data,
1023
0
                    pruned_blocks,
1024
0
                    best_output_block_updated,
1025
0
                });
1026
0
            }
1027
0
        }
1028
1029
        // Now try to report blocks that haven't been reported yet.
1030
        // TODO: O(n) complexity and allocations
1031
0
        for node_index in self
1032
0
            .non_finalized_blocks
1033
0
            .iter_unordered()
1034
0
            .map(|(idx, _)| idx)
1035
0
            .collect::<Vec<_>>()
1036
        {
1037
            // Skip this block if its parent isn't reported yet.
1038
0
            if let Some(parent) = self.non_finalized_blocks.parent(node_index) {
1039
0
                if !matches!(
1040
0
                    self.non_finalized_blocks.get(parent).unwrap().async_op,
1041
                    AsyncOpState::Finished { reported: true, .. }
1042
                ) {
1043
0
                    continue;
1044
0
                }
1045
0
            }
1046
1047
            // Skip this block if it's already been reported. Otherwise, mark it as reported.
1048
0
            match &mut self
1049
0
                .non_finalized_blocks
1050
0
                .get_mut(node_index)
1051
0
                .unwrap()
1052
                .async_op
1053
            {
1054
0
                AsyncOpState::Finished { reported, .. } if !*reported => {
1055
0
                    *reported = true;
1056
0
                }
1057
0
                _ => continue,
1058
            }
1059
1060
            // Try to mark the best we're about to report as best block, if possible.
1061
0
            let is_new_best = self
1062
0
                .non_finalized_blocks
1063
0
                .get(node_index)
1064
0
                .unwrap()
1065
0
                .input_best_block_weight
1066
0
                > self
1067
0
                    .output_best_block_index
1068
0
                    .map_or(self.output_finalized_block_weight, |idx| {
1069
0
                        self.non_finalized_blocks
1070
0
                            .get(idx)
1071
0
                            .unwrap()
1072
0
                            .input_best_block_weight
1073
0
                    });
Unexecuted instantiation: _RNCNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreepppE18try_advance_outputs1_0B8_
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18try_advance_outputs1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEE18try_advance_outputs1_0Cs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNCNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEE18try_advance_outputs1_0Cs7snhGEhbuap_18smoldot_light_wasm
1074
0
            if is_new_best {
1075
0
                debug_assert_ne!(self.output_best_block_index, Some(node_index));
1076
0
                self.output_best_block_index = Some(node_index);
1077
0
            }
1078
1079
            // Report the new block.
1080
0
            return Some(OutputUpdate::Block(OutputUpdateBlock {
1081
0
                index: node_index,
1082
0
                is_new_best,
1083
0
            }));
1084
        }
1085
1086
        // Try to advance the output best block.
1087
        {
1088
0
            let mut best_block_updated = false;
1089
1090
            // Try to advance the output best block to the `Finished` block with the highest
1091
            // weight.
1092
            // Weight of the current output best block.
1093
0
            let mut current_runtime_service_best_block_weight = match self.output_best_block_index {
1094
0
                None => self.output_finalized_block_weight,
1095
0
                Some(idx) => {
1096
0
                    self.non_finalized_blocks
1097
0
                        .get(idx)
1098
0
                        .unwrap()
1099
0
                        .input_best_block_weight
1100
                }
1101
            };
1102
1103
0
            for (node_index, block) in self.non_finalized_blocks.iter_unordered() {
1104
                // Check uniqueness of weights.
1105
0
                debug_assert!(
1106
0
                    block.input_best_block_weight != current_runtime_service_best_block_weight
1107
0
                        || block.input_best_block_weight == 0
1108
0
                        || self.output_best_block_index == Some(node_index)
1109
                );
1110
1111
0
                if block.input_best_block_weight <= current_runtime_service_best_block_weight {
1112
0
                    continue;
1113
0
                }
1114
1115
0
                if !matches!(
1116
0
                    block.async_op,
1117
                    AsyncOpState::Finished { reported: true, .. }
1118
                ) {
1119
0
                    continue;
1120
0
                }
1121
1122
                // Input best can be updated to the block being iterated.
1123
0
                current_runtime_service_best_block_weight = block.input_best_block_weight;
1124
0
                self.output_best_block_index = Some(node_index);
1125
0
                best_block_updated = true;
1126
1127
                // Continue looping, as there might be another block with an even
1128
                // higher weight.
1129
            }
1130
1131
0
            if best_block_updated {
1132
0
                return Some(OutputUpdate::BestBlockChanged {
1133
0
                    best_block_index: self.output_best_block_index,
1134
0
                });
1135
0
            }
1136
        }
1137
1138
        // Nothing to do.
1139
0
        None
1140
0
    }
Unexecuted instantiation: _RNvMNtNtCsjlkOsLH0Zfj_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18try_advance_outputB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreepppE18try_advance_outputB6_
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEE18try_advance_outputCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB14_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEEE18try_advance_outputCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvMNtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB2_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1D_7RuntimeEE18try_advance_outputCs7snhGEhbuap_18smoldot_light_wasm
1141
}
1142
1143
impl<TNow, TBl, TAsync> ops::Index<NodeIndex> for AsyncTree<TNow, TBl, TAsync> {
1144
    type Output = TBl;
1145
1146
0
    fn index(&self, node_index: NodeIndex) -> &Self::Output {
1147
0
        &self.non_finalized_blocks.get(node_index).unwrap().user_data
1148
0
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot5chain10async_trees_0pppEINtB5_9AsyncTreepppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtNtB7_9fork_tree9NodeIndexE5indexB9_
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot5chain10async_trees_0pppEINtB5_9AsyncTreepppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtNtB7_9fork_tree9NodeIndexE5indexB9_
Unexecuted instantiation: _RNvXs_NtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationAhj20_INtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc3vec3VechEEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvXs_NtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtB16_6option6OptionINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCs7snhGEhbuap_18smoldot_light_wasm
Unexecuted instantiation: _RNvXs_NtNtCsc1ywvx6YAnK_7smoldot5chain10async_treeINtB4_9AsyncTreeNtNtCs1p5UDGgVI4d_4core4time8DurationNtNtCs508CmrSPkZh_13smoldot_light15runtime_service5BlockINtNtCsaFPxhswmqCN_5alloc4sync3ArcNtB1F_7RuntimeEEINtNtNtB16_3ops5index5IndexNtNtB6_9fork_tree9NodeIndexE5indexCs7snhGEhbuap_18smoldot_light_wasm
1149
}
1150
1151
impl<TNow, TBl, TAsync> ops::IndexMut<NodeIndex> for AsyncTree<TNow, TBl, TAsync> {
1152
0
    fn index_mut(&mut self, node_index: NodeIndex) -> &mut Self::Output {
1153
0
        &mut self
1154
0
            .non_finalized_blocks
1155
0
            .get_mut(node_index)
1156
0
            .unwrap()
1157
0
            .user_data
1158
0
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot5chain10async_trees0_0pppEINtB5_9AsyncTreepppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtNtB7_9fork_tree9NodeIndexE9index_mutB9_
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot5chain10async_trees0_0pppEINtB5_9AsyncTreepppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtNtB7_9fork_tree9NodeIndexE9index_mutB9_
1159
}
1160
1161
/// See [`AsyncTree::input_output_iter_unordered`] and
1162
/// [`AsyncTree::input_output_iter_ancestry_order`].
1163
#[derive(Debug, Clone, PartialEq, Eq)]
1164
pub struct InputIterItem<'a, TBl, TAsync> {
1165
    /// Index of the block.
1166
    pub id: NodeIndex,
1167
1168
    /// User data associated to this block that was passed to [`AsyncTree::input_insert_block`].
1169
    pub user_data: &'a TBl,
1170
1171
    /// User data of the asynchronous operation of this block.
1172
    ///
1173
    /// `Some` if and only if the block has been reported in a [`OutputUpdate`] before.
1174
    pub async_op_user_data: Option<&'a TAsync>,
1175
1176
    /// Whether this block is considered as the best block of the output.
1177
    ///
1178
    /// Either 0 or 1 blocks will have the "is output best" boolean set to true. If no blocks have
1179
    /// this boolean set, then the best block is the finalized block.
1180
    pub is_output_best: bool,
1181
}
1182
1183
/// See [`AsyncTree::try_advance_output`].
1184
#[derive(Debug, Clone, PartialEq, Eq)]
1185
pub enum OutputUpdate<TBl, TAsync> {
1186
    /// A non-finalized block has been finalized in the output.
1187
    ///
1188
    /// This block is no longer part of the data structure.
1189
    ///
1190
    /// Blocks are guaranteed to be finalized one after the other, without any gap.
1191
    Finalized {
1192
        /// Index of the node within the data structure. This index is no longer valid and is
1193
        /// here for reference.
1194
        former_index: NodeIndex,
1195
1196
        /// User data associated to this block.
1197
        user_data: TBl,
1198
1199
        /// User data associated to the `async` operation of the previous finalized block.
1200
        former_finalized_async_op_user_data: TAsync,
1201
1202
        /// `true` if the finalization has updated the best output block.
1203
        best_output_block_updated: bool,
1204
1205
        /// Blocks that were a descendant of the former finalized block but not of the new
1206
        /// finalized block. These blocks are no longer part of the data structure.
1207
        ///
1208
        /// If the `Option<TAsync>` is `Some`, then that block was part of the output. Otherwise
1209
        /// it wasn't.
1210
        pruned_blocks: Vec<(NodeIndex, TBl, Option<TAsync>)>,
1211
    },
1212
1213
    /// A new block has been added to the list of output unfinalized blocks.
1214
    Block(OutputUpdateBlock),
1215
1216
    /// The output best block has been modified.
1217
    BestBlockChanged {
1218
        /// Index of the best block after the finalization. `None` if the best block is the
1219
        /// output finalized block.
1220
        best_block_index: Option<NodeIndex>,
1221
    },
1222
}
1223
1224
/// See [`OutputUpdate`].
1225
#[derive(Debug, Clone, PartialEq, Eq)]
1226
pub struct OutputUpdateBlock {
1227
    /// Index of the node within the data structure.
1228
    pub index: NodeIndex,
1229
1230
    /// True if this block is considered as the best block of the chain.
1231
    pub is_new_best: bool,
1232
}
1233
1234
struct Block<TNow, TBl, TAsync> {
1235
    /// User data associated with that block.
1236
    user_data: TBl,
1237
1238
    /// Operation information of that block. Shared amongst multiple different blocks.
1239
    async_op: AsyncOpState<TNow, TAsync>,
1240
1241
    /// A block with a higher value here has been reported by the input as the best block
1242
    /// more recently than a block with a lower value. `0` means never reported as best block.
1243
    input_best_block_weight: u32,
1244
}
1245
1246
enum AsyncOpState<TNow, TAsync> {
1247
    /// Operation has finished and was successful.
1248
    Finished {
1249
        /// User data chose by the user.
1250
        user_data: TAsync,
1251
1252
        /// `true` if this block has already been reported in the output.
1253
        reported: bool,
1254
    },
1255
1256
    /// Operation is currently in progress.
1257
    InProgress {
1258
        /// Identifier for this operation in the public API.
1259
        /// Attributed from [`AsyncTree::next_async_op_id`]. Multiple different blocks can
1260
        /// point to the same `async_op_id` when it is known that they point to the same operation.
1261
        async_op_id: AsyncOpId,
1262
1263
        /// Do not start any operation before `TNow`. Used to avoid repeatedly trying to perform
1264
        /// the operation on the same block over and over again when it's constantly failing.
1265
        timeout: Option<TNow>,
1266
    },
1267
1268
    /// Operation hasn't started.
1269
    Pending {
1270
        /// `true` if this operation should be the same as its parent's.
1271
        /// If `true`, it is illegal for the parent to be in the state
1272
        /// [`AsyncOpState::Finished`] or [`AsyncOpState::InProgress`].
1273
        ///
1274
        /// When in doubt, `false`.
1275
        same_as_parent: bool,
1276
1277
        /// Do not start any operation before `TNow`. Used to avoid repeatedly trying to perform
1278
        /// the same operation over and over again when it's constantly failing.
1279
        timeout: Option<TNow>,
1280
    },
1281
}
1282
1283
/// Equivalent to [`NextNecessaryAsyncOp`] but private and doesn't use lifetimes. Necessary in
1284
/// order to bypass borrow checker issues.
1285
#[derive(Debug)]
1286
enum NextNecessaryAsyncOpInternal<TNow> {
1287
    Ready(AsyncOpId, NodeIndex),
1288
    NotReady { when: Option<TNow> },
1289
}
1290
1291
// TODO: needs tests