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/network/service.rs
Line
Count
Source
1
// Smoldot
2
// Copyright (C) 2023  Pierre Krieger
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
//! State machine of all networking connections.
19
//!
20
//! The [`ChainNetwork`] struct is a state machine containing multiple collections that are
21
//! controlled by the API user:
22
//!
23
//! - A list of networking connections, identified by a [`ConnectionId`]. Each connection is
24
//! either in the handshake phase, healthy, or shutting down. Each connection in the handshake
25
//! phase has an optional expected [`PeerId`] representing the identity of the node that is
26
//! expected to be reached once the handshake is finished. Each connection that is healthy or
27
//! shutting down has an (actual) [`PeerId`] associated to it.
28
//! - A list of chains, identified by a [`ChainId`].
29
//! - A set of "desired" `(ChainId, PeerId, GossipKind)` tuples representing, for each chain, the
30
//! identities of the nodes that the API user wants to establish a gossip link with.
31
//!
32
//! In addition to this, the [`ChainNetwork`] also exposes:
33
//!
34
//! - A set of `(ChainId, PeerId, GossipKind)` tuples representing the gossip links that have been
35
//! established.
36
//! - A list of outgoing requests, identified by a [`SubstreamId`], that have been sent to a peer
37
//! and that are awaiting a response.
38
//! - A list of ingoing requests, identified by a [`SubstreamId`], that have been received from a
39
//! peer and that must be answered by the API user.
40
//! - A list of outgoing gossip link connection attempts, identified by a [`SubstreamId`], that
41
//! must be answered by the peer.
42
//! - A set of `(ChainId, PeerId, GossipKind)` tuples representing the peers that would like to
43
//! establish a gossip link with the local node, and that are awaiting a response by the API user.
44
//!
45
//! # Usage
46
//!
47
//! At initialization, create a new [`ChainNetwork`] with [`ChainNetwork::new`], and add chains
48
//! using [`ChainNetwork::add_chain`].
49
//!
50
//! The [`ChainNetwork`] doesn't automatically open connections to peers. This must be done
51
//! manually using [`ChainNetwork::add_single_stream_connection`] or
52
//! [`ChainNetwork::add_multi_stream_connection`]. Choosing which peer to connect to and through
53
//! which address is outside of the scope of this module.
54
//!
55
//! Adding a connection using [`ChainNetwork::add_single_stream_connection`] or
56
//! [`ChainNetwork::add_multi_stream_connection`] returns a "connection task". This connection task
57
//! must be processed. TODO: expand explanation here
58
//!
59
//! After a message has been injected using [`ChainNetwork::inject_connection_message`], repeatedly
60
//! [`ChainNetwork::next_event`] until it returns `None` in order to determine what has happened.
61
//!
62
//! Once a connection has been established (which is indicated by a [`Event::HandshakeFinished`]
63
//! event), one can open a gossip link to this peer using [`ChainNetwork::gossip_open`].
64
//!
65
//! In order to facilitate this process, the [`ChainNetwork`] provides a "desired gossip links"
66
//! system. Use [`ChainNetwork::gossip_insert_desired`] and [`ChainNetwork::gossip_remove_desired`]
67
//! to insert or remove `(ChainId, PeerId, GossipKind)` tuples into the state machine. You can
68
//! then use [`ChainNetwork::unconnected_desired`] to obtain a list of [`PeerId`]s that are marked
69
//! as desired and for which a connection should be opened, and
70
//! [`ChainNetwork::connected_unopened_gossip_desired`] to obtain a list of [`PeerId`]s that are
71
//! marked as desired and that have a healthy connection and for which a gossip link should be
72
//! opened. Marking peers as desired only influences the return values of
73
//! [`ChainNetwork::unconnected_desired`] and [`ChainNetwork::connected_unopened_gossip_desired`]
74
//! and has no other effect.
75
//!
76
77
// TODO: expand explanations once the API is finalized
78
79
use crate::libp2p::collection;
80
use crate::network::codec;
81
use crate::util::{self, SipHasherBuild};
82
83
use alloc::{borrow::ToOwned as _, collections::BTreeSet, string::String, vec::Vec};
84
use core::{
85
    fmt,
86
    hash::Hash,
87
    iter,
88
    ops::{self, Add, Sub},
89
    time::Duration,
90
};
91
use rand_chacha::rand_core::{RngCore as _, SeedableRng as _};
92
93
pub use crate::libp2p::{
94
    collection::{
95
        ConnectionId, ConnectionToCoordinator, CoordinatorToConnection, InboundError,
96
        MultiStreamConnectionTask, MultiStreamHandshakeKind, NotificationsOutErr, ReadWrite,
97
        RequestError, SingleStreamConnectionTask, SingleStreamHandshakeKind, SubstreamId,
98
    },
99
    connection::noise::{self, NoiseKey},
100
    multiaddr::{self, Multiaddr},
101
    peer_id::{self, PeerId},
102
};
103
104
pub use crate::network::codec::{BlockAnnouncesHandshakeDecodeError, Role};
105
106
/// Configuration for a [`ChainNetwork`].
107
pub struct Config {
108
    /// Capacity to initially reserve to the list of connections.
109
    pub connections_capacity: usize,
110
111
    /// Capacity to reserve for the list of chains.
112
    pub chains_capacity: usize,
113
114
    /// Seed for the randomness within the networking state machine.
115
    ///
116
    /// While this seed influences the general behavior of the networking state machine, it
117
    /// notably isn't used when generating the ephemeral key used for the Diffie-Hellman
118
    /// handshake.
119
    /// This is a defensive measure against users passing a dummy seed instead of actual entropy.
120
    pub randomness_seed: [u8; 32],
121
122
    /// Amount of time after which a connection hathat ndshake is considered to have taken too long
123
    /// and must be aborted.
124
    pub handshake_timeout: Duration,
125
}
126
127
/// Configuration for a specific overlay network.
128
///
129
/// See [`ChainNetwork::add_chain`].
130
pub struct ChainConfig<TChain> {
131
    /// Opaque data chosen by the API user. Can later be accessed using the `Index`/`IndexMut`
132
    /// trait implementation of the [`ChainNetwork`].
133
    pub user_data: TChain,
134
135
    /// Hash of the genesis block (i.e. block number 0) according to the local node.
136
    pub genesis_hash: [u8; 32],
137
138
    /// Optional identifier to insert into the networking protocol names. Used to differentiate
139
    /// between chains with the same genesis hash.
140
    ///
141
    /// > **Note**: This value is typically found in the specification of the chain (the
142
    /// >           "chain spec").
143
    pub fork_id: Option<String>,
144
145
    /// Number of bytes of the block number in the networking protocol.
146
    pub block_number_bytes: usize,
147
148
    /// If `Some`, the chain uses the GrandPa networking protocol.
149
    pub grandpa_protocol_config: Option<GrandpaState>,
150
151
    /// `true` if incoming block requests are allowed.
152
    pub allow_inbound_block_requests: bool,
153
154
    /// Hash of the best block according to the local node.
155
    pub best_hash: [u8; 32],
156
    /// Height of the best block according to the local node.
157
    pub best_number: u64,
158
159
    /// Role of the local node. Sent to the remote nodes and used as a hint. Has no incidence
160
    /// on the behavior of any function.
161
    pub role: Role,
162
}
163
164
/// Identifier of a chain added through [`ChainNetwork::add_chain`].
165
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
166
pub struct ChainId(usize);
167
168
/// Data structure containing the list of all connections and their latest known state. See also
169
/// [the module-level documentation](..).
170
pub struct ChainNetwork<TChain, TConn, TNow> {
171
    /// Underlying data structure.
172
    inner: collection::Network<ConnectionInfo<TConn>, TNow>,
173
174
    /// List of all chains that have been added.
175
    // TODO: shrink to fit from time to time
176
    chains: slab::Slab<Chain<TChain>>,
177
178
    /// Chains indexed by genesis hash and fork ID.
179
    ///
180
    /// Contains the same number of entries as [`ChainNetwork::chains`]. The values are `usize`s
181
    /// that are indices into [`ChainNetwork::chains`].
182
    // TODO: shrink to fit from time to time
183
    chains_by_protocol_info:
184
        hashbrown::HashMap<([u8; 32], Option<String>), usize, fnv::FnvBuildHasher>,
185
186
    /// List of all known network identities. The `usize` in [`PeerIndex`] refers to an index
187
    /// within this list.
188
    // TODO: shrink to fit from time to time
189
    peers: slab::Slab<PeerId>,
190
191
    /// Same entries as [`ChainNetwork::peers`], by indexed differently.
192
    // TODO: shrink to fit from time to time
193
    peers_by_peer_id: hashbrown::HashMap<PeerId, PeerIndex, SipHasherBuild>,
194
195
    /// Connections indexed by the value in [`ConnectionInfo::peer_index`].
196
    connections_by_peer_id: BTreeSet<(PeerIndex, collection::ConnectionId)>,
197
198
    /// List of peers that have been marked as desired. Can include peers not connected to the
199
    /// local node yet.
200
    gossip_desired_peers_by_chain: BTreeSet<(usize, GossipKind, PeerIndex)>,
201
202
    /// Same entries as [`ChainNetwork::gossip_desired_peers_by_chain`] but indexed differently.
203
    gossip_desired_peers: BTreeSet<(PeerIndex, GossipKind, usize)>,
204
205
    /// Subset of peers in [`ChainNetwork::gossip_desired_peers`] for which no healthy
206
    /// connection exists.
207
    // TODO: shrink to fit from time to time
208
    unconnected_desired: hashbrown::HashSet<PeerIndex, fnv::FnvBuildHasher>,
209
210
    /// List of [`PeerId`]s that are marked as desired, and for which a healthy connection exists,
211
    /// but for which no substream connection (attempt or established) exists.
212
    // TODO: shrink to fit from time to time
213
    connected_unopened_gossip_desired:
214
        hashbrown::HashSet<(PeerIndex, ChainId, GossipKind), fnv::FnvBuildHasher>,
215
216
    /// List of [`PeerId`]s for which a substream connection (attempt or established) exists, but
217
    /// that are not marked as desired.
218
    // TODO: shrink to fit from time to time
219
    opened_gossip_undesired:
220
        hashbrown::HashSet<(ChainId, PeerIndex, GossipKind), fnv::FnvBuildHasher>,
221
222
    /// All the substreams of [`ChainNetwork::inner`], with info attached to them.
223
    // TODO: add a substream user data to `collection::Network` instead
224
    // TODO: shrink to fit from time to time
225
    substreams: hashbrown::HashMap<SubstreamId, SubstreamInfo, fnv::FnvBuildHasher>,
226
227
    /// All the outbound notification substreams, indexed by protocol, `PeerId`, and state.
228
    // TODO: unclear whether PeerId should come before or after the state, same for direction/state
229
    notification_substreams_by_peer_id: BTreeSet<(
230
        NotificationsProtocol,
231
        PeerIndex,
232
        SubstreamDirection,
233
        NotificationsSubstreamState,
234
        collection::SubstreamId,
235
    )>,
236
}
237
238
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
239
struct PeerIndex(usize);
240
241
struct Chain<TChain> {
242
    /// See [`ChainConfig::block_number_bytes`].
243
    block_number_bytes: usize,
244
245
    /// See [`ChainConfig::genesis_hash`].
246
    genesis_hash: [u8; 32],
247
    /// See [`ChainConfig::fork_id`].
248
    fork_id: Option<String>,
249
250
    /// See [`ChainConfig::role`].
251
    role: Role,
252
253
    /// See [`ChainConfig::best_hash`].
254
    best_hash: [u8; 32],
255
    /// See [`ChainConfig::best_number`].
256
    best_number: u64,
257
258
    /// See [`ChainConfig::grandpa_protocol_config`].
259
    grandpa_protocol_config: Option<GrandpaState>,
260
261
    /// See [`ChainConfig::allow_inbound_block_requests`].
262
    allow_inbound_block_requests: bool,
263
264
    /// See [`ChainConfig::user_data`].
265
    user_data: TChain,
266
}
267
268
/// See [`ChainNetwork::inner`].
269
struct ConnectionInfo<TConn> {
270
    address: Vec<u8>,
271
272
    /// Public key of the local node used for this connection.
273
    /// This information can be requested by the remote.
274
    ed25519_public_key: [u8; 32],
275
276
    /// Identity of the remote. Can be either the expected or the actual identity.
277
    ///
278
    /// `None` if unknown, which can only be the case if the connection is still in its handshake
279
    /// phase.
280
    peer_index: Option<PeerIndex>,
281
282
    /// User data decided by the API user.
283
    user_data: TConn,
284
}
285
286
/// See [`ChainNetwork::substreams`].
287
#[derive(Debug, Clone)]
288
struct SubstreamInfo {
289
    // TODO: substream <-> connection mapping should be provided by collection.rs instead
290
    connection_id: collection::ConnectionId,
291
    /// `None` if the substream concerns a chain that has been removed.
292
    protocol: Option<Protocol>,
293
}
294
295
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
296
enum Protocol {
297
    Identify,
298
    Ping,
299
    Notifications(NotificationsProtocol),
300
    Sync { chain_index: usize },
301
    LightUnknown { chain_index: usize },
302
    LightStorage { chain_index: usize },
303
    LightCall { chain_index: usize },
304
    Kad { chain_index: usize },
305
    SyncWarp { chain_index: usize },
306
    State { chain_index: usize },
307
}
308
309
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
310
enum NotificationsProtocol {
311
    BlockAnnounces { chain_index: usize },
312
    Transactions { chain_index: usize },
313
    Grandpa { chain_index: usize },
314
}
315
316
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
317
enum SubstreamDirection {
318
    In,
319
    Out,
320
}
321
322
impl SubstreamDirection {
323
    const MIN: Self = SubstreamDirection::In;
324
    const MAX: Self = SubstreamDirection::Out;
325
}
326
327
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
328
enum NotificationsSubstreamState {
329
    Pending,
330
    Open { asked_to_leave: bool },
331
}
332
333
impl NotificationsSubstreamState {
334
    const MIN: Self = NotificationsSubstreamState::Pending;
335
    const MAX: Self = NotificationsSubstreamState::Open {
336
        asked_to_leave: true,
337
    };
338
    const OPEN_MIN_VALUE: Self = NotificationsSubstreamState::Open {
339
        asked_to_leave: false,
340
    };
341
    const OPEN_MAX_VALUE: Self = NotificationsSubstreamState::Open {
342
        asked_to_leave: true,
343
    };
344
}
345
346
impl<TChain, TConn, TNow> ChainNetwork<TChain, TConn, TNow>
347
where
348
    TNow: Clone + Add<Duration, Output = TNow> + Sub<TNow, Output = Duration> + Ord,
349
{
350
    /// Initializes a new [`ChainNetwork`].
351
21
    pub fn new(config: Config) -> Self {
352
21
        let mut randomness = rand_chacha::ChaCha20Rng::from_seed(config.randomness_seed);
353
354
21
        ChainNetwork {
355
21
            inner: collection::Network::new(collection::Config {
356
21
                capacity: config.connections_capacity,
357
21
                max_inbound_substreams: 128, // TODO: arbitrary value ; this value should be dynamically adjusted based on the number of chains that have been added
358
21
                max_protocol_name_len: 64,
359
21
                randomness_seed: {
360
21
                    let mut seed = [0; 32];
361
21
                    randomness.fill_bytes(&mut seed);
362
21
                    seed
363
21
                },
364
21
                ping_protocol: "/ipfs/ping/1.0.0".into(),
365
21
                handshake_timeout: config.handshake_timeout,
366
21
            }),
367
21
            peers: slab::Slab::with_capacity(config.connections_capacity),
368
21
            peers_by_peer_id: hashbrown::HashMap::with_capacity_and_hasher(
369
21
                config.connections_capacity,
370
21
                SipHasherBuild::new({
371
21
                    let mut seed = [0; 16];
372
21
                    randomness.fill_bytes(&mut seed);
373
21
                    seed
374
21
                }),
375
21
            ),
376
21
            substreams: hashbrown::HashMap::with_capacity_and_hasher(
377
21
                config.connections_capacity * 20, // TODO: capacity?
378
21
                fnv::FnvBuildHasher::default(),
379
21
            ),
380
21
            connections_by_peer_id: BTreeSet::new(),
381
21
            notification_substreams_by_peer_id: BTreeSet::new(),
382
21
            gossip_desired_peers_by_chain: BTreeSet::new(),
383
21
            gossip_desired_peers: BTreeSet::new(),
384
21
            unconnected_desired: hashbrown::HashSet::with_capacity_and_hasher(
385
21
                config.connections_capacity,
386
21
                Default::default(),
387
21
            ),
388
21
            connected_unopened_gossip_desired: hashbrown::HashSet::with_capacity_and_hasher(
389
21
                config.connections_capacity,
390
21
                Default::default(),
391
21
            ),
392
21
            opened_gossip_undesired: hashbrown::HashSet::with_capacity_and_hasher(
393
21
                config.connections_capacity,
394
21
                Default::default(),
395
21
            ),
396
21
            chains: slab::Slab::with_capacity(config.chains_capacity),
397
21
            chains_by_protocol_info: hashbrown::HashMap::with_capacity_and_hasher(
398
21
                config.chains_capacity,
399
21
                Default::default(),
400
21
            ),
401
21
        }
402
21
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE3newB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE3newCscoAnRPySggw_6author
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE3newB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE3newB24_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE3newCsjyNE3yDMkgA_14json_rpc_basic
Line
Count
Source
351
2
    pub fn new(config: Config) -> Self {
352
2
        let mut randomness = rand_chacha::ChaCha20Rng::from_seed(config.randomness_seed);
353
354
2
        ChainNetwork {
355
2
            inner: collection::Network::new(collection::Config {
356
2
                capacity: config.connections_capacity,
357
2
                max_inbound_substreams: 128, // TODO: arbitrary value ; this value should be dynamically adjusted based on the number of chains that have been added
358
2
                max_protocol_name_len: 64,
359
2
                randomness_seed: {
360
2
                    let mut seed = [0; 32];
361
2
                    randomness.fill_bytes(&mut seed);
362
2
                    seed
363
2
                },
364
2
                ping_protocol: "/ipfs/ping/1.0.0".into(),
365
2
                handshake_timeout: config.handshake_timeout,
366
2
            }),
367
2
            peers: slab::Slab::with_capacity(config.connections_capacity),
368
2
            peers_by_peer_id: hashbrown::HashMap::with_capacity_and_hasher(
369
2
                config.connections_capacity,
370
2
                SipHasherBuild::new({
371
2
                    let mut seed = [0; 16];
372
2
                    randomness.fill_bytes(&mut seed);
373
2
                    seed
374
2
                }),
375
2
            ),
376
2
            substreams: hashbrown::HashMap::with_capacity_and_hasher(
377
2
                config.connections_capacity * 20, // TODO: capacity?
378
2
                fnv::FnvBuildHasher::default(),
379
2
            ),
380
2
            connections_by_peer_id: BTreeSet::new(),
381
2
            notification_substreams_by_peer_id: BTreeSet::new(),
382
2
            gossip_desired_peers_by_chain: BTreeSet::new(),
383
2
            gossip_desired_peers: BTreeSet::new(),
384
2
            unconnected_desired: hashbrown::HashSet::with_capacity_and_hasher(
385
2
                config.connections_capacity,
386
2
                Default::default(),
387
2
            ),
388
2
            connected_unopened_gossip_desired: hashbrown::HashSet::with_capacity_and_hasher(
389
2
                config.connections_capacity,
390
2
                Default::default(),
391
2
            ),
392
2
            opened_gossip_undesired: hashbrown::HashSet::with_capacity_and_hasher(
393
2
                config.connections_capacity,
394
2
                Default::default(),
395
2
            ),
396
2
            chains: slab::Slab::with_capacity(config.chains_capacity),
397
2
            chains_by_protocol_info: hashbrown::HashMap::with_capacity_and_hasher(
398
2
                config.chains_capacity,
399
2
                Default::default(),
400
2
            ),
401
2
        }
402
2
    }
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE3newCs4VrkfB1pvQ3_25json_rpc_general_requests
Line
Count
Source
351
19
    pub fn new(config: Config) -> Self {
352
19
        let mut randomness = rand_chacha::ChaCha20Rng::from_seed(config.randomness_seed);
353
354
19
        ChainNetwork {
355
19
            inner: collection::Network::new(collection::Config {
356
19
                capacity: config.connections_capacity,
357
19
                max_inbound_substreams: 128, // TODO: arbitrary value ; this value should be dynamically adjusted based on the number of chains that have been added
358
19
                max_protocol_name_len: 64,
359
19
                randomness_seed: {
360
19
                    let mut seed = [0; 32];
361
19
                    randomness.fill_bytes(&mut seed);
362
19
                    seed
363
19
                },
364
19
                ping_protocol: "/ipfs/ping/1.0.0".into(),
365
19
                handshake_timeout: config.handshake_timeout,
366
19
            }),
367
19
            peers: slab::Slab::with_capacity(config.connections_capacity),
368
19
            peers_by_peer_id: hashbrown::HashMap::with_capacity_and_hasher(
369
19
                config.connections_capacity,
370
19
                SipHasherBuild::new({
371
19
                    let mut seed = [0; 16];
372
19
                    randomness.fill_bytes(&mut seed);
373
19
                    seed
374
19
                }),
375
19
            ),
376
19
            substreams: hashbrown::HashMap::with_capacity_and_hasher(
377
19
                config.connections_capacity * 20, // TODO: capacity?
378
19
                fnv::FnvBuildHasher::default(),
379
19
            ),
380
19
            connections_by_peer_id: BTreeSet::new(),
381
19
            notification_substreams_by_peer_id: BTreeSet::new(),
382
19
            gossip_desired_peers_by_chain: BTreeSet::new(),
383
19
            gossip_desired_peers: BTreeSet::new(),
384
19
            unconnected_desired: hashbrown::HashSet::with_capacity_and_hasher(
385
19
                config.connections_capacity,
386
19
                Default::default(),
387
19
            ),
388
19
            connected_unopened_gossip_desired: hashbrown::HashSet::with_capacity_and_hasher(
389
19
                config.connections_capacity,
390
19
                Default::default(),
391
19
            ),
392
19
            opened_gossip_undesired: hashbrown::HashSet::with_capacity_and_hasher(
393
19
                config.connections_capacity,
394
19
                Default::default(),
395
19
            ),
396
19
            chains: slab::Slab::with_capacity(config.chains_capacity),
397
19
            chains_by_protocol_info: hashbrown::HashMap::with_capacity_and_hasher(
398
19
                config.chains_capacity,
399
19
                Default::default(),
400
19
            ),
401
19
        }
402
19
    }
403
404
    /// Adds a chain to the list of chains that is handled by the [`ChainNetwork`].
405
    ///
406
    /// It is not possible to add a chain if its protocol names would conflict with an existing
407
    /// chain.
408
21
    pub fn add_chain(&mut self, config: ChainConfig<TChain>) -> Result<ChainId, AddChainError> {
409
21
        let chain_entry = self.chains.vacant_entry();
410
21
        let chain_id = chain_entry.key();
411
412
21
        match self
413
21
            .chains_by_protocol_info
414
21
            .entry((config.genesis_hash, config.fork_id.clone()))
415
        {
416
21
            hashbrown::hash_map::Entry::Vacant(entry) => {
417
21
                entry.insert(chain_id);
418
21
            }
419
0
            hashbrown::hash_map::Entry::Occupied(entry) => {
420
0
                return Err(AddChainError::Duplicate {
421
0
                    existing_identical: ChainId(*entry.get()),
422
0
                });
423
            }
424
        }
425
426
21
        chain_entry.insert(Chain {
427
21
            block_number_bytes: config.block_number_bytes,
428
21
            genesis_hash: config.genesis_hash,
429
21
            fork_id: config.fork_id,
430
21
            role: config.role,
431
21
            best_hash: config.best_hash,
432
21
            best_number: config.best_number,
433
21
            allow_inbound_block_requests: config.allow_inbound_block_requests,
434
21
            grandpa_protocol_config: config.grandpa_protocol_config,
435
21
            user_data: config.user_data,
436
21
        });
437
438
        // TODO: consider optimizing this, as it's O(n) over the number of chains currently
439
21
        self.inner.set_max_protocol_name_len(
440
21
            self.chains
441
21
                .iter()
442
21
                .map(|chain| chain.1.fork_id.as_ref().map_or(0, |s| 
s0
.
len0
() + 1))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE9add_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain0CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE9add_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE9add_chain0B26_
_RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain0CsjyNE3yDMkgA_14json_rpc_basic
Line
Count
Source
442
2
                .map(|chain| chain.1.fork_id.as_ref().map_or(0, |s| s.len() + 1))
_RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain0Cs4VrkfB1pvQ3_25json_rpc_general_requests
Line
Count
Source
442
19
                .map(|chain| chain.1.fork_id.as_ref().map_or(0, |s| s.len() + 1))
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB9_12ChainNetworkpppE9add_chain00Bd_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain00CscoAnRPySggw_6author
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkpppE9add_chain00Bd_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE9add_chain00B28_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain00CsjyNE3yDMkgA_14json_rpc_basic
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chain00Cs4VrkfB1pvQ3_25json_rpc_general_requests
443
21
                .max()
444
21
                .unwrap_or(0)
445
                + 64,
446
        );
447
448
21
        Ok(ChainId(chain_id))
449
21
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE9add_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chainCscoAnRPySggw_6author
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE9add_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE9add_chainB24_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chainCsjyNE3yDMkgA_14json_rpc_basic
Line
Count
Source
408
2
    pub fn add_chain(&mut self, config: ChainConfig<TChain>) -> Result<ChainId, AddChainError> {
409
2
        let chain_entry = self.chains.vacant_entry();
410
2
        let chain_id = chain_entry.key();
411
412
2
        match self
413
2
            .chains_by_protocol_info
414
2
            .entry((config.genesis_hash, config.fork_id.clone()))
415
        {
416
2
            hashbrown::hash_map::Entry::Vacant(entry) => {
417
2
                entry.insert(chain_id);
418
2
            }
419
0
            hashbrown::hash_map::Entry::Occupied(entry) => {
420
0
                return Err(AddChainError::Duplicate {
421
0
                    existing_identical: ChainId(*entry.get()),
422
0
                });
423
            }
424
        }
425
426
2
        chain_entry.insert(Chain {
427
2
            block_number_bytes: config.block_number_bytes,
428
2
            genesis_hash: config.genesis_hash,
429
2
            fork_id: config.fork_id,
430
2
            role: config.role,
431
2
            best_hash: config.best_hash,
432
2
            best_number: config.best_number,
433
2
            allow_inbound_block_requests: config.allow_inbound_block_requests,
434
2
            grandpa_protocol_config: config.grandpa_protocol_config,
435
2
            user_data: config.user_data,
436
2
        });
437
438
        // TODO: consider optimizing this, as it's O(n) over the number of chains currently
439
2
        self.inner.set_max_protocol_name_len(
440
2
            self.chains
441
2
                .iter()
442
2
                .map(|chain| chain.1.fork_id.as_ref().map_or(0, |s| s.len() + 1))
443
2
                .max()
444
2
                .unwrap_or(0)
445
                + 64,
446
        );
447
448
2
        Ok(ChainId(chain_id))
449
2
    }
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE9add_chainCs4VrkfB1pvQ3_25json_rpc_general_requests
Line
Count
Source
408
19
    pub fn add_chain(&mut self, config: ChainConfig<TChain>) -> Result<ChainId, AddChainError> {
409
19
        let chain_entry = self.chains.vacant_entry();
410
19
        let chain_id = chain_entry.key();
411
412
19
        match self
413
19
            .chains_by_protocol_info
414
19
            .entry((config.genesis_hash, config.fork_id.clone()))
415
        {
416
19
            hashbrown::hash_map::Entry::Vacant(entry) => {
417
19
                entry.insert(chain_id);
418
19
            }
419
0
            hashbrown::hash_map::Entry::Occupied(entry) => {
420
0
                return Err(AddChainError::Duplicate {
421
0
                    existing_identical: ChainId(*entry.get()),
422
0
                });
423
            }
424
        }
425
426
19
        chain_entry.insert(Chain {
427
19
            block_number_bytes: config.block_number_bytes,
428
19
            genesis_hash: config.genesis_hash,
429
19
            fork_id: config.fork_id,
430
19
            role: config.role,
431
19
            best_hash: config.best_hash,
432
19
            best_number: config.best_number,
433
19
            allow_inbound_block_requests: config.allow_inbound_block_requests,
434
19
            grandpa_protocol_config: config.grandpa_protocol_config,
435
19
            user_data: config.user_data,
436
19
        });
437
438
        // TODO: consider optimizing this, as it's O(n) over the number of chains currently
439
19
        self.inner.set_max_protocol_name_len(
440
19
            self.chains
441
19
                .iter()
442
19
                .map(|chain| chain.1.fork_id.as_ref().map_or(0, |s| s.len() + 1))
443
19
                .max()
444
19
                .unwrap_or(0)
445
                + 64,
446
        );
447
448
19
        Ok(ChainId(chain_id))
449
19
    }
450
451
    /// Removes a chain previously added with [`ChainNetwork::add_chain`].
452
    ///
453
    /// This function will return an error if any gossip link is currently open through the
454
    /// given chain. Gossip links should be closed prior to calling this function.
455
    ///
456
    /// Any request using the given chain will continue as normal.
457
    ///
458
    /// # Panic
459
    ///
460
    /// Panics if the [`ChainId`] is out of range.
461
    ///
462
0
    pub fn remove_chain(&mut self, chain_id: ChainId) -> Result<TChain, RemoveChainError> {
463
        // Check whether the chain is still in use.
464
0
        for protocol in [NotificationsProtocol::BlockAnnounces {
465
0
            chain_index: chain_id.0,
466
0
        }] {
467
0
            if self
468
0
                .notification_substreams_by_peer_id
469
0
                .range(
470
0
                    (
471
0
                        protocol,
472
0
                        PeerIndex(usize::MIN),
473
0
                        SubstreamDirection::Out,
474
0
                        NotificationsSubstreamState::OPEN_MIN_VALUE,
475
0
                        SubstreamId::MIN,
476
0
                    )
477
0
                        ..=(
478
0
                            protocol,
479
0
                            PeerIndex(usize::MAX),
480
0
                            SubstreamDirection::Out,
481
0
                            NotificationsSubstreamState::OPEN_MAX_VALUE,
482
0
                            SubstreamId::MAX,
483
0
                        ),
484
0
                )
485
0
                .find(|(_, _, direction, state, _)| {
486
0
                    matches!(*direction, SubstreamDirection::Out)
487
0
                        && matches!(*state, NotificationsSubstreamState::Open { .. })
488
0
                })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE12remove_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE12remove_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE12remove_chain0B26_
489
0
                .is_some()
490
            {
491
0
                return Err(RemoveChainError::InUse);
492
0
            }
493
        }
494
495
        // Clean up desired peers.
496
0
        let desired = self
497
0
            .gossip_desired_peers_by_chain
498
0
            .range(
499
0
                (
500
0
                    chain_id.0,
501
0
                    GossipKind::ConsensusTransactions,
502
0
                    PeerIndex(usize::MIN),
503
0
                )
504
0
                    ..=(
505
0
                        chain_id.0,
506
0
                        GossipKind::ConsensusTransactions,
507
0
                        PeerIndex(usize::MAX),
508
0
                    ),
509
            )
510
0
            .map(|(_, _, peer_index)| *peer_index)
511
0
            .collect::<Vec<_>>();
512
0
        for desired in desired {
513
0
            self.gossip_remove_desired_inner(chain_id, desired, GossipKind::ConsensusTransactions);
514
0
        }
515
516
        // Close any notifications substream of the chain.
517
0
        for protocol in [
518
0
            NotificationsProtocol::BlockAnnounces {
519
0
                chain_index: chain_id.0,
520
0
            },
521
0
            NotificationsProtocol::Transactions {
522
0
                chain_index: chain_id.0,
523
0
            },
524
0
            NotificationsProtocol::Grandpa {
525
0
                chain_index: chain_id.0,
526
0
            },
527
        ] {
528
0
            for (protocol, peer_index, direction, state, substream_id) in self
529
0
                .notification_substreams_by_peer_id
530
0
                .range(
531
0
                    (
532
0
                        protocol,
533
0
                        PeerIndex(usize::MIN),
534
0
                        SubstreamDirection::MIN,
535
0
                        NotificationsSubstreamState::MIN,
536
0
                        SubstreamId::MIN,
537
0
                    )
538
0
                        ..=(
539
0
                            protocol,
540
0
                            PeerIndex(usize::MAX),
541
0
                            SubstreamDirection::MAX,
542
0
                            NotificationsSubstreamState::MAX,
543
0
                            SubstreamId::MAX,
544
0
                        ),
545
                )
546
0
                .cloned()
547
0
                .collect::<Vec<_>>()
548
            {
549
0
                self.notification_substreams_by_peer_id.remove(&(
550
0
                    protocol,
551
0
                    peer_index,
552
0
                    direction,
553
0
                    state,
554
0
                    substream_id,
555
0
                ));
556
557
0
                match (direction, state) {
558
                    (SubstreamDirection::In, NotificationsSubstreamState::Pending) => {
559
0
                        self.inner.reject_in_notifications(substream_id);
560
0
                        let _was_in = self.substreams.remove(&substream_id);
561
0
                        debug_assert!(_was_in.is_some());
562
                    }
563
                    (
564
                        SubstreamDirection::In,
565
                        NotificationsSubstreamState::Open {
566
                            asked_to_leave: true,
567
                        },
568
0
                    ) => {
569
0
                        self.substreams.get_mut(&substream_id).unwrap().protocol = None;
570
0
                    }
571
                    (
572
                        SubstreamDirection::In,
573
                        NotificationsSubstreamState::Open {
574
                            asked_to_leave: false,
575
                        },
576
0
                    ) => {
577
0
                        self.inner
578
0
                            .start_close_in_notifications(substream_id, Duration::from_secs(5));
579
0
                        // TODO: arbitrary timeout ^
580
0
                        self.substreams.get_mut(&substream_id).unwrap().protocol = None;
581
0
                    }
582
                    (SubstreamDirection::Out, _) => {
583
0
                        self.inner.close_out_notifications(substream_id);
584
0
                        let _was_in = self.substreams.remove(&substream_id);
585
0
                        debug_assert!(_was_in.is_some());
586
                    }
587
                }
588
            }
589
        }
590
591
        // Process request-response protocols.
592
        // TODO: how to do request-responses in non-O(n) time?
593
0
        for (_, substream) in &mut self.substreams {
594
0
            match substream.protocol {
595
                Some(Protocol::Notifications(NotificationsProtocol::BlockAnnounces {
596
0
                    chain_index,
597
                }))
598
                | Some(Protocol::Notifications(NotificationsProtocol::Transactions {
599
0
                    chain_index,
600
                }))
601
0
                | Some(Protocol::Notifications(NotificationsProtocol::Grandpa { chain_index }))
602
0
                | Some(Protocol::Sync { chain_index })
603
0
                | Some(Protocol::LightUnknown { chain_index })
604
0
                | Some(Protocol::LightStorage { chain_index })
605
0
                | Some(Protocol::LightCall { chain_index })
606
0
                | Some(Protocol::Kad { chain_index })
607
0
                | Some(Protocol::SyncWarp { chain_index })
608
0
                | Some(Protocol::State { chain_index }) => {
609
0
                    if chain_index != chain_id.0 {
610
0
                        continue;
611
0
                    }
612
                }
613
0
                Some(Protocol::Identify) | Some(Protocol::Ping) | None => continue,
614
            }
615
616
0
            substream.protocol = None;
617
618
            // TODO: cancel outgoing requests instead of just ignoring their response
619
            // TODO: must send back an error to the ingoing requests; this is not a huge deal because requests will time out on the remote's side, but it's very stupid nonetheless
620
        }
621
622
        // Actually remove the chain. This will panic if the `ChainId` is invalid.
623
0
        let chain = self.chains.remove(chain_id.0);
624
0
        let _was_in = self
625
0
            .chains_by_protocol_info
626
0
            .remove(&(chain.genesis_hash, chain.fork_id));
627
0
        debug_assert_eq!(_was_in, Some(chain_id.0));
628
629
0
        Ok(chain.user_data)
630
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE12remove_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE12remove_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE12remove_chainB24_
631
632
    /// Modifies the best block of the local node for the given chain. See
633
    /// [`ChainConfig::best_hash`] and [`ChainConfig::best_number`].
634
    ///
635
    /// This information is sent to remotes whenever a block announces substream is opened.
636
    ///
637
    /// # Panic
638
    ///
639
    /// Panics if the [`ChainId`] is out of range.
640
    ///
641
21
    pub fn set_chain_local_best_block(
642
21
        &mut self,
643
21
        chain_id: ChainId,
644
21
        best_hash: [u8; 32],
645
21
        best_number: u64,
646
21
    ) {
647
21
        let chain = &mut self.chains[chain_id.0];
648
21
        chain.best_hash = best_hash;
649
21
        chain.best_number = best_number;
650
21
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE26set_chain_local_best_blockB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE26set_chain_local_best_blockB19_
Line
Count
Source
641
21
    pub fn set_chain_local_best_block(
642
21
        &mut self,
643
21
        chain_id: ChainId,
644
21
        best_hash: [u8; 32],
645
21
        best_number: u64,
646
21
    ) {
647
21
        let chain = &mut self.chains[chain_id.0];
648
21
        chain.best_hash = best_hash;
649
21
        chain.best_number = best_number;
650
21
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE26set_chain_local_best_blockB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE26set_chain_local_best_blockB24_
651
652
    /// Returns the list of all the chains that have been added.
653
234
    pub fn chains(&self) -> impl ExactSizeIterator<Item = ChainId> {
654
234
        self.chains.iter().map(|(idx, _)| ChainId(idx))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE6chains0Bb_
_RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE6chains0B1b_
Line
Count
Source
654
234
        self.chains.iter().map(|(idx, _)| ChainId(idx))
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE6chains0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE6chains0B26_
655
234
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE6chainsB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE6chainsB19_
Line
Count
Source
653
234
    pub fn chains(&self) -> impl ExactSizeIterator<Item = ChainId> {
654
234
        self.chains.iter().map(|(idx, _)| ChainId(idx))
655
234
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE6chainsB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE6chainsB24_
656
657
    /// Returns the value passed as [`ChainConfig::block_number_bytes`] for the given chain.
658
    ///
659
    /// # Panic
660
    ///
661
    /// Panics if the given [`ChainId`] is invalid.
662
    ///
663
0
    pub fn block_number_bytes(&self, chain_id: ChainId) -> usize {
664
0
        self.chains[chain_id.0].block_number_bytes
665
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE18block_number_bytesB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18block_number_bytesB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE18block_number_bytesB9_
666
667
    /// Marks the given chain-peer combination as "desired".
668
    ///
669
    /// Has no effect if it was already marked as desired.
670
    ///
671
    /// Returns `true` if the peer has been marked as desired, and `false` if it was already
672
    /// marked as desired.
673
    ///
674
    /// # Panic
675
    ///
676
    /// Panics if the given [`ChainId`] is invalid.
677
    ///
678
0
    pub fn gossip_insert_desired(
679
0
        &mut self,
680
0
        chain_id: ChainId,
681
0
        peer_id: PeerId,
682
0
        kind: GossipKind,
683
0
    ) -> bool {
684
0
        assert!(self.chains.contains(chain_id.0));
685
686
0
        let peer_index = self.peer_index_or_insert(peer_id);
687
688
0
        if !self
689
0
            .gossip_desired_peers_by_chain
690
0
            .insert((chain_id.0, kind, peer_index))
691
        {
692
            // Return if already marked as desired, as there's nothing more to update.
693
            // Note that this doesn't cover the possibility where the peer was desired with
694
            // another chain.
695
0
            return false;
696
0
        }
697
698
0
        let _was_inserted = self
699
0
            .gossip_desired_peers
700
0
            .insert((peer_index, kind, chain_id.0));
701
0
        debug_assert!(_was_inserted);
702
703
0
        self.opened_gossip_undesired
704
0
            .remove(&(chain_id, peer_index, kind));
705
706
        //  Add either to `unconnected_desired` or to `connected_unopened_gossip_desired`,
707
        // depending on the situation.
708
0
        if self
709
0
            .connections_by_peer_id
710
0
            .range((peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX))
711
0
            .any(|(_, connection_id)| {
712
0
                let state = self.inner.connection_state(*connection_id);
713
0
                state.established && !state.shutting_down
714
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE21gossip_insert_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE21gossip_insert_desired0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE21gossip_insert_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE21gossip_insert_desired0B26_
715
        {
716
0
            if self
717
0
                .notification_substreams_by_peer_id
718
0
                .range(
719
0
                    (
720
0
                        NotificationsProtocol::BlockAnnounces {
721
0
                            chain_index: chain_id.0,
722
0
                        },
723
0
                        peer_index,
724
0
                        SubstreamDirection::Out,
725
0
                        NotificationsSubstreamState::MIN,
726
0
                        SubstreamId::MIN,
727
0
                    )
728
0
                        ..=(
729
0
                            NotificationsProtocol::BlockAnnounces {
730
0
                                chain_index: chain_id.0,
731
0
                            },
732
0
                            peer_index,
733
0
                            SubstreamDirection::Out,
734
0
                            NotificationsSubstreamState::MAX,
735
0
                            SubstreamId::MAX,
736
0
                        ),
737
0
                )
738
0
                .next()
739
0
                .is_none()
740
            {
741
0
                let _was_inserted = self
742
0
                    .connected_unopened_gossip_desired
743
0
                    .insert((peer_index, chain_id, kind));
744
0
                debug_assert!(_was_inserted);
745
0
            }
746
0
        }
747
748
0
        if !self
749
0
            .connections_by_peer_id
750
0
            .range((peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX))
751
0
            .any(|(_, connection_id)| {
752
0
                let state = self.inner.connection_state(*connection_id);
753
0
                !state.shutting_down
754
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE21gossip_insert_desireds_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE21gossip_insert_desireds_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE21gossip_insert_desireds_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE21gossip_insert_desireds_0B26_
755
0
        {
756
0
            // Note that that `PeerId` might already be desired towards a different chain, in
757
0
            // which case it is already present in `unconnected_desired`.
758
0
            self.unconnected_desired.insert(peer_index);
759
0
        }
760
761
0
        true
762
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE21gossip_insert_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE21gossip_insert_desiredB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE21gossip_insert_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE21gossip_insert_desiredB24_
763
764
    /// Removes the given chain-peer combination from the list of desired chain-peers.
765
    ///
766
    /// Has no effect if it was not marked as desired.
767
    ///
768
    /// Returns `true` if the peer was desired on this chain.
769
    ///
770
    /// # Panic
771
    ///
772
    /// Panics if the given [`ChainId`] is invalid.
773
    ///
774
0
    pub fn gossip_remove_desired(
775
0
        &mut self,
776
0
        chain_id: ChainId,
777
0
        peer_id: &PeerId,
778
0
        kind: GossipKind,
779
0
    ) -> bool {
780
0
        assert!(self.chains.contains(chain_id.0));
781
782
0
        let Some(&peer_index) = self.peers_by_peer_id.get(peer_id) else {
783
            // If the `PeerId` is unknown, then it wasn't marked as desired.
784
0
            return false;
785
        };
786
787
0
        self.gossip_remove_desired_inner(chain_id, peer_index, kind)
788
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE21gossip_remove_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE21gossip_remove_desiredB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE21gossip_remove_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE21gossip_remove_desiredB24_
789
790
0
    fn gossip_remove_desired_inner(
791
0
        &mut self,
792
0
        chain_id: ChainId,
793
0
        peer_index: PeerIndex,
794
0
        kind: GossipKind,
795
0
    ) -> bool {
796
0
        if !self
797
0
            .gossip_desired_peers_by_chain
798
0
            .remove(&(chain_id.0, kind, peer_index))
799
        {
800
            // Return if wasn't marked as desired, as there's nothing more to update.
801
0
            return false;
802
0
        }
803
804
0
        self.gossip_desired_peers
805
0
            .remove(&(peer_index, kind, chain_id.0));
806
807
0
        self.connected_unopened_gossip_desired
808
0
            .remove(&(peer_index, chain_id, kind));
809
810
0
        if self
811
0
            .gossip_desired_peers
812
0
            .range((peer_index, kind, usize::MIN)..=(peer_index, kind, usize::MAX))
813
0
            .next()
814
0
            .is_none()
815
0
        {
816
0
            self.unconnected_desired.remove(&peer_index);
817
0
        }
818
819
0
        if self
820
0
            .notification_substreams_by_peer_id
821
0
            .range(
822
0
                (
823
0
                    NotificationsProtocol::BlockAnnounces {
824
0
                        chain_index: chain_id.0,
825
0
                    },
826
0
                    peer_index,
827
0
                    SubstreamDirection::Out,
828
0
                    NotificationsSubstreamState::MIN,
829
0
                    SubstreamId::MIN,
830
0
                )
831
0
                    ..=(
832
0
                        NotificationsProtocol::BlockAnnounces {
833
0
                            chain_index: chain_id.0,
834
0
                        },
835
0
                        peer_index,
836
0
                        SubstreamDirection::Out,
837
0
                        NotificationsSubstreamState::MAX,
838
0
                        SubstreamId::MAX,
839
0
                    ),
840
0
            )
841
0
            .next()
842
0
            .is_some()
843
        {
844
0
            let _was_inserted = self
845
0
                .opened_gossip_undesired
846
0
                .insert((chain_id, peer_index, kind));
847
0
            debug_assert!(_was_inserted);
848
0
        }
849
850
0
        self.try_clean_up_peer(peer_index);
851
852
0
        true
853
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE27gossip_remove_desired_innerB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE27gossip_remove_desired_innerB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE27gossip_remove_desired_innerB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE27gossip_remove_desired_innerB24_
854
855
    /// Removes the given peer from the list of desired chain-peers of all the chains that exist.
856
    ///
857
    /// Has no effect if it was not marked as desired.
858
0
    pub fn gossip_remove_desired_all(&mut self, peer_id: &PeerId, kind: GossipKind) {
859
0
        let Some(&peer_index) = self.peers_by_peer_id.get(peer_id) else {
860
            // If the `PeerId` is unknown, then it wasn't marked as desired.
861
0
            return;
862
        };
863
864
0
        let chains = {
865
            // TODO: this works only because there's only one GossipKind
866
0
            let mut chains_and_after =
867
0
                self.gossip_desired_peers
868
0
                    .split_off(&(peer_index, kind, usize::MIN));
869
0
            let mut chains_after =
870
0
                chains_and_after.split_off(&(PeerIndex(peer_index.0 + 1), kind, usize::MIN));
871
0
            self.gossip_desired_peers.append(&mut chains_after);
872
0
            chains_and_after
873
        };
874
875
0
        for (_removed_peer_index, _, chain_index) in chains {
876
0
            debug_assert_eq!(_removed_peer_index, peer_index);
877
0
            let _was_in =
878
0
                self.gossip_desired_peers_by_chain
879
0
                    .remove(&(chain_index, kind, peer_index));
880
0
            debug_assert!(_was_in);
881
0
            self.connected_unopened_gossip_desired.remove(&(
882
0
                peer_index,
883
0
                ChainId(chain_index),
884
0
                kind,
885
0
            ));
886
        }
887
888
0
        self.unconnected_desired.remove(&peer_index);
889
0
        self.try_clean_up_peer(peer_index);
890
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE25gossip_remove_desired_allB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE25gossip_remove_desired_allB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE25gossip_remove_desired_allB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE25gossip_remove_desired_allB24_
891
892
    /// Returns the list of gossip-desired peers for the given chain, in no specific order.
893
    ///
894
    /// # Panic
895
    ///
896
    /// Panics if the given [`ChainId`] is invalid.
897
    ///
898
138
    pub fn gossip_desired_iter(
899
138
        &self,
900
138
        chain_id: ChainId,
901
138
        kind: GossipKind,
902
138
    ) -> impl Iterator<Item = &PeerId> {
903
138
        self.gossip_desired_peers_by_chain
904
138
            .range(
905
138
                (chain_id.0, kind, PeerIndex(usize::MIN))
906
138
                    ..=(chain_id.0, kind, PeerIndex(usize::MAX)),
907
            )
908
138
            .map(|(_, _, peer_index)| &
self.peers[peer_index.0]0
)
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE19gossip_desired_iter0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE19gossip_desired_iter0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE19gossip_desired_iter0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE19gossip_desired_iter0B26_
909
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE19gossip_desired_iterB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE19gossip_desired_iterB19_
Line
Count
Source
898
138
    pub fn gossip_desired_iter(
899
138
        &self,
900
138
        chain_id: ChainId,
901
138
        kind: GossipKind,
902
138
    ) -> impl Iterator<Item = &PeerId> {
903
138
        self.gossip_desired_peers_by_chain
904
138
            .range(
905
138
                (chain_id.0, kind, PeerIndex(usize::MIN))
906
138
                    ..=(chain_id.0, kind, PeerIndex(usize::MAX)),
907
            )
908
138
            .map(|(_, _, peer_index)| &self.peers[peer_index.0])
909
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE19gossip_desired_iterB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE19gossip_desired_iterB24_
910
911
    /// Returns the number of gossip-desired peers for the given chain.
912
    ///
913
    /// # Panic
914
    ///
915
    /// Panics if the given [`ChainId`] is invalid.
916
    ///
917
138
    pub fn gossip_desired_num(&self, chain_id: ChainId, kind: GossipKind) -> usize {
918
138
        self.gossip_desired_iter(chain_id, kind).count()
919
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE18gossip_desired_numB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18gossip_desired_numB19_
Line
Count
Source
917
138
    pub fn gossip_desired_num(&self, chain_id: ChainId, kind: GossipKind) -> usize {
918
138
        self.gossip_desired_iter(chain_id, kind).count()
919
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE18gossip_desired_numB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18gossip_desired_numB24_
920
921
    /// Returns the list of [`PeerId`]s that are desired (for any chain) but for which no
922
    /// connection exists.
923
    ///
924
    /// > **Note**: Connections that are currently in the process of shutting down are also
925
    /// >           ignored for the purpose of this function.
926
138
    pub fn unconnected_desired(&self) -> impl ExactSizeIterator<Item = &PeerId> + Clone {
927
138
        self.unconnected_desired
928
138
            .iter()
929
138
            .map(|peer_index| &
self.peers[peer_index.0]0
)
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE19unconnected_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE19unconnected_desired0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE19unconnected_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE19unconnected_desired0B26_
930
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE19unconnected_desiredB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE19unconnected_desiredB19_
Line
Count
Source
926
138
    pub fn unconnected_desired(&self) -> impl ExactSizeIterator<Item = &PeerId> + Clone {
927
138
        self.unconnected_desired
928
138
            .iter()
929
138
            .map(|peer_index| &self.peers[peer_index.0])
930
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE19unconnected_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE19unconnected_desiredB24_
931
932
    /// Returns the list of [`PeerId`]s that are marked as desired, and for which a healthy
933
    /// connection exists, but for which no substream connection attempt exists.
934
138
    pub fn connected_unopened_gossip_desired(
935
138
        &self,
936
138
    ) -> impl ExactSizeIterator<Item = (&PeerId, ChainId, GossipKind)> + Clone {
937
138
        self.connected_unopened_gossip_desired.iter().map(
938
0
            move |(peer_index, chain_id, gossip_kind)| {
939
0
                (&self.peers[peer_index.0], *chain_id, *gossip_kind)
940
0
            },
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE33connected_unopened_gossip_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE33connected_unopened_gossip_desired0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE33connected_unopened_gossip_desired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE33connected_unopened_gossip_desired0B26_
941
        )
942
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE33connected_unopened_gossip_desiredB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE33connected_unopened_gossip_desiredB19_
Line
Count
Source
934
138
    pub fn connected_unopened_gossip_desired(
935
138
        &self,
936
138
    ) -> impl ExactSizeIterator<Item = (&PeerId, ChainId, GossipKind)> + Clone {
937
138
        self.connected_unopened_gossip_desired.iter().map(
938
            move |(peer_index, chain_id, gossip_kind)| {
939
                (&self.peers[peer_index.0], *chain_id, *gossip_kind)
940
            },
941
        )
942
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE33connected_unopened_gossip_desiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE33connected_unopened_gossip_desiredB24_
943
944
    /// Returns the list of [`PeerId`]s for which a substream connection or connection attempt
945
    /// exists but that are not marked as desired.
946
0
    pub fn opened_gossip_undesired(
947
0
        &self,
948
0
    ) -> impl ExactSizeIterator<Item = (&PeerId, ChainId, GossipKind)> + Clone {
949
0
        self.opened_gossip_undesired
950
0
            .iter()
951
0
            .map(move |(chain_id, peer_index, gossip_kind)| {
952
0
                (&self.peers[peer_index.0], *chain_id, *gossip_kind)
953
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE23opened_gossip_undesired0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE23opened_gossip_undesired0Bb_
954
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE23opened_gossip_undesiredB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE23opened_gossip_undesiredB9_
955
956
    /// Returns the list of [`PeerId`]s for which a substream connection or connection attempt
957
    /// exists against the given chain but that are not marked as desired.
958
    ///
959
    /// # Panic
960
    ///
961
    /// Panics if the [`ChainId`] is invalid.
962
    ///
963
0
    pub fn opened_gossip_undesired_by_chain(
964
0
        &self,
965
0
        chain_id: ChainId,
966
0
    ) -> impl Iterator<Item = (&PeerId, GossipKind)> + Clone {
967
        // TODO: optimize and add an ExactSizeIterator bound to the return value, and update the users to use len() instead of count()
968
0
        self.opened_gossip_undesired
969
0
            .iter()
970
0
            .filter(move |(c, _, _)| *c == chain_id)
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE32opened_gossip_undesired_by_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32opened_gossip_undesired_by_chain0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE32opened_gossip_undesired_by_chain0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32opened_gossip_undesired_by_chain0B26_
971
0
            .map(move |(_, peer_index, gossip_kind)| (&self.peers[peer_index.0], *gossip_kind))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE32opened_gossip_undesired_by_chains_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32opened_gossip_undesired_by_chains_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE32opened_gossip_undesired_by_chains_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32opened_gossip_undesired_by_chains_0B26_
972
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE32opened_gossip_undesired_by_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32opened_gossip_undesired_by_chainB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE32opened_gossip_undesired_by_chainB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32opened_gossip_undesired_by_chainB24_
973
974
    /// Adds a single-stream connection to the state machine.
975
    ///
976
    /// This connection hasn't finished handshaking and the [`PeerId`] of the remote isn't known
977
    /// yet.
978
    ///
979
    /// If `expected_peer_id` is `Some`, this connection is expected to reach the given [`PeerId`].
980
    /// The `expected_peer_id` is only used to influence the result of
981
    /// [`ChainNetwork::unconnected_desired`].
982
    ///
983
    /// Must be passed the moment (as a `TNow`) when the connection has first been opened, in
984
    /// order to determine when the handshake timeout expires.
985
    ///
986
    /// The `remote_addr` is the multiaddress used to reach back the remote. In the case of TCP, it
987
    /// contains the TCP dialing port of the remote. The remote can ask, through the `identify`
988
    /// libp2p protocol, its own address, in which case we send it. Because the multiaddress
989
    /// specification is flexible, this module doesn't attempt to parse the address.
990
0
    pub fn add_single_stream_connection(
991
0
        &mut self,
992
0
        when_connection_start: TNow,
993
0
        handshake_kind: SingleStreamHandshakeKind,
994
0
        remote_addr: Vec<u8>,
995
0
        expected_peer_id: Option<PeerId>,
996
0
        user_data: TConn,
997
0
    ) -> (ConnectionId, SingleStreamConnectionTask<TNow>) {
998
0
        let substreams_capacity = 16; // TODO: ?
999
0
        let ed25519_public_key = match handshake_kind {
1000
0
            SingleStreamHandshakeKind::MultistreamSelectNoiseYamux { noise_key, .. } => {
1001
0
                *noise_key.libp2p_public_ed25519_key()
1002
            }
1003
        };
1004
0
        let expected_peer_index =
1005
0
            expected_peer_id.map(|peer_id| self.peer_index_or_insert(peer_id));
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE28add_single_stream_connection0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE28add_single_stream_connection0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE28add_single_stream_connection0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE28add_single_stream_connection0B26_
1006
0
        let (id, task) = self.inner.insert_single_stream(
1007
0
            when_connection_start,
1008
0
            handshake_kind,
1009
0
            substreams_capacity,
1010
0
            ConnectionInfo {
1011
0
                address: remote_addr,
1012
0
                ed25519_public_key,
1013
0
                peer_index: expected_peer_index,
1014
0
                user_data,
1015
0
            },
1016
0
        );
1017
0
        if let Some(expected_peer_index) = expected_peer_index {
1018
0
            self.unconnected_desired.remove(&expected_peer_index);
1019
0
            self.connections_by_peer_id
1020
0
                .insert((expected_peer_index, id));
1021
0
        }
1022
0
        (id, task)
1023
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE28add_single_stream_connectionB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE28add_single_stream_connectionB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE28add_single_stream_connectionB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE28add_single_stream_connectionB24_
1024
1025
    /// Adds a multi-stream connection to the state machine.
1026
    ///
1027
    /// This connection hasn't finished handshaking and the [`PeerId`] of the remote isn't known
1028
    /// yet.
1029
    ///
1030
    /// If `expected_peer_id` is `Some`, this connection is expected to reach the given [`PeerId`].
1031
    /// The `expected_peer_id` is only used to influence the result of
1032
    /// [`ChainNetwork::unconnected_desired`].
1033
    ///
1034
    /// Must be passed the moment (as a `TNow`) when the connection has first been opened, in
1035
    /// order to determine when the handshake timeout expires.
1036
    ///
1037
    /// The `remote_addr` is the multiaddress used to reach back the remote. In the case of TCP, it
1038
    /// contains the TCP dialing port of the remote. The remote can ask, through the `identify`
1039
    /// libp2p protocol, its own address, in which case we send it. Because the multiaddress
1040
    /// specification is flexible, this module doesn't attempt to parse the address.
1041
0
    pub fn add_multi_stream_connection<TSubId>(
1042
0
        &mut self,
1043
0
        when_connection_start: TNow,
1044
0
        handshake_kind: MultiStreamHandshakeKind,
1045
0
        remote_addr: Vec<u8>,
1046
0
        expected_peer_id: Option<PeerId>,
1047
0
        user_data: TConn,
1048
0
    ) -> (ConnectionId, MultiStreamConnectionTask<TNow, TSubId>)
1049
0
    where
1050
0
        TSubId: Clone + PartialEq + Eq + Hash,
1051
    {
1052
0
        let substreams_capacity = 16; // TODO: ?
1053
0
        let ed25519_public_key = match handshake_kind {
1054
0
            MultiStreamHandshakeKind::WebRtc { noise_key, .. } => {
1055
0
                *noise_key.libp2p_public_ed25519_key()
1056
            }
1057
        };
1058
0
        let expected_peer_index =
1059
0
            expected_peer_id.map(|peer_id| self.peer_index_or_insert(peer_id));
Unexecuted instantiation: _RNCINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB8_12ChainNetworkpppE27add_multi_stream_connectionpE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkpppE27add_multi_stream_connectionpE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBc_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE27add_multi_stream_connectionjE0B27_
1060
0
        let (id, task) = self.inner.insert_multi_stream(
1061
0
            when_connection_start,
1062
0
            handshake_kind,
1063
0
            substreams_capacity,
1064
0
            ConnectionInfo {
1065
0
                address: remote_addr,
1066
0
                peer_index: expected_peer_index,
1067
0
                ed25519_public_key,
1068
0
                user_data,
1069
0
            },
1070
0
        );
1071
0
        if let Some(expected_peer_index) = expected_peer_index {
1072
0
            self.unconnected_desired.remove(&expected_peer_index);
1073
0
            self.connections_by_peer_id
1074
0
                .insert((expected_peer_index, id));
1075
0
        }
1076
0
        (id, task)
1077
0
    }
Unexecuted instantiation: _RINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB6_12ChainNetworkpppE27add_multi_stream_connectionpEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkpppE27add_multi_stream_connectionpEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBa_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE27add_multi_stream_connectionjEB25_
1078
1079
    /// Returns the number of connections, both handshaking or established.
1080
0
    pub fn num_connections(&self) -> usize {
1081
0
        self.inner.len()
1082
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE15num_connectionsB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE15num_connectionsB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE15num_connectionsB9_
1083
1084
    /// Returns the remote address that was passed to [`ChainNetwork::add_single_stream_connection`]
1085
    /// or [`ChainNetwork::add_multi_stream_connection`] for the given connection.
1086
    ///
1087
    /// > **Note**: This module does in no way attempt to parse the address. This function simply
1088
    /// >           returns the value that was provided by the API user, whatever it is.
1089
    ///
1090
    /// # Panic
1091
    ///
1092
    /// Panics if the [`ConnectionId`] is invalid.
1093
    ///
1094
0
    pub fn connection_remote_addr(&self, id: ConnectionId) -> &[u8] {
1095
0
        &self.inner[id].address
1096
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE22connection_remote_addrB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE22connection_remote_addrB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE22connection_remote_addrB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE22connection_remote_addrB24_
1097
1098
    /// Returns the number of connections with the given peer.
1099
    ///
1100
    /// Both connections that have and have not finished their handshaking phase are considered.
1101
0
    pub fn num_potential_and_established_connections(&self, peer_id: &PeerId) -> usize {
1102
0
        let Some(&peer_index) = self.peers_by_peer_id.get(peer_id) else {
1103
0
            return 0;
1104
        };
1105
1106
0
        self.connections_by_peer_id
1107
0
            .range((peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX))
1108
0
            .count()
1109
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE41num_potential_and_established_connectionsB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE41num_potential_and_established_connectionsB9_
1110
1111
    /// Pulls a message that must be sent to a connection.
1112
    ///
1113
    /// The message must be passed to [`SingleStreamConnectionTask::inject_coordinator_message`]
1114
    /// or [`MultiStreamConnectionTask::inject_coordinator_message`] in the appropriate connection.
1115
    ///
1116
    /// This function guarantees that the [`ConnectionId`] always refers to a connection that
1117
    /// is still alive, in the sense that [`SingleStreamConnectionTask::inject_coordinator_message`]
1118
    /// or [`MultiStreamConnectionTask::inject_coordinator_message`] has never returned `None`
1119
    /// and that no [`Event::Disconnected`] or [`Event::PreHandshakeDisconnected`] has been
1120
    /// generated for this connection.
1121
138
    pub fn pull_message_to_connection(
1122
138
        &mut self,
1123
138
    ) -> Option<(ConnectionId, CoordinatorToConnection)> {
1124
138
        self.inner.pull_message_to_connection()
1125
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE26pull_message_to_connectionB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE26pull_message_to_connectionB19_
Line
Count
Source
1121
138
    pub fn pull_message_to_connection(
1122
138
        &mut self,
1123
138
    ) -> Option<(ConnectionId, CoordinatorToConnection)> {
1124
138
        self.inner.pull_message_to_connection()
1125
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE26pull_message_to_connectionB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE26pull_message_to_connectionB24_
1126
1127
    /// Injects into the state machine a message generated by
1128
    /// [`SingleStreamConnectionTask::pull_message_to_coordinator`] or
1129
    /// [`MultiStreamConnectionTask::pull_message_to_coordinator`].
1130
0
    pub fn inject_connection_message(
1131
0
        &mut self,
1132
0
        connection_id: ConnectionId,
1133
0
        message: ConnectionToCoordinator,
1134
0
    ) {
1135
0
        self.inner.inject_connection_message(connection_id, message)
1136
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE25inject_connection_messageB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE25inject_connection_messageB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE25inject_connection_messageB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE25inject_connection_messageB24_
1137
1138
    /// Returns the next event produced by the service.
1139
138
    pub fn next_event(&mut self) -> Option<Event<TConn>> {
1140
        loop {
1141
138
            let 
inner_event0
= self.inner.next_event()?;
1142
0
            match inner_event {
1143
                collection::Event::HandshakeFinished {
1144
0
                    id,
1145
0
                    peer_id: actual_peer_id,
1146
                } => {
1147
                    // A handshaking connection has finished its handshake. We must update `self`
1148
                    // and return an event.
1149
                    // What makes this a bit complicated is the possibility that the actual PeerId
1150
                    // might not be the same as the one that was expected.
1151
1152
0
                    let actual_peer_index = self.peer_index_or_insert(actual_peer_id);
1153
0
                    let expected_peer_index = self.inner[id].peer_index;
1154
1155
0
                    match expected_peer_index {
1156
0
                        None => {
1157
0
                            // The connection didn't have any expected PeerId.
1158
0
                            self.inner[id].peer_index = Some(actual_peer_index);
1159
0
                            self.unconnected_desired.remove(&actual_peer_index);
1160
0
                        }
1161
0
                        Some(expected_peer_index) if expected_peer_index != actual_peer_index => {
1162
                            // The actual PeerId doesn't match the expected PeerId.
1163
1164
                            // Update the connection owner.
1165
0
                            self.inner[id].peer_index = Some(actual_peer_index);
1166
0
                            let _was_removed = self
1167
0
                                .connections_by_peer_id
1168
0
                                .remove(&(expected_peer_index, id));
1169
0
                            debug_assert!(_was_removed);
1170
0
                            let _was_inserted =
1171
0
                                self.connections_by_peer_id.insert((actual_peer_index, id));
1172
0
                            debug_assert!(_was_inserted);
1173
1174
                            // Update `unconnected_desired`.
1175
0
                            self.unconnected_desired.remove(&actual_peer_index);
1176
0
                            if self
1177
0
                                .gossip_desired_peers
1178
0
                                .range(
1179
0
                                    (
1180
0
                                        expected_peer_index,
1181
0
                                        GossipKind::ConsensusTransactions,
1182
0
                                        usize::MIN,
1183
0
                                    )
1184
0
                                        ..=(
1185
0
                                            expected_peer_index,
1186
0
                                            GossipKind::ConsensusTransactions,
1187
0
                                            usize::MAX,
1188
0
                                        ),
1189
0
                                )
1190
0
                                .next()
1191
0
                                .is_some()
1192
0
                                && !self
1193
0
                                    .connections_by_peer_id
1194
0
                                    .range(
1195
0
                                        (expected_peer_index, ConnectionId::MIN)
1196
0
                                            ..=(expected_peer_index, ConnectionId::MAX),
1197
0
                                    )
1198
0
                                    .any(|(_, connection_id)| {
1199
0
                                        let state = self.inner.connection_state(*connection_id);
1200
0
                                        !state.shutting_down
1201
0
                                    })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_event0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_event0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_event0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_event0B26_
1202
                            {
1203
0
                                let _was_inserted =
1204
0
                                    self.unconnected_desired.insert(expected_peer_index);
1205
0
                                debug_assert!(_was_inserted);
1206
0
                            }
1207
                        }
1208
                        _ => {
1209
                            // Expected matches actual.
1210
0
                            debug_assert_eq!(expected_peer_index, Some(actual_peer_index));
1211
                        }
1212
                    }
1213
1214
                    // TODO: limit the number of connections per peer?
1215
1216
                    // Insert the new connection in `self.connected_unopened_gossip_desired`
1217
                    // if relevant.
1218
0
                    for (_, _, chain_id) in self.gossip_desired_peers.range(
1219
0
                        (
1220
0
                            actual_peer_index,
1221
0
                            GossipKind::ConsensusTransactions,
1222
0
                            usize::MIN,
1223
0
                        )
1224
0
                            ..=(
1225
0
                                actual_peer_index,
1226
0
                                GossipKind::ConsensusTransactions,
1227
0
                                usize::MAX,
1228
0
                            ),
1229
                    ) {
1230
0
                        if self
1231
0
                            .notification_substreams_by_peer_id
1232
0
                            .range(
1233
0
                                (
1234
0
                                    NotificationsProtocol::BlockAnnounces {
1235
0
                                        chain_index: *chain_id,
1236
0
                                    },
1237
0
                                    actual_peer_index,
1238
0
                                    SubstreamDirection::Out,
1239
0
                                    NotificationsSubstreamState::MIN,
1240
0
                                    SubstreamId::MIN,
1241
0
                                )
1242
0
                                    ..=(
1243
0
                                        NotificationsProtocol::BlockAnnounces {
1244
0
                                            chain_index: *chain_id,
1245
0
                                        },
1246
0
                                        actual_peer_index,
1247
0
                                        SubstreamDirection::Out,
1248
0
                                        NotificationsSubstreamState::MAX,
1249
0
                                        SubstreamId::MAX,
1250
0
                                    ),
1251
0
                            )
1252
0
                            .next()
1253
0
                            .is_none()
1254
0
                        {
1255
0
                            self.connected_unopened_gossip_desired.insert((
1256
0
                                actual_peer_index,
1257
0
                                ChainId(*chain_id),
1258
0
                                GossipKind::ConsensusTransactions,
1259
0
                            ));
1260
0
                        }
1261
                    }
1262
1263
                    // Try to clean up the expected peer index.
1264
                    // This is done at the very end so that `self` is in a coherent state.
1265
0
                    let expected_peer_id = expected_peer_index.map(|idx| self.peers[idx.0].clone());
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events_0B26_
1266
0
                    if let Some(expected_peer_index) = expected_peer_index {
1267
0
                        if expected_peer_index != actual_peer_index {
1268
0
                            self.try_clean_up_peer(expected_peer_index);
1269
0
                        }
1270
0
                    }
1271
1272
                    // Small sanity check.
1273
0
                    debug_assert!(!self.unconnected_desired.contains(&actual_peer_index));
1274
1275
0
                    return Some(Event::HandshakeFinished {
1276
0
                        id,
1277
0
                        expected_peer_id,
1278
0
                        peer_id: self.peers[actual_peer_index.0].clone(),
1279
0
                    });
1280
                }
1281
1282
0
                collection::Event::PingOutFailed { id }
1283
0
                | collection::Event::StartShutdown { id, .. } => {
1284
                    // A connection has started its shutdown, or must start its shutdown.
1285
1286
                    // We handle a ping failure the same way as a shutdown start, as we react to
1287
                    // a ping failure by starting the shutdown of the connection. Thus, the clean
1288
                    // up phase is the same in both cases.
1289
0
                    if let collection::Event::PingOutFailed { .. } = inner_event {
1290
0
                        self.inner.start_shutdown(id);
1291
0
                    }
1292
1293
                    // TODO: IMPORTANT this event should be turned into `NewOutboundSubstreamsForbidden` and the `reason` removed; see <https://github.com/smol-dot/smoldot/pull/391>
1294
1295
                    // Nothing more to do if the connection is inbound and handshaking.
1296
0
                    let Some(peer_index) = self.inner[id].peer_index else {
1297
0
                        debug_assert!(!self.inner.connection_state(id).established);
1298
0
                        continue;
1299
                    };
1300
1301
                    // If peer is desired, and we have no connection or only shutting down
1302
                    // connections, add peer to `unconnected_desired` and remove it from
1303
                    // `connected_unopened_gossip_desired`.
1304
0
                    if self
1305
0
                        .gossip_desired_peers
1306
0
                        .range(
1307
0
                            (peer_index, GossipKind::ConsensusTransactions, usize::MIN)
1308
0
                                ..=(peer_index, GossipKind::ConsensusTransactions, usize::MAX),
1309
0
                        )
1310
0
                        .count()
1311
0
                        != 0
1312
                    {
1313
0
                        if !self
1314
0
                            .connections_by_peer_id
1315
0
                            .range(
1316
0
                                (peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX),
1317
0
                            )
1318
0
                            .any(|(_, connection_id)| {
1319
0
                                let state = self.inner.connection_state(*connection_id);
1320
0
                                !state.shutting_down
1321
0
                            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events0_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events0_0B26_
1322
0
                        {
1323
0
                            self.unconnected_desired.insert(peer_index);
1324
0
                        }
1325
0
                        if !self
1326
0
                            .connections_by_peer_id
1327
0
                            .range(
1328
0
                                (peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX),
1329
0
                            )
1330
0
                            .any(|(_, connection_id)| {
1331
0
                                let state = self.inner.connection_state(*connection_id);
1332
0
                                state.established && !state.shutting_down
1333
0
                            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events1_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events1_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events1_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events1_0B26_
1334
                        {
1335
0
                            for (_, _, chain_index) in self.gossip_desired_peers.range(
1336
0
                                (peer_index, GossipKind::ConsensusTransactions, usize::MIN)
1337
0
                                    ..=(peer_index, GossipKind::ConsensusTransactions, usize::MAX),
1338
0
                            ) {
1339
0
                                self.connected_unopened_gossip_desired.remove(&(
1340
0
                                    peer_index,
1341
0
                                    ChainId(*chain_index),
1342
0
                                    GossipKind::ConsensusTransactions,
1343
0
                                ));
1344
0
                            }
1345
0
                        }
1346
0
                    }
1347
                }
1348
1349
                collection::Event::Shutdown {
1350
0
                    id,
1351
0
                    was_established,
1352
0
                    user_data: connection_info,
1353
                } => {
1354
                    // A connection has been completely closed.
1355
                    // The underlying state machine guarantees that all the substreams have been
1356
                    // closed beforehand through other events.
1357
1358
0
                    debug_assert!(connection_info.peer_index.is_some() || !was_established);
1359
1360
0
                    let peer_id = connection_info
1361
0
                        .peer_index
1362
0
                        .map(|peer_index| self.peers[peer_index.0].clone());
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events2_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events2_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events2_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events2_0B26_
1363
1364
0
                    if let Some(peer_index) = connection_info.peer_index {
1365
0
                        let _was_removed = self.connections_by_peer_id.remove(&(peer_index, id));
1366
0
                        debug_assert!(_was_removed);
1367
0
                        self.try_clean_up_peer(peer_index);
1368
0
                    }
1369
1370
                    // TODO: IMPORTANT this event should indicate a clean shutdown, a pre-handshake interruption, a protocol error, a reset, etc. and should get a `reason`; see <https://github.com/smol-dot/smoldot/pull/391>
1371
1372
0
                    if was_established {
1373
0
                        return Some(Event::Disconnected {
1374
0
                            id,
1375
0
                            address: connection_info.address,
1376
0
                            peer_id: peer_id.unwrap(),
1377
0
                            user_data: connection_info.user_data,
1378
0
                        });
1379
                    } else {
1380
0
                        return Some(Event::PreHandshakeDisconnected {
1381
0
                            id,
1382
0
                            address: connection_info.address,
1383
0
                            expected_peer_id: peer_id,
1384
0
                            user_data: connection_info.user_data,
1385
0
                        });
1386
                    }
1387
                }
1388
1389
0
                collection::Event::InboundError { .. } => {
1390
0
                    // TODO: report the error for diagnostic purposes, but revisit the concept of "InboundError"
1391
0
                }
1392
1393
                collection::Event::InboundNegotiated {
1394
0
                    id,
1395
0
                    substream_id,
1396
0
                    protocol_name,
1397
                } => {
1398
                    // An inbound substream opened by the remote would like to negotiate the given
1399
                    // protocol. We must decide whether to accept this protocol or instead reject
1400
                    // the substream.
1401
                    // If accepted, we must also save the protocol somewhere in `self` in order to
1402
                    // load it later once things happen on this substream.
1403
0
                    let Ok(protocol) = self.recognize_protocol(&protocol_name) else {
1404
0
                        self.inner.reject_inbound(substream_id);
1405
0
                        continue;
1406
                    };
1407
1408
0
                    let inbound_type = match protocol {
1409
0
                        Protocol::Identify => collection::InboundTy::Request {
1410
0
                            request_max_size: None,
1411
0
                        },
1412
0
                        Protocol::Ping => collection::InboundTy::Ping,
1413
0
                        Protocol::Notifications(NotificationsProtocol::Grandpa { chain_index })
1414
0
                            if self.chains[chain_index].grandpa_protocol_config.is_none() =>
1415
                        {
1416
0
                            self.inner.reject_inbound(substream_id);
1417
0
                            continue;
1418
                        }
1419
0
                        Protocol::Notifications(p) => collection::InboundTy::Notifications {
1420
0
                            max_handshake_size: self.notifications_protocol_max_handshake_size(p),
1421
0
                        },
1422
0
                        Protocol::Sync { chain_index }
1423
0
                            if self.chains[chain_index].allow_inbound_block_requests =>
1424
                        {
1425
0
                            collection::InboundTy::Request {
1426
0
                                request_max_size: Some(1024),
1427
0
                            }
1428
                        }
1429
                        Protocol::Sync { .. } => {
1430
0
                            self.inner.reject_inbound(substream_id);
1431
0
                            continue;
1432
                        }
1433
1434
                        // TODO: the protocols below are not supported yet
1435
                        Protocol::LightUnknown { .. }
1436
                        | Protocol::Kad { .. }
1437
                        | Protocol::SyncWarp { .. }
1438
                        | Protocol::State { .. } => {
1439
0
                            self.inner.reject_inbound(substream_id);
1440
0
                            continue;
1441
                        }
1442
1443
                        Protocol::LightStorage { .. } | Protocol::LightCall { .. } => {
1444
0
                            unreachable!()
1445
                        }
1446
                    };
1447
1448
0
                    self.inner.accept_inbound(substream_id, inbound_type);
1449
1450
0
                    let _prev_value = self.substreams.insert(
1451
0
                        substream_id,
1452
0
                        SubstreamInfo {
1453
0
                            connection_id: id,
1454
0
                            protocol: Some(protocol),
1455
0
                        },
1456
                    );
1457
0
                    debug_assert!(_prev_value.is_none());
1458
                }
1459
1460
                collection::Event::InboundNegotiatedCancel { .. } => {
1461
                    // Because we immediately accept or reject substreams, this event can never
1462
                    // happen.
1463
0
                    unreachable!()
1464
                }
1465
1466
0
                collection::Event::InboundAcceptedCancel { substream_id } => {
1467
                    // An inbound substream has been aborted after having been accepted.
1468
                    // Since we don't report any event to the API user when a substream is
1469
                    // accepted, we have nothing to do but clean up our local state.
1470
0
                    let _was_in = self.substreams.remove(&substream_id);
1471
0
                    debug_assert!(_was_in.is_some());
1472
                }
1473
1474
                collection::Event::Response {
1475
0
                    substream_id,
1476
0
                    response,
1477
                } => {
1478
                    // Received a response to a request in a request-response protocol.
1479
0
                    let substream_info = self
1480
0
                        .substreams
1481
0
                        .remove(&substream_id)
1482
0
                        .unwrap_or_else(|| unreachable!());
1483
0
                    let peer_index = *self.inner[substream_info.connection_id]
1484
0
                        .peer_index
1485
0
                        .as_ref()
1486
0
                        .unwrap_or_else(|| unreachable!());
1487
1488
                    // Decode/verify the response.
1489
0
                    let (response, chain_index) = match substream_info.protocol {
1490
0
                        None => continue,
1491
0
                        Some(Protocol::Identify) => todo!(), // TODO: we don't send identify requests yet, so it's fine to leave this unimplemented
1492
0
                        Some(Protocol::Sync { chain_index, .. }) => (
1493
                            RequestResult::Blocks(
1494
0
                                response.map_err(BlocksRequestError::Request).and_then(
1495
0
                                    |response| {
1496
0
                                        codec::decode_block_response(&response)
1497
0
                                            .map_err(BlocksRequestError::Decode)
1498
0
                                    },
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events5_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events5_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events5_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events5_0B26_
1499
                                ),
1500
                            ),
1501
0
                            chain_index,
1502
                        ),
1503
0
                        Some(Protocol::LightUnknown { .. }) => unreachable!(),
1504
0
                        Some(Protocol::LightStorage { chain_index, .. }) => (
1505
                            RequestResult::StorageProof(
1506
0
                                response
1507
0
                                    .map_err(StorageProofRequestError::Request)
1508
0
                                    .and_then(|payload| {
1509
0
                                        match codec::decode_storage_or_call_proof_response(
1510
0
                                            codec::StorageOrCallProof::StorageProof,
1511
0
                                            &payload,
1512
                                        ) {
1513
0
                                            Err(err) => Err(StorageProofRequestError::Decode(err)),
1514
                                            Ok(None) => {
1515
0
                                                Err(StorageProofRequestError::RemoteCouldntAnswer)
1516
                                            }
1517
0
                                            Ok(Some(_)) => Ok(EncodedMerkleProof(
1518
0
                                                payload,
1519
0
                                                codec::StorageOrCallProof::StorageProof,
1520
0
                                            )),
1521
                                        }
1522
0
                                    }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events6_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events6_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events6_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events6_0B26_
1523
                            ),
1524
0
                            chain_index,
1525
                        ),
1526
0
                        Some(Protocol::LightCall { chain_index, .. }) => (
1527
                            RequestResult::CallProof(
1528
0
                                response.map_err(CallProofRequestError::Request).and_then(
1529
0
                                    |payload| match codec::decode_storage_or_call_proof_response(
1530
0
                                        codec::StorageOrCallProof::CallProof,
1531
0
                                        &payload,
1532
                                    ) {
1533
0
                                        Err(err) => Err(CallProofRequestError::Decode(err)),
1534
0
                                        Ok(None) => Err(CallProofRequestError::RemoteCouldntAnswer),
1535
0
                                        Ok(Some(_)) => Ok(EncodedMerkleProof(
1536
0
                                            payload,
1537
0
                                            codec::StorageOrCallProof::CallProof,
1538
0
                                        )),
1539
0
                                    },
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events7_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events7_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events7_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events7_0B26_
1540
                                ),
1541
                            ),
1542
0
                            chain_index,
1543
                        ),
1544
0
                        Some(Protocol::Kad { chain_index, .. }) => (
1545
                            RequestResult::KademliaFindNode(
1546
0
                                response
1547
0
                                    .map_err(KademliaFindNodeError::RequestFailed)
1548
0
                                    .and_then(|payload| {
1549
0
                                        match codec::decode_find_node_response(&payload) {
1550
0
                                            Err(err) => {
1551
0
                                                Err(KademliaFindNodeError::DecodeError(err))
1552
                                            }
1553
0
                                            Ok(nodes) => Ok(nodes),
1554
                                        }
1555
0
                                    }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events8_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events8_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events8_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events8_0B26_
1556
                            ),
1557
0
                            chain_index,
1558
                        ),
1559
0
                        Some(Protocol::SyncWarp { chain_index }) => (
1560
                            RequestResult::GrandpaWarpSync(
1561
0
                                response
1562
0
                                    .map_err(GrandpaWarpSyncRequestError::Request)
1563
0
                                    .and_then(|message| {
1564
0
                                        if let Err(err) = codec::decode_grandpa_warp_sync_response(
1565
0
                                            &message,
1566
0
                                            self.chains[chain_index].block_number_bytes,
1567
0
                                        ) {
1568
0
                                            Err(GrandpaWarpSyncRequestError::Decode(err))
1569
                                        } else {
1570
0
                                            Ok(EncodedGrandpaWarpSyncResponse {
1571
0
                                                message,
1572
0
                                                block_number_bytes: self.chains[chain_index]
1573
0
                                                    .block_number_bytes,
1574
0
                                            })
1575
                                        }
1576
0
                                    }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events9_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_events9_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_events9_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_events9_0B26_
1577
                            ),
1578
0
                            chain_index,
1579
                        ),
1580
0
                        Some(Protocol::State { chain_index, .. }) => (
1581
                            RequestResult::State(
1582
0
                                response
1583
0
                                    .map_err(StateRequestError::Request)
1584
0
                                    .and_then(|payload| {
1585
0
                                        if let Err(err) = codec::decode_state_response(&payload) {
1586
0
                                            Err(StateRequestError::Decode(err))
1587
                                        } else {
1588
0
                                            Ok(EncodedStateResponse(payload))
1589
                                        }
1590
0
                                    }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsa_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsa_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsa_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsa_0B26_
1591
                            ),
1592
0
                            chain_index,
1593
                        ),
1594
1595
                        // The protocols below aren't request-response protocols.
1596
0
                        Some(Protocol::Ping) | Some(Protocol::Notifications(_)) => unreachable!(),
1597
                    };
1598
1599
0
                    return Some(Event::RequestResult {
1600
0
                        peer_id: self.peers[peer_index.0].clone(),
1601
0
                        chain_id: ChainId(chain_index),
1602
0
                        substream_id,
1603
0
                        response,
1604
0
                    });
1605
                }
1606
1607
                collection::Event::RequestIn {
1608
0
                    substream_id,
1609
0
                    request_payload,
1610
                } => {
1611
                    // Received a request on a request-response protocol.
1612
0
                    let substream_info = self
1613
0
                        .substreams
1614
0
                        .get(&substream_id)
1615
0
                        .unwrap_or_else(|| unreachable!());
1616
0
                    let peer_id = self.peers[self.inner[substream_info.connection_id]
1617
0
                        .peer_index
1618
0
                        .as_ref()
1619
0
                        .unwrap_or_else(|| unreachable!())
1620
                        .0]
1621
0
                        .clone();
1622
1623
0
                    match substream_info.protocol {
1624
0
                        None => {
1625
0
                            // Substream concerns a chain that has been removed.
1626
0
                            let _ = self.substreams.remove(&substream_id);
1627
0
                            self.inner.respond_in_request(substream_id, Err(()));
1628
0
                        }
1629
                        Some(Protocol::Identify) => {
1630
0
                            if request_payload.is_empty() {
1631
0
                                return Some(Event::IdentifyRequestIn {
1632
0
                                    peer_id,
1633
0
                                    substream_id,
1634
0
                                });
1635
                            } else {
1636
                                // TODO: can this actually be reached? isn't the inner code going to refuse a bad request anyway due to no length prefix?
1637
0
                                let _ = self.substreams.remove(&substream_id);
1638
0
                                self.inner.respond_in_request(substream_id, Err(()));
1639
0
                                return Some(Event::ProtocolError {
1640
0
                                    peer_id,
1641
0
                                    error: ProtocolError::BadIdentifyRequest,
1642
0
                                });
1643
                            }
1644
                        }
1645
0
                        Some(Protocol::Sync { chain_index }) => {
1646
0
                            match codec::decode_block_request(
1647
0
                                self.chains[chain_index].block_number_bytes,
1648
0
                                &request_payload,
1649
0
                            ) {
1650
0
                                Ok(config) => {
1651
0
                                    return Some(Event::BlocksRequestIn {
1652
0
                                        peer_id,
1653
0
                                        chain_id: ChainId(chain_index),
1654
0
                                        config,
1655
0
                                        substream_id,
1656
0
                                    });
1657
                                }
1658
0
                                Err(error) => {
1659
0
                                    let _ = self.substreams.remove(&substream_id);
1660
0
                                    self.inner.respond_in_request(substream_id, Err(()));
1661
0
                                    return Some(Event::ProtocolError {
1662
0
                                        peer_id,
1663
0
                                        error: ProtocolError::BadBlocksRequest(error),
1664
0
                                    });
1665
                                }
1666
                            }
1667
                        }
1668
                        // Any other protocol is declined when the protocol is negotiated.
1669
0
                        _ => unreachable!(),
1670
                    }
1671
                }
1672
1673
0
                collection::Event::RequestInCancel { substream_id } => {
1674
                    // The remote has cancelled a previously-emitted request. Propagate this event
1675
                    // to the API user.
1676
0
                    let _was_in = self.substreams.remove(&substream_id);
1677
0
                    debug_assert!(_was_in.is_some());
1678
0
                    return Some(Event::RequestInCancel { substream_id });
1679
                }
1680
1681
                // TODO: this whole block of code is too complex
1682
                collection::Event::NotificationsOutResult {
1683
0
                    substream_id,
1684
0
                    result,
1685
                } => {
1686
                    // Outgoing notifications substream has finished opening.
1687
                    // TODO: this if is pretty hacky
1688
0
                    let substream_info = if result.is_ok() {
1689
0
                        self.substreams
1690
0
                            .get(&substream_id)
1691
0
                            .unwrap_or_else(|| unreachable!())
1692
0
                            .clone()
1693
                    } else {
1694
0
                        self.substreams.remove(&substream_id).unwrap()
1695
                    };
1696
0
                    let connection_id = substream_info.connection_id;
1697
0
                    let peer_index = *self.inner[connection_id]
1698
0
                        .peer_index
1699
0
                        .as_ref()
1700
0
                        .unwrap_or_else(|| unreachable!());
1701
0
                    let Some(Protocol::Notifications(substream_protocol)) = substream_info.protocol
1702
                    else {
1703
                        // All outgoing substream attempts are cancelled when a chain is removed,
1704
                        // as such `protocol` can't be `None`.
1705
0
                        unreachable!();
1706
                    };
1707
1708
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
1709
0
                        substream_protocol,
1710
0
                        peer_index,
1711
0
                        SubstreamDirection::Out,
1712
0
                        NotificationsSubstreamState::Pending,
1713
0
                        substream_id,
1714
0
                    ));
1715
0
                    debug_assert!(_was_in);
1716
1717
                    // The behaviour is very specific to the protocol.
1718
0
                    match substream_protocol {
1719
0
                        NotificationsProtocol::BlockAnnounces { chain_index } => {
1720
                            // Parse the handshake to check whether it's correct.
1721
0
                            let result = match &result {
1722
0
                                Ok(handshake) => {
1723
0
                                    match codec::decode_block_announces_handshake(
1724
0
                                        self.chains[chain_index].block_number_bytes,
1725
0
                                        handshake,
1726
                                    ) {
1727
0
                                        Ok(decoded_handshake)
1728
0
                                            if *decoded_handshake.genesis_hash
1729
0
                                                == self.chains[chain_index].genesis_hash =>
1730
                                        {
1731
0
                                            Ok(decoded_handshake)
1732
                                        }
1733
0
                                        Ok(decoded_handshake) => {
1734
0
                                            Err(GossipConnectError::GenesisMismatch {
1735
0
                                                local_genesis: self.chains[chain_index]
1736
0
                                                    .genesis_hash,
1737
0
                                                remote_genesis: *decoded_handshake.genesis_hash,
1738
0
                                            })
1739
                                        }
1740
0
                                        Err(err) => Err(GossipConnectError::HandshakeDecode(err)),
1741
                                    }
1742
                                }
1743
0
                                Err(err) => Err(GossipConnectError::Substream(err.clone())),
1744
                            };
1745
1746
0
                            match result {
1747
0
                                Ok(decoded_handshake) => {
1748
0
                                    let _was_inserted =
1749
0
                                        self.notification_substreams_by_peer_id.insert((
1750
0
                                            NotificationsProtocol::BlockAnnounces { chain_index },
1751
0
                                            peer_index,
1752
0
                                            SubstreamDirection::Out,
1753
0
                                            NotificationsSubstreamState::Open {
1754
0
                                                asked_to_leave: false,
1755
0
                                            },
1756
0
                                            substream_id,
1757
0
                                        ));
1758
0
                                    debug_assert!(_was_inserted);
1759
1760
0
                                    for other_protocol in
1761
0
                                        iter::once(NotificationsProtocol::Transactions {
1762
0
                                            chain_index,
1763
0
                                        })
1764
0
                                        .chain(
1765
0
                                            self.chains[chain_index]
1766
0
                                                .grandpa_protocol_config
1767
0
                                                .is_some()
1768
0
                                                .then(|| NotificationsProtocol::Grandpa {
1769
0
                                                    chain_index,
1770
0
                                                }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsf_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsf_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsf_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsf_0B26_
1771
                                        )
1772
                                    {
1773
0
                                        if self
1774
0
                                            .notification_substreams_by_peer_id
1775
0
                                            .range(
1776
0
                                                (
1777
0
                                                    other_protocol,
1778
0
                                                    peer_index,
1779
0
                                                    SubstreamDirection::Out,
1780
0
                                                    NotificationsSubstreamState::MIN,
1781
0
                                                    SubstreamId::MIN,
1782
0
                                                )
1783
0
                                                    ..=(
1784
0
                                                        other_protocol,
1785
0
                                                        peer_index,
1786
0
                                                        SubstreamDirection::Out,
1787
0
                                                        NotificationsSubstreamState::MAX,
1788
0
                                                        SubstreamId::MAX,
1789
0
                                                    ),
1790
0
                                            )
1791
0
                                            .next()
1792
0
                                            .is_some()
1793
                                        {
1794
0
                                            continue;
1795
0
                                        }
1796
1797
0
                                        let new_substream_id = self.inner.open_out_notifications(
1798
0
                                            connection_id,
1799
0
                                            codec::encode_protocol_name_string(
1800
0
                                                match other_protocol {
1801
                                                    NotificationsProtocol::Transactions {
1802
0
                                                        chain_index,
1803
0
                                                    } => codec::ProtocolName::Transactions {
1804
0
                                                        genesis_hash: self.chains[chain_index]
1805
0
                                                            .genesis_hash,
1806
0
                                                        fork_id: self.chains[chain_index]
1807
0
                                                            .fork_id
1808
0
                                                            .as_deref(),
1809
0
                                                    },
1810
                                                    NotificationsProtocol::Grandpa {
1811
0
                                                        chain_index,
1812
0
                                                    } => codec::ProtocolName::Grandpa {
1813
0
                                                        genesis_hash: self.chains[chain_index]
1814
0
                                                            .genesis_hash,
1815
0
                                                        fork_id: self.chains[chain_index]
1816
0
                                                            .fork_id
1817
0
                                                            .as_deref(),
1818
0
                                                    },
1819
0
                                                    _ => unreachable!(),
1820
                                                },
1821
                                            ),
1822
0
                                            self.notifications_protocol_handshake_timeout(
1823
0
                                                other_protocol,
1824
                                            ),
1825
0
                                            self.notifications_protocol_handshake(other_protocol),
1826
0
                                            self.notifications_protocol_max_handshake_size(
1827
0
                                                other_protocol,
1828
                                            ),
1829
                                        );
1830
1831
0
                                        self.substreams.insert(
1832
0
                                            new_substream_id,
1833
0
                                            SubstreamInfo {
1834
0
                                                connection_id,
1835
0
                                                protocol: Some(Protocol::Notifications(
1836
0
                                                    other_protocol,
1837
0
                                                )),
1838
0
                                            },
1839
                                        );
1840
1841
0
                                        self.notification_substreams_by_peer_id.insert((
1842
0
                                            other_protocol,
1843
0
                                            peer_index,
1844
0
                                            SubstreamDirection::Out,
1845
0
                                            NotificationsSubstreamState::Pending,
1846
0
                                            new_substream_id,
1847
0
                                        ));
1848
                                    }
1849
1850
0
                                    return Some(Event::GossipConnected {
1851
0
                                        peer_id: self.peers[peer_index.0].clone(),
1852
0
                                        chain_id: ChainId(chain_index),
1853
0
                                        kind: GossipKind::ConsensusTransactions,
1854
0
                                        role: decoded_handshake.role,
1855
0
                                        best_number: decoded_handshake.best_number,
1856
0
                                        best_hash: *decoded_handshake.best_hash,
1857
0
                                    });
1858
                                }
1859
0
                                Err(error) => {
1860
0
                                    if self
1861
0
                                        .connections_by_peer_id
1862
0
                                        .range(
1863
0
                                            (peer_index, ConnectionId::MIN)
1864
0
                                                ..=(peer_index, ConnectionId::MIN),
1865
0
                                        )
1866
0
                                        .any(|(_, c)| {
1867
0
                                            let state = self.inner.connection_state(*c);
1868
0
                                            state.established && !state.shutting_down
1869
0
                                        })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsg_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsg_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsg_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsg_0B26_
1870
0
                                        && self.gossip_desired_peers_by_chain.contains(&(
1871
0
                                            chain_index,
1872
0
                                            GossipKind::ConsensusTransactions,
1873
0
                                            peer_index,
1874
0
                                        ))
1875
                                    {
1876
0
                                        debug_assert!(self
1877
0
                                            .notification_substreams_by_peer_id
1878
0
                                            .range(
1879
0
                                                (
1880
0
                                                    NotificationsProtocol::BlockAnnounces {
1881
0
                                                        chain_index
1882
0
                                                    },
1883
0
                                                    peer_index,
1884
0
                                                    SubstreamDirection::Out,
1885
0
                                                    NotificationsSubstreamState::OPEN_MIN_VALUE,
1886
0
                                                    SubstreamId::MIN,
1887
0
                                                )
1888
0
                                                    ..=(
1889
0
                                                        NotificationsProtocol::BlockAnnounces {
1890
0
                                                            chain_index
1891
0
                                                        },
1892
0
                                                        peer_index,
1893
0
                                                        SubstreamDirection::Out,
1894
0
                                                        NotificationsSubstreamState::OPEN_MAX_VALUE,
1895
0
                                                        SubstreamId::MAX,
1896
0
                                                    ),
1897
0
                                            )
1898
0
                                            .next()
1899
0
                                            .is_none());
1900
1901
0
                                        self.connected_unopened_gossip_desired.insert((
1902
0
                                            peer_index,
1903
0
                                            ChainId(chain_index),
1904
0
                                            GossipKind::ConsensusTransactions,
1905
0
                                        ));
1906
0
                                    }
1907
1908
0
                                    self.opened_gossip_undesired.remove(&(
1909
0
                                        ChainId(chain_index),
1910
0
                                        peer_index,
1911
0
                                        GossipKind::ConsensusTransactions,
1912
0
                                    ));
1913
1914
                                    // TODO: pretty hacky
1915
                                    if let GossipConnectError::HandshakeDecode(_)
1916
0
                                    | GossipConnectError::GenesisMismatch { .. } = error
1917
0
                                    {
1918
0
                                        self.inner.close_out_notifications(substream_id);
1919
0
                                        self.substreams.remove(&substream_id).unwrap();
1920
0
                                    }
1921
1922
                                    // Close all the notification substreams of that chain.
1923
0
                                    for other_protocol in [
1924
0
                                        NotificationsProtocol::BlockAnnounces { chain_index },
1925
0
                                        NotificationsProtocol::Transactions { chain_index },
1926
0
                                        NotificationsProtocol::Grandpa { chain_index },
1927
                                    ] {
1928
0
                                        for (substream_id, direction, state) in self
1929
0
                                            .notification_substreams_by_peer_id
1930
0
                                            .range(
1931
0
                                                (
1932
0
                                                    other_protocol,
1933
0
                                                    peer_index,
1934
0
                                                    SubstreamDirection::MIN,
1935
0
                                                    NotificationsSubstreamState::MIN,
1936
0
                                                    SubstreamId::MIN,
1937
0
                                                )
1938
0
                                                    ..=(
1939
0
                                                        other_protocol,
1940
0
                                                        peer_index,
1941
0
                                                        SubstreamDirection::MAX,
1942
0
                                                        NotificationsSubstreamState::MAX,
1943
0
                                                        SubstreamId::MAX,
1944
0
                                                    ),
1945
                                            )
1946
0
                                            .map(|(_, _, dir, state, s)| (*s, *dir, *state))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsh_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsh_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsh_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsh_0B26_
1947
0
                                            .collect::<Vec<_>>()
1948
                                        {
1949
0
                                            match (direction, state) {
1950
                                                (SubstreamDirection::Out, _) => {
1951
0
                                                    self.inner
1952
0
                                                        .close_out_notifications(substream_id);
1953
1954
0
                                                    let _was_in = self
1955
0
                                                        .notification_substreams_by_peer_id
1956
0
                                                        .remove(&(
1957
0
                                                            other_protocol,
1958
0
                                                            peer_index,
1959
0
                                                            direction,
1960
0
                                                            state,
1961
0
                                                            substream_id,
1962
0
                                                        ));
1963
0
                                                    debug_assert!(_was_in);
1964
0
                                                    let _was_in =
1965
0
                                                        self.substreams.remove(&substream_id);
1966
0
                                                    debug_assert!(_was_in.is_some());
1967
                                                }
1968
                                                (
1969
                                                    SubstreamDirection::In,
1970
                                                    NotificationsSubstreamState::Pending,
1971
                                                ) => {
1972
0
                                                    self.inner
1973
0
                                                        .reject_in_notifications(substream_id);
1974
1975
0
                                                    let _was_in = self
1976
0
                                                        .notification_substreams_by_peer_id
1977
0
                                                        .remove(&(
1978
0
                                                            other_protocol,
1979
0
                                                            peer_index,
1980
0
                                                            direction,
1981
0
                                                            state,
1982
0
                                                            substream_id,
1983
0
                                                        ));
1984
0
                                                    debug_assert!(_was_in);
1985
0
                                                    let _was_in =
1986
0
                                                        self.substreams.remove(&substream_id);
1987
0
                                                    debug_assert!(_was_in.is_some());
1988
                                                }
1989
                                                (
1990
                                                    SubstreamDirection::In,
1991
                                                    NotificationsSubstreamState::Open {
1992
                                                        asked_to_leave: false,
1993
                                                    },
1994
                                                ) => {
1995
0
                                                    self.inner.start_close_in_notifications(
1996
0
                                                        substream_id,
1997
0
                                                        Duration::from_secs(5),
1998
                                                    ); // TODO: arbitrary constant
1999
2000
0
                                                    let _was_removed = self
2001
0
                                                        .notification_substreams_by_peer_id
2002
0
                                                        .remove(&(
2003
0
                                                            other_protocol,
2004
0
                                                            peer_index,
2005
0
                                                            SubstreamDirection::In,
2006
0
                                                            NotificationsSubstreamState::Open {
2007
0
                                                                asked_to_leave: false,
2008
0
                                                            },
2009
0
                                                            substream_id,
2010
0
                                                        ));
2011
0
                                                    debug_assert!(_was_removed);
2012
0
                                                    let _was_inserted = self
2013
0
                                                        .notification_substreams_by_peer_id
2014
0
                                                        .insert((
2015
0
                                                            other_protocol,
2016
0
                                                            peer_index,
2017
0
                                                            SubstreamDirection::In,
2018
0
                                                            NotificationsSubstreamState::Open {
2019
0
                                                                asked_to_leave: true,
2020
0
                                                            },
2021
0
                                                            substream_id,
2022
0
                                                        ));
2023
0
                                                    debug_assert!(_was_inserted);
2024
                                                }
2025
                                                (
2026
                                                    SubstreamDirection::In,
2027
                                                    NotificationsSubstreamState::Open {
2028
                                                        asked_to_leave: true,
2029
                                                    },
2030
0
                                                ) => {
2031
0
                                                    // Nothing to do.
2032
0
                                                }
2033
                                            }
2034
                                        }
2035
                                    }
2036
2037
0
                                    return Some(Event::GossipOpenFailed {
2038
0
                                        peer_id: self.peers[peer_index.0].clone(),
2039
0
                                        chain_id: ChainId(chain_index),
2040
0
                                        kind: GossipKind::ConsensusTransactions,
2041
0
                                        error,
2042
0
                                    });
2043
                                }
2044
                            }
2045
                        }
2046
2047
0
                        NotificationsProtocol::Transactions { chain_index }
2048
0
                        | NotificationsProtocol::Grandpa { chain_index } => {
2049
                            // TODO: doesn't check the handshakes
2050
2051
                            // This can only happen if we have a block announces substream with
2052
                            // that peer, otherwise the substream opening attempt should have
2053
                            // been cancelled.
2054
0
                            debug_assert!(
2055
0
                                self.notification_substreams_by_peer_id
2056
0
                                    .range(
2057
0
                                        (
2058
0
                                            NotificationsProtocol::BlockAnnounces { chain_index },
2059
0
                                            peer_index,
2060
0
                                            SubstreamDirection::Out,
2061
0
                                            NotificationsSubstreamState::OPEN_MIN_VALUE,
2062
0
                                            SubstreamId::MIN
2063
0
                                        )
2064
0
                                            ..=(
2065
0
                                                NotificationsProtocol::BlockAnnounces {
2066
0
                                                    chain_index
2067
0
                                                },
2068
0
                                                peer_index,
2069
0
                                                SubstreamDirection::Out,
2070
0
                                                NotificationsSubstreamState::OPEN_MAX_VALUE,
2071
0
                                                SubstreamId::MAX
2072
0
                                            )
2073
0
                                    )
2074
0
                                    .next()
2075
0
                                    .is_some()
2076
                            );
2077
2078
                            // If the substream failed to open, we simply try again.
2079
                            // Trying again means that we might be hammering the remote with
2080
                            // substream requests, however as of the writing of this text this is
2081
                            // necessary in order to bypass an issue in Substrate.
2082
                            // Note that in the situation where the connection is shutting down,
2083
                            // we don't re-open the substream on a different connection, but
2084
                            // that's ok as the block announces substream should be closed soon.
2085
0
                            if result.is_err() {
2086
0
                                if self.inner.connection_state(connection_id).shutting_down {
2087
0
                                    continue;
2088
0
                                }
2089
2090
0
                                let new_substream_id = self.inner.open_out_notifications(
2091
0
                                    connection_id,
2092
0
                                    codec::encode_protocol_name_string(match substream_protocol {
2093
                                        NotificationsProtocol::Transactions { .. } => {
2094
0
                                            codec::ProtocolName::Transactions {
2095
0
                                                genesis_hash: self.chains[chain_index].genesis_hash,
2096
0
                                                fork_id: self.chains[chain_index]
2097
0
                                                    .fork_id
2098
0
                                                    .as_deref(),
2099
0
                                            }
2100
                                        }
2101
                                        NotificationsProtocol::Grandpa { .. } => {
2102
0
                                            codec::ProtocolName::Grandpa {
2103
0
                                                genesis_hash: self.chains[chain_index].genesis_hash,
2104
0
                                                fork_id: self.chains[chain_index]
2105
0
                                                    .fork_id
2106
0
                                                    .as_deref(),
2107
0
                                            }
2108
                                        }
2109
0
                                        _ => unreachable!(),
2110
                                    }),
2111
0
                                    self.notifications_protocol_handshake_timeout(
2112
0
                                        substream_protocol,
2113
                                    ),
2114
0
                                    self.notifications_protocol_handshake(substream_protocol),
2115
0
                                    self.notifications_protocol_max_handshake_size(
2116
0
                                        substream_protocol,
2117
                                    ),
2118
                                );
2119
0
                                let _was_inserted =
2120
0
                                    self.notification_substreams_by_peer_id.insert((
2121
0
                                        substream_protocol,
2122
0
                                        peer_index,
2123
0
                                        SubstreamDirection::Out,
2124
0
                                        NotificationsSubstreamState::Pending,
2125
0
                                        new_substream_id,
2126
0
                                    ));
2127
0
                                debug_assert!(_was_inserted);
2128
0
                                let _prev_value = self.substreams.insert(
2129
0
                                    new_substream_id,
2130
0
                                    SubstreamInfo {
2131
0
                                        connection_id,
2132
0
                                        protocol: substream_info.protocol,
2133
0
                                    },
2134
                                );
2135
0
                                debug_assert!(_prev_value.is_none());
2136
0
                                continue;
2137
0
                            }
2138
2139
0
                            let _was_inserted = self.notification_substreams_by_peer_id.insert((
2140
0
                                substream_protocol,
2141
0
                                peer_index,
2142
0
                                SubstreamDirection::Out,
2143
0
                                NotificationsSubstreamState::Open {
2144
0
                                    asked_to_leave: false,
2145
0
                                },
2146
0
                                substream_id,
2147
0
                            ));
2148
0
                            debug_assert!(_was_inserted);
2149
2150
                            // In case of Grandpa, we immediately send a neighbor packet with
2151
                            // the current local state.
2152
0
                            if matches!(substream_protocol, NotificationsProtocol::Grandpa { .. }) {
2153
0
                                let grandpa_state = &self.chains[chain_index]
2154
0
                                    .grandpa_protocol_config
2155
0
                                    .as_ref()
2156
0
                                    .unwrap();
2157
0
                                let packet = codec::GrandpaNotificationRef::Neighbor(
2158
0
                                    codec::NeighborPacket {
2159
0
                                        round_number: grandpa_state.round_number,
2160
0
                                        set_id: grandpa_state.set_id,
2161
0
                                        commit_finalized_height: grandpa_state
2162
0
                                            .commit_finalized_height,
2163
0
                                    },
2164
0
                                )
2165
0
                                .scale_encoding(self.chains[chain_index].block_number_bytes)
2166
0
                                .fold(Vec::new(), |mut a, b| {
2167
0
                                    a.extend_from_slice(b.as_ref());
2168
0
                                    a
2169
0
                                });
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsi_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsi_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsi_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsi_0B26_
2170
0
                                match self.inner.queue_notification(substream_id, packet) {
2171
0
                                    Ok(()) => {}
2172
                                    Err(collection::QueueNotificationError::QueueFull) => {
2173
0
                                        unreachable!()
2174
                                    }
2175
                                }
2176
0
                            }
2177
                        }
2178
                    }
2179
                }
2180
2181
0
                collection::Event::NotificationsOutCloseDemanded { substream_id }
2182
0
                | collection::Event::NotificationsOutReset { substream_id } => {
2183
                    // Outgoing notifications substream has been closed or must be closed.
2184
                    // These two situations are handled together, as we immediately react to a
2185
                    // demanded closing by performing the closing. The rest of the code is thus
2186
                    // the same for both situations.
2187
2188
                    // If the request demands the closing, we immediately comply.
2189
0
                    if matches!(
2190
0
                        inner_event,
2191
                        collection::Event::NotificationsOutCloseDemanded { .. }
2192
0
                    ) {
2193
0
                        self.inner.close_out_notifications(substream_id);
2194
0
                    }
2195
2196
                    // Load various information about the substream and connection.
2197
0
                    let substream_info = self
2198
0
                        .substreams
2199
0
                        .remove(&substream_id)
2200
0
                        .unwrap_or_else(|| unreachable!());
2201
0
                    let connection_id = substream_info.connection_id;
2202
0
                    let peer_index = *self.inner[connection_id]
2203
0
                        .peer_index
2204
0
                        .as_ref()
2205
0
                        .unwrap_or_else(|| unreachable!());
2206
2207
                    // All outgoing substream attempts are cancelled when a chain is removed, as
2208
                    // such `protocol` can't be `None`.
2209
0
                    let Some(Protocol::Notifications(substream_protocol)) = substream_info.protocol
2210
                    else {
2211
0
                        unreachable!();
2212
                    };
2213
2214
                    // Clean up the local state.
2215
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
2216
0
                        substream_protocol,
2217
0
                        peer_index,
2218
0
                        SubstreamDirection::Out,
2219
0
                        NotificationsSubstreamState::Open {
2220
0
                            asked_to_leave: false,
2221
0
                        },
2222
0
                        substream_id,
2223
0
                    ));
2224
0
                    debug_assert!(_was_in);
2225
2226
                    // Rest of the code depends on the protocol.
2227
0
                    match substream_protocol {
2228
0
                        NotificationsProtocol::BlockAnnounces { chain_index } => {
2229
0
                            self.opened_gossip_undesired.remove(&(
2230
0
                                ChainId(chain_index),
2231
0
                                peer_index,
2232
0
                                GossipKind::ConsensusTransactions,
2233
0
                            ));
2234
2235
                            // Insert back in `connected_unopened_gossip_desired` if relevant.
2236
0
                            if self.gossip_desired_peers_by_chain.contains(&(
2237
0
                                chain_index,
2238
0
                                GossipKind::ConsensusTransactions,
2239
0
                                peer_index,
2240
0
                            )) && self
2241
0
                                .connections_by_peer_id
2242
0
                                .range(
2243
0
                                    (peer_index, ConnectionId::MIN)
2244
0
                                        ..=(peer_index, ConnectionId::MAX),
2245
0
                                )
2246
0
                                .any(|(_, connection_id)| {
2247
0
                                    let state = self.inner.connection_state(*connection_id);
2248
0
                                    state.established && !state.shutting_down
2249
0
                                })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsl_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsl_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsl_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsl_0B26_
2250
                            {
2251
0
                                debug_assert!(
2252
0
                                    self.notification_substreams_by_peer_id
2253
0
                                        .range(
2254
0
                                            (
2255
0
                                                NotificationsProtocol::BlockAnnounces {
2256
0
                                                    chain_index
2257
0
                                                },
2258
0
                                                peer_index,
2259
0
                                                SubstreamDirection::Out,
2260
0
                                                NotificationsSubstreamState::MIN,
2261
0
                                                SubstreamId::MIN,
2262
0
                                            )
2263
0
                                                ..=(
2264
0
                                                    NotificationsProtocol::BlockAnnounces {
2265
0
                                                        chain_index
2266
0
                                                    },
2267
0
                                                    peer_index,
2268
0
                                                    SubstreamDirection::Out,
2269
0
                                                    NotificationsSubstreamState::MAX,
2270
0
                                                    SubstreamId::MAX,
2271
0
                                                ),
2272
0
                                        )
2273
0
                                        .next()
2274
0
                                        .is_none()
2275
                                );
2276
2277
0
                                let _was_inserted =
2278
0
                                    self.connected_unopened_gossip_desired.insert((
2279
0
                                        peer_index,
2280
0
                                        ChainId(chain_index),
2281
0
                                        GossipKind::ConsensusTransactions,
2282
0
                                    ));
2283
0
                                debug_assert!(_was_inserted);
2284
0
                            }
2285
2286
                            // The transactions and Grandpa protocols are tied to the block
2287
                            // announces substream. As such, we also close any transactions or
2288
                            // grandpa substream, either pending or fully opened.
2289
0
                            for proto in [
2290
0
                                NotificationsProtocol::Transactions { chain_index },
2291
0
                                NotificationsProtocol::Grandpa { chain_index },
2292
                            ] {
2293
0
                                for (substream_direction, substream_state, substream_id) in self
2294
0
                                    .notification_substreams_by_peer_id
2295
0
                                    .range(
2296
0
                                        (
2297
0
                                            proto,
2298
0
                                            peer_index,
2299
0
                                            SubstreamDirection::MIN,
2300
0
                                            NotificationsSubstreamState::MIN,
2301
0
                                            SubstreamId::MIN,
2302
0
                                        )
2303
0
                                            ..=(
2304
0
                                                proto,
2305
0
                                                peer_index,
2306
0
                                                SubstreamDirection::MAX,
2307
0
                                                NotificationsSubstreamState::MAX,
2308
0
                                                SubstreamId::MAX,
2309
0
                                            ),
2310
                                    )
2311
0
                                    .map(|(_, _, direction, state, substream_id)| {
2312
0
                                        (*direction, *state, *substream_id)
2313
0
                                    })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsm_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventsm_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE10next_eventsm_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventsm_0B26_
2314
0
                                    .collect::<Vec<_>>()
2315
                                {
2316
0
                                    match (substream_direction, substream_state) {
2317
                                        (SubstreamDirection::Out, _) => {
2318
0
                                            self.inner.close_out_notifications(substream_id);
2319
0
                                            let _was_removed =
2320
0
                                                self.notification_substreams_by_peer_id.remove(&(
2321
0
                                                    proto,
2322
0
                                                    peer_index,
2323
0
                                                    SubstreamDirection::Out,
2324
0
                                                    substream_state,
2325
0
                                                    substream_id,
2326
0
                                                ));
2327
0
                                            debug_assert!(_was_removed);
2328
0
                                            self.substreams.remove(&substream_id);
2329
                                        }
2330
                                        (
2331
                                            SubstreamDirection::In,
2332
                                            NotificationsSubstreamState::Pending,
2333
                                        ) => {
2334
                                            // Inbound notification substreams are always accepted
2335
                                            // or rejected immediately when a gossip link is open.
2336
0
                                            unreachable!()
2337
                                        }
2338
                                        (
2339
                                            SubstreamDirection::In,
2340
                                            NotificationsSubstreamState::Open {
2341
                                                asked_to_leave: true,
2342
                                            },
2343
0
                                        ) => {
2344
0
                                            // Nothing to do.
2345
0
                                        }
2346
                                        (
2347
                                            SubstreamDirection::In,
2348
                                            NotificationsSubstreamState::Open {
2349
                                                asked_to_leave: false,
2350
                                            },
2351
                                        ) => {
2352
0
                                            self.inner.start_close_in_notifications(
2353
0
                                                substream_id,
2354
0
                                                Duration::from_secs(5), // TODO: arbitrary constant
2355
                                            );
2356
0
                                            let _was_removed =
2357
0
                                                self.notification_substreams_by_peer_id.remove(&(
2358
0
                                                    proto,
2359
0
                                                    peer_index,
2360
0
                                                    SubstreamDirection::In,
2361
0
                                                    NotificationsSubstreamState::Open {
2362
0
                                                        asked_to_leave: false,
2363
0
                                                    },
2364
0
                                                    substream_id,
2365
0
                                                ));
2366
0
                                            debug_assert!(_was_removed);
2367
0
                                            let _was_inserted =
2368
0
                                                self.notification_substreams_by_peer_id.insert((
2369
0
                                                    proto,
2370
0
                                                    peer_index,
2371
0
                                                    SubstreamDirection::In,
2372
0
                                                    NotificationsSubstreamState::Open {
2373
0
                                                        asked_to_leave: true,
2374
0
                                                    },
2375
0
                                                    substream_id,
2376
0
                                                ));
2377
0
                                            debug_assert!(_was_inserted);
2378
                                        }
2379
                                    }
2380
                                }
2381
                            }
2382
2383
0
                            return Some(Event::GossipDisconnected {
2384
0
                                peer_id: self.peers[peer_index.0].clone(),
2385
0
                                chain_id: ChainId(chain_index),
2386
0
                                kind: GossipKind::ConsensusTransactions,
2387
0
                            });
2388
                        }
2389
2390
                        // The transactions and grandpa protocols are tied to the block announces
2391
                        // substream. If there is a block announce substream with the peer, we try
2392
                        // to reopen these two substreams.
2393
                        NotificationsProtocol::Transactions { .. }
2394
                        | NotificationsProtocol::Grandpa { .. } => {
2395
                            // Don't actually try to reopen if the connection is shutting down.
2396
                            // Note that we don't try to reopen on a different connection, as the
2397
                            // block announces substream will very soon be closed too anyway.
2398
0
                            if self.inner.connection_state(connection_id).shutting_down {
2399
0
                                continue;
2400
0
                            }
2401
2402
0
                            let new_substream_id = self.inner.open_out_notifications(
2403
0
                                connection_id,
2404
0
                                codec::encode_protocol_name_string(match substream_protocol {
2405
0
                                    NotificationsProtocol::Transactions { chain_index } => {
2406
0
                                        codec::ProtocolName::Transactions {
2407
0
                                            genesis_hash: self.chains[chain_index].genesis_hash,
2408
0
                                            fork_id: self.chains[chain_index].fork_id.as_deref(),
2409
0
                                        }
2410
                                    }
2411
0
                                    NotificationsProtocol::Grandpa { chain_index } => {
2412
0
                                        codec::ProtocolName::Grandpa {
2413
0
                                            genesis_hash: self.chains[chain_index].genesis_hash,
2414
0
                                            fork_id: self.chains[chain_index].fork_id.as_deref(),
2415
0
                                        }
2416
                                    }
2417
0
                                    _ => unreachable!(),
2418
                                }),
2419
0
                                self.notifications_protocol_handshake_timeout(substream_protocol),
2420
0
                                self.notifications_protocol_handshake(substream_protocol),
2421
0
                                self.notifications_protocol_max_handshake_size(substream_protocol),
2422
                            );
2423
0
                            self.substreams.insert(
2424
0
                                new_substream_id,
2425
0
                                SubstreamInfo {
2426
0
                                    connection_id,
2427
0
                                    protocol: Some(Protocol::Notifications(substream_protocol)),
2428
0
                                },
2429
                            );
2430
0
                            self.notification_substreams_by_peer_id.insert((
2431
0
                                substream_protocol,
2432
0
                                peer_index,
2433
0
                                SubstreamDirection::Out,
2434
0
                                NotificationsSubstreamState::Pending,
2435
0
                                new_substream_id,
2436
0
                            ));
2437
                        }
2438
                    }
2439
                }
2440
2441
0
                collection::Event::NotificationsInOpen { substream_id, .. } => {
2442
                    // Remote would like to open a notifications substream with us.
2443
2444
                    // There exists three possible ways to handle this event:
2445
                    //
2446
                    // - Accept the demand immediately. This happens if the API user has opened
2447
                    //   a gossip substream in the past or is currently trying to open a gossip
2448
                    //   substream with this peer.
2449
                    // - Refuse the demand immediately. This happens if there already exists a
2450
                    //   pending inbound notifications substream. Opening multiple notification
2451
                    //   substreams of the same protocol is a protocol violation. This also happens
2452
                    //   for transactions and grandpa substreams if no block announce substream is
2453
                    //   open.
2454
                    // - Generate an event to ask the API user whether to accept the demand. This
2455
                    //   happens specifically for block announce substreams.
2456
2457
                    // Extract various bits of information about the substream.
2458
                    // Instantly reject the substream if it concerns a chain that has since then
2459
                    // been removed from `self`, which can happen if the protocol name was already
2460
                    // negotiated when the chain was removed.
2461
0
                    let substream_info = self
2462
0
                        .substreams
2463
0
                        .get(&substream_id)
2464
0
                        .unwrap_or_else(|| unreachable!());
2465
0
                    let peer_index = *self.inner[substream_info.connection_id]
2466
0
                        .peer_index
2467
0
                        .as_ref()
2468
0
                        .unwrap_or_else(|| unreachable!());
2469
0
                    let Some(substream_protocol) = substream_info.protocol else {
2470
0
                        self.inner.reject_in_notifications(substream_id);
2471
0
                        self.substreams.remove(&substream_id);
2472
0
                        continue;
2473
                    };
2474
0
                    let Protocol::Notifications(substream_protocol) = substream_protocol else {
2475
0
                        unreachable!()
2476
                    };
2477
0
                    let (NotificationsProtocol::BlockAnnounces { chain_index }
2478
0
                    | NotificationsProtocol::Transactions { chain_index }
2479
0
                    | NotificationsProtocol::Grandpa { chain_index }) = substream_protocol;
2480
2481
                    // Check whether a substream with the same protocol already exists with that
2482
                    // peer, and if so deny the request.
2483
                    // Note that substreams with `asked_to_leave` equal to `true` are ignored when
2484
                    // searching, as in this case it's not a protocol violation.
2485
0
                    if self
2486
0
                        .notification_substreams_by_peer_id
2487
0
                        .range(
2488
0
                            (
2489
0
                                substream_protocol,
2490
0
                                peer_index,
2491
0
                                SubstreamDirection::In,
2492
0
                                NotificationsSubstreamState::MIN,
2493
0
                                SubstreamId::MIN,
2494
0
                            )
2495
0
                                ..(
2496
0
                                    substream_protocol,
2497
0
                                    peer_index,
2498
0
                                    SubstreamDirection::In,
2499
0
                                    NotificationsSubstreamState::Open {
2500
0
                                        asked_to_leave: true,
2501
0
                                    },
2502
0
                                    SubstreamId::MIN,
2503
0
                                ),
2504
0
                        )
2505
0
                        .next()
2506
0
                        .is_some()
2507
                    {
2508
0
                        self.inner.reject_in_notifications(substream_id);
2509
0
                        let _was_removed = self.substreams.remove(&substream_id);
2510
0
                        debug_assert!(_was_removed.is_some());
2511
0
                        continue;
2512
0
                    }
2513
2514
                    // If an outgoing block announces notifications protocol (either pending or
2515
                    // fully open) exists, accept the substream immediately.
2516
0
                    if self
2517
0
                        .notification_substreams_by_peer_id
2518
0
                        .range(
2519
0
                            (
2520
0
                                NotificationsProtocol::BlockAnnounces { chain_index },
2521
0
                                peer_index,
2522
0
                                SubstreamDirection::Out,
2523
0
                                NotificationsSubstreamState::MIN,
2524
0
                                SubstreamId::MIN,
2525
0
                            )
2526
0
                                ..=(
2527
0
                                    NotificationsProtocol::BlockAnnounces { chain_index },
2528
0
                                    peer_index,
2529
0
                                    SubstreamDirection::Out,
2530
0
                                    NotificationsSubstreamState::MAX,
2531
0
                                    SubstreamId::MAX,
2532
0
                                ),
2533
0
                        )
2534
0
                        .next()
2535
0
                        .is_some()
2536
                    {
2537
0
                        let _was_inserted = self.notification_substreams_by_peer_id.insert((
2538
0
                            substream_protocol,
2539
0
                            peer_index,
2540
0
                            SubstreamDirection::In,
2541
0
                            NotificationsSubstreamState::Open {
2542
0
                                asked_to_leave: false,
2543
0
                            },
2544
0
                            substream_id,
2545
0
                        ));
2546
0
                        debug_assert!(_was_inserted);
2547
0
                        self.inner.accept_in_notifications(
2548
0
                            substream_id,
2549
0
                            self.notifications_protocol_handshake(substream_protocol),
2550
0
                            self.notifications_protocol_max_notification_size(substream_protocol),
2551
                        );
2552
0
                        continue;
2553
0
                    }
2554
2555
                    // It is forbidden to cold-open a substream other than the block announces
2556
                    // substream.
2557
0
                    if !matches!(
2558
0
                        substream_protocol,
2559
                        NotificationsProtocol::BlockAnnounces { .. }
2560
                    ) {
2561
0
                        self.inner.reject_in_notifications(substream_id);
2562
0
                        let _was_removed = self.substreams.remove(&substream_id);
2563
0
                        debug_assert!(_was_removed.is_some());
2564
0
                        continue;
2565
0
                    }
2566
2567
                    // Update the local state and return the event.
2568
0
                    debug_assert!(matches!(
2569
0
                        substream_protocol,
2570
                        NotificationsProtocol::BlockAnnounces { .. }
2571
                    ));
2572
0
                    self.notification_substreams_by_peer_id.insert((
2573
0
                        substream_protocol,
2574
0
                        peer_index,
2575
0
                        SubstreamDirection::In,
2576
0
                        NotificationsSubstreamState::Pending,
2577
0
                        substream_id,
2578
0
                    ));
2579
0
                    return Some(Event::GossipInDesired {
2580
0
                        peer_id: self.peers[peer_index.0].clone(),
2581
0
                        chain_id: ChainId(chain_index),
2582
0
                        kind: GossipKind::ConsensusTransactions,
2583
0
                    });
2584
                }
2585
2586
0
                collection::Event::NotificationsInOpenCancel { substream_id } => {
2587
                    // Remote has cancelled a pending `NotificationsInOpen`.
2588
2589
0
                    let substream_info = self
2590
0
                        .substreams
2591
0
                        .remove(&substream_id)
2592
0
                        .unwrap_or_else(|| unreachable!());
2593
0
                    let peer_index = *self.inner[substream_info.connection_id]
2594
0
                        .peer_index
2595
0
                        .as_ref()
2596
0
                        .unwrap_or_else(|| unreachable!());
2597
2598
                    // All incoming notification substreams are immediately accepted/rejected
2599
                    // except for block announce substreams. Additionally, when a chain is removed,
2600
                    // all its pending block announce substreams are rejected. Therefore, this
2601
                    // event can only happen for block announce substreams.
2602
                    let Some(Protocol::Notifications(NotificationsProtocol::BlockAnnounces {
2603
0
                        chain_index,
2604
0
                    })) = substream_info.protocol
2605
                    else {
2606
0
                        unreachable!()
2607
                    };
2608
2609
                    // Clean up the local state.
2610
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
2611
0
                        NotificationsProtocol::BlockAnnounces { chain_index },
2612
0
                        peer_index,
2613
0
                        SubstreamDirection::In,
2614
0
                        NotificationsSubstreamState::Pending,
2615
0
                        substream_id,
2616
0
                    ));
2617
0
                    debug_assert!(_was_in);
2618
2619
                    // Notify API user.
2620
0
                    return Some(Event::GossipInDesiredCancel {
2621
0
                        peer_id: self.peers[peer_index.0].clone(),
2622
0
                        chain_id: ChainId(chain_index),
2623
0
                        kind: GossipKind::ConsensusTransactions,
2624
0
                    });
2625
                }
2626
2627
                collection::Event::NotificationsIn {
2628
0
                    substream_id,
2629
0
                    notification,
2630
                } => {
2631
                    // Received a notification from a remote.
2632
0
                    let substream_info = self
2633
0
                        .substreams
2634
0
                        .get(&substream_id)
2635
0
                        .unwrap_or_else(|| unreachable!());
2636
0
                    let substream_protocol = match substream_info.protocol {
2637
                        None => {
2638
                            // Substream concerns a chain that has been removed.
2639
                            // Ignore the notification.
2640
0
                            continue;
2641
                        }
2642
0
                        Some(Protocol::Notifications(p)) => p,
2643
0
                        Some(_) => unreachable!(),
2644
                    };
2645
0
                    let (NotificationsProtocol::BlockAnnounces { chain_index }
2646
0
                    | NotificationsProtocol::Transactions { chain_index }
2647
0
                    | NotificationsProtocol::Grandpa { chain_index }) = substream_protocol;
2648
0
                    let peer_index = *self.inner[substream_info.connection_id]
2649
0
                        .peer_index
2650
0
                        .as_ref()
2651
0
                        .unwrap_or_else(|| unreachable!());
2652
2653
                    // Check whether there is an open outgoing block announces substream, as this
2654
                    // means that we are "gossip-connected". If not, then the notification is
2655
                    // silently discarded.
2656
0
                    if self
2657
0
                        .notification_substreams_by_peer_id
2658
0
                        .range(
2659
0
                            (
2660
0
                                NotificationsProtocol::BlockAnnounces { chain_index },
2661
0
                                peer_index,
2662
0
                                SubstreamDirection::Out,
2663
0
                                NotificationsSubstreamState::OPEN_MIN_VALUE,
2664
0
                                collection::SubstreamId::MIN,
2665
0
                            )
2666
0
                                ..=(
2667
0
                                    NotificationsProtocol::BlockAnnounces { chain_index },
2668
0
                                    peer_index,
2669
0
                                    SubstreamDirection::Out,
2670
0
                                    NotificationsSubstreamState::OPEN_MAX_VALUE,
2671
0
                                    collection::SubstreamId::MAX,
2672
0
                                ),
2673
0
                        )
2674
0
                        .next()
2675
0
                        .is_none()
2676
                    {
2677
0
                        continue;
2678
0
                    }
2679
2680
                    // Decode the notification and return an event.
2681
0
                    match substream_protocol {
2682
                        NotificationsProtocol::BlockAnnounces { .. } => {
2683
0
                            if let Err(err) = codec::decode_block_announce(
2684
0
                                &notification,
2685
0
                                self.chains[chain_index].block_number_bytes,
2686
0
                            ) {
2687
0
                                return Some(Event::ProtocolError {
2688
0
                                    error: ProtocolError::BadBlockAnnounce(err),
2689
0
                                    peer_id: self.peers[peer_index.0].clone(),
2690
0
                                });
2691
0
                            }
2692
2693
0
                            return Some(Event::BlockAnnounce {
2694
0
                                chain_id: ChainId(chain_index),
2695
0
                                peer_id: self.peers[peer_index.0].clone(),
2696
0
                                announce: EncodedBlockAnnounce {
2697
0
                                    message: notification,
2698
0
                                    block_number_bytes: self.chains[chain_index].block_number_bytes,
2699
0
                                },
2700
0
                            });
2701
                        }
2702
0
                        NotificationsProtocol::Transactions { .. } => {
2703
0
                            // TODO: not implemented
2704
0
                        }
2705
                        NotificationsProtocol::Grandpa { .. } => {
2706
0
                            let decoded_notif = match codec::decode_grandpa_notification(
2707
0
                                &notification,
2708
0
                                self.chains[chain_index].block_number_bytes,
2709
0
                            ) {
2710
0
                                Ok(n) => n,
2711
0
                                Err(err) => {
2712
0
                                    return Some(Event::ProtocolError {
2713
0
                                        error: ProtocolError::BadGrandpaNotification(err),
2714
0
                                        peer_id: self.peers[peer_index.0].clone(),
2715
0
                                    });
2716
                                }
2717
                            };
2718
2719
0
                            match decoded_notif {
2720
                                codec::GrandpaNotificationRef::Commit(_) => {
2721
0
                                    return Some(Event::GrandpaCommitMessage {
2722
0
                                        chain_id: ChainId(chain_index),
2723
0
                                        peer_id: self.peers[peer_index.0].clone(),
2724
0
                                        message: EncodedGrandpaCommitMessage {
2725
0
                                            message: notification,
2726
0
                                            block_number_bytes: self.chains[chain_index]
2727
0
                                                .block_number_bytes,
2728
0
                                        },
2729
0
                                    });
2730
                                }
2731
0
                                codec::GrandpaNotificationRef::Neighbor(n) => {
2732
0
                                    return Some(Event::GrandpaNeighborPacket {
2733
0
                                        chain_id: ChainId(chain_index),
2734
0
                                        peer_id: self.peers[peer_index.0].clone(),
2735
0
                                        state: GrandpaState {
2736
0
                                            round_number: n.round_number,
2737
0
                                            set_id: n.set_id,
2738
0
                                            commit_finalized_height: n.commit_finalized_height,
2739
0
                                        },
2740
0
                                    });
2741
                                }
2742
0
                                _ => {
2743
0
                                    // Any other type of message is currently ignored. Support
2744
0
                                    // for them could be added in the future.
2745
0
                                }
2746
                            }
2747
                        }
2748
                    }
2749
                }
2750
2751
0
                collection::Event::NotificationsInClose { substream_id, .. } => {
2752
                    // An incoming notifications substream has been closed.
2753
                    // Nothing to do except clean up the local state.
2754
0
                    let Some(substream_info) = self.substreams.remove(&substream_id) else {
2755
0
                        unreachable!()
2756
                    };
2757
0
                    let peer_index = *self.inner[substream_info.connection_id]
2758
0
                        .peer_index
2759
0
                        .as_ref()
2760
0
                        .unwrap_or_else(|| unreachable!());
2761
0
                    let Some(protocol) = substream_info.protocol else {
2762
                        // Substream concerns a chain that has since then been removed.
2763
0
                        continue;
2764
                    };
2765
0
                    let Protocol::Notifications(protocol) = protocol else {
2766
0
                        unreachable!()
2767
                    };
2768
2769
                    // Clean up with both `asked_to_leave` equal to `true` or `false`, as we don't
2770
                    // know in which of the two the substream is.
2771
0
                    let _was_in1 = self.notification_substreams_by_peer_id.remove(&(
2772
0
                        protocol,
2773
0
                        peer_index,
2774
0
                        SubstreamDirection::In,
2775
0
                        NotificationsSubstreamState::Open {
2776
0
                            asked_to_leave: false,
2777
0
                        },
2778
0
                        substream_id,
2779
0
                    ));
2780
0
                    let _was_in2 = self.notification_substreams_by_peer_id.remove(&(
2781
0
                        protocol,
2782
0
                        peer_index,
2783
0
                        SubstreamDirection::In,
2784
0
                        NotificationsSubstreamState::Open {
2785
0
                            asked_to_leave: true,
2786
0
                        },
2787
0
                        substream_id,
2788
0
                    ));
2789
0
                    debug_assert!(_was_in1 || _was_in2);
2790
                }
2791
2792
0
                collection::Event::PingOutSuccess { id, ping_time } => {
2793
                    // The connection is necessarily past its handshake phase, and thus
2794
                    // the `peer_index` is necessarily known and valid.
2795
0
                    let Some(peer_index) = self.inner[id].peer_index else {
2796
0
                        unreachable!()
2797
                    };
2798
0
                    return Some(Event::PingOutSuccess {
2799
0
                        id,
2800
0
                        peer_id: self.peers[peer_index.0].clone(),
2801
0
                        ping_time,
2802
0
                    });
2803
                }
2804
            }
2805
        }
2806
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE10next_eventB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE10next_eventB19_
Line
Count
Source
1139
138
    pub fn next_event(&mut self) -> Option<Event<TConn>> {
1140
        loop {
1141
138
            let 
inner_event0
= self.inner.next_event()?;
1142
0
            match inner_event {
1143
                collection::Event::HandshakeFinished {
1144
0
                    id,
1145
0
                    peer_id: actual_peer_id,
1146
                } => {
1147
                    // A handshaking connection has finished its handshake. We must update `self`
1148
                    // and return an event.
1149
                    // What makes this a bit complicated is the possibility that the actual PeerId
1150
                    // might not be the same as the one that was expected.
1151
1152
0
                    let actual_peer_index = self.peer_index_or_insert(actual_peer_id);
1153
0
                    let expected_peer_index = self.inner[id].peer_index;
1154
1155
0
                    match expected_peer_index {
1156
0
                        None => {
1157
0
                            // The connection didn't have any expected PeerId.
1158
0
                            self.inner[id].peer_index = Some(actual_peer_index);
1159
0
                            self.unconnected_desired.remove(&actual_peer_index);
1160
0
                        }
1161
0
                        Some(expected_peer_index) if expected_peer_index != actual_peer_index => {
1162
                            // The actual PeerId doesn't match the expected PeerId.
1163
1164
                            // Update the connection owner.
1165
0
                            self.inner[id].peer_index = Some(actual_peer_index);
1166
0
                            let _was_removed = self
1167
0
                                .connections_by_peer_id
1168
0
                                .remove(&(expected_peer_index, id));
1169
0
                            debug_assert!(_was_removed);
1170
0
                            let _was_inserted =
1171
0
                                self.connections_by_peer_id.insert((actual_peer_index, id));
1172
0
                            debug_assert!(_was_inserted);
1173
1174
                            // Update `unconnected_desired`.
1175
0
                            self.unconnected_desired.remove(&actual_peer_index);
1176
0
                            if self
1177
0
                                .gossip_desired_peers
1178
0
                                .range(
1179
0
                                    (
1180
0
                                        expected_peer_index,
1181
0
                                        GossipKind::ConsensusTransactions,
1182
0
                                        usize::MIN,
1183
0
                                    )
1184
0
                                        ..=(
1185
0
                                            expected_peer_index,
1186
0
                                            GossipKind::ConsensusTransactions,
1187
0
                                            usize::MAX,
1188
0
                                        ),
1189
0
                                )
1190
0
                                .next()
1191
0
                                .is_some()
1192
0
                                && !self
1193
0
                                    .connections_by_peer_id
1194
0
                                    .range(
1195
0
                                        (expected_peer_index, ConnectionId::MIN)
1196
0
                                            ..=(expected_peer_index, ConnectionId::MAX),
1197
0
                                    )
1198
0
                                    .any(|(_, connection_id)| {
1199
                                        let state = self.inner.connection_state(*connection_id);
1200
                                        !state.shutting_down
1201
                                    })
1202
                            {
1203
0
                                let _was_inserted =
1204
0
                                    self.unconnected_desired.insert(expected_peer_index);
1205
0
                                debug_assert!(_was_inserted);
1206
0
                            }
1207
                        }
1208
                        _ => {
1209
                            // Expected matches actual.
1210
0
                            debug_assert_eq!(expected_peer_index, Some(actual_peer_index));
1211
                        }
1212
                    }
1213
1214
                    // TODO: limit the number of connections per peer?
1215
1216
                    // Insert the new connection in `self.connected_unopened_gossip_desired`
1217
                    // if relevant.
1218
0
                    for (_, _, chain_id) in self.gossip_desired_peers.range(
1219
0
                        (
1220
0
                            actual_peer_index,
1221
0
                            GossipKind::ConsensusTransactions,
1222
0
                            usize::MIN,
1223
0
                        )
1224
0
                            ..=(
1225
0
                                actual_peer_index,
1226
0
                                GossipKind::ConsensusTransactions,
1227
0
                                usize::MAX,
1228
0
                            ),
1229
                    ) {
1230
0
                        if self
1231
0
                            .notification_substreams_by_peer_id
1232
0
                            .range(
1233
0
                                (
1234
0
                                    NotificationsProtocol::BlockAnnounces {
1235
0
                                        chain_index: *chain_id,
1236
0
                                    },
1237
0
                                    actual_peer_index,
1238
0
                                    SubstreamDirection::Out,
1239
0
                                    NotificationsSubstreamState::MIN,
1240
0
                                    SubstreamId::MIN,
1241
0
                                )
1242
0
                                    ..=(
1243
0
                                        NotificationsProtocol::BlockAnnounces {
1244
0
                                            chain_index: *chain_id,
1245
0
                                        },
1246
0
                                        actual_peer_index,
1247
0
                                        SubstreamDirection::Out,
1248
0
                                        NotificationsSubstreamState::MAX,
1249
0
                                        SubstreamId::MAX,
1250
0
                                    ),
1251
0
                            )
1252
0
                            .next()
1253
0
                            .is_none()
1254
0
                        {
1255
0
                            self.connected_unopened_gossip_desired.insert((
1256
0
                                actual_peer_index,
1257
0
                                ChainId(*chain_id),
1258
0
                                GossipKind::ConsensusTransactions,
1259
0
                            ));
1260
0
                        }
1261
                    }
1262
1263
                    // Try to clean up the expected peer index.
1264
                    // This is done at the very end so that `self` is in a coherent state.
1265
0
                    let expected_peer_id = expected_peer_index.map(|idx| self.peers[idx.0].clone());
1266
0
                    if let Some(expected_peer_index) = expected_peer_index {
1267
0
                        if expected_peer_index != actual_peer_index {
1268
0
                            self.try_clean_up_peer(expected_peer_index);
1269
0
                        }
1270
0
                    }
1271
1272
                    // Small sanity check.
1273
0
                    debug_assert!(!self.unconnected_desired.contains(&actual_peer_index));
1274
1275
0
                    return Some(Event::HandshakeFinished {
1276
0
                        id,
1277
0
                        expected_peer_id,
1278
0
                        peer_id: self.peers[actual_peer_index.0].clone(),
1279
0
                    });
1280
                }
1281
1282
0
                collection::Event::PingOutFailed { id }
1283
0
                | collection::Event::StartShutdown { id, .. } => {
1284
                    // A connection has started its shutdown, or must start its shutdown.
1285
1286
                    // We handle a ping failure the same way as a shutdown start, as we react to
1287
                    // a ping failure by starting the shutdown of the connection. Thus, the clean
1288
                    // up phase is the same in both cases.
1289
0
                    if let collection::Event::PingOutFailed { .. } = inner_event {
1290
0
                        self.inner.start_shutdown(id);
1291
0
                    }
1292
1293
                    // TODO: IMPORTANT this event should be turned into `NewOutboundSubstreamsForbidden` and the `reason` removed; see <https://github.com/smol-dot/smoldot/pull/391>
1294
1295
                    // Nothing more to do if the connection is inbound and handshaking.
1296
0
                    let Some(peer_index) = self.inner[id].peer_index else {
1297
0
                        debug_assert!(!self.inner.connection_state(id).established);
1298
0
                        continue;
1299
                    };
1300
1301
                    // If peer is desired, and we have no connection or only shutting down
1302
                    // connections, add peer to `unconnected_desired` and remove it from
1303
                    // `connected_unopened_gossip_desired`.
1304
0
                    if self
1305
0
                        .gossip_desired_peers
1306
0
                        .range(
1307
0
                            (peer_index, GossipKind::ConsensusTransactions, usize::MIN)
1308
0
                                ..=(peer_index, GossipKind::ConsensusTransactions, usize::MAX),
1309
0
                        )
1310
0
                        .count()
1311
0
                        != 0
1312
                    {
1313
0
                        if !self
1314
0
                            .connections_by_peer_id
1315
0
                            .range(
1316
0
                                (peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX),
1317
0
                            )
1318
0
                            .any(|(_, connection_id)| {
1319
                                let state = self.inner.connection_state(*connection_id);
1320
                                !state.shutting_down
1321
                            })
1322
0
                        {
1323
0
                            self.unconnected_desired.insert(peer_index);
1324
0
                        }
1325
0
                        if !self
1326
0
                            .connections_by_peer_id
1327
0
                            .range(
1328
0
                                (peer_index, ConnectionId::MIN)..=(peer_index, ConnectionId::MAX),
1329
0
                            )
1330
0
                            .any(|(_, connection_id)| {
1331
                                let state = self.inner.connection_state(*connection_id);
1332
                                state.established && !state.shutting_down
1333
                            })
1334
                        {
1335
0
                            for (_, _, chain_index) in self.gossip_desired_peers.range(
1336
0
                                (peer_index, GossipKind::ConsensusTransactions, usize::MIN)
1337
0
                                    ..=(peer_index, GossipKind::ConsensusTransactions, usize::MAX),
1338
0
                            ) {
1339
0
                                self.connected_unopened_gossip_desired.remove(&(
1340
0
                                    peer_index,
1341
0
                                    ChainId(*chain_index),
1342
0
                                    GossipKind::ConsensusTransactions,
1343
0
                                ));
1344
0
                            }
1345
0
                        }
1346
0
                    }
1347
                }
1348
1349
                collection::Event::Shutdown {
1350
0
                    id,
1351
0
                    was_established,
1352
0
                    user_data: connection_info,
1353
                } => {
1354
                    // A connection has been completely closed.
1355
                    // The underlying state machine guarantees that all the substreams have been
1356
                    // closed beforehand through other events.
1357
1358
0
                    debug_assert!(connection_info.peer_index.is_some() || !was_established);
1359
1360
0
                    let peer_id = connection_info
1361
0
                        .peer_index
1362
0
                        .map(|peer_index| self.peers[peer_index.0].clone());
1363
1364
0
                    if let Some(peer_index) = connection_info.peer_index {
1365
0
                        let _was_removed = self.connections_by_peer_id.remove(&(peer_index, id));
1366
0
                        debug_assert!(_was_removed);
1367
0
                        self.try_clean_up_peer(peer_index);
1368
0
                    }
1369
1370
                    // TODO: IMPORTANT this event should indicate a clean shutdown, a pre-handshake interruption, a protocol error, a reset, etc. and should get a `reason`; see <https://github.com/smol-dot/smoldot/pull/391>
1371
1372
0
                    if was_established {
1373
0
                        return Some(Event::Disconnected {
1374
0
                            id,
1375
0
                            address: connection_info.address,
1376
0
                            peer_id: peer_id.unwrap(),
1377
0
                            user_data: connection_info.user_data,
1378
0
                        });
1379
                    } else {
1380
0
                        return Some(Event::PreHandshakeDisconnected {
1381
0
                            id,
1382
0
                            address: connection_info.address,
1383
0
                            expected_peer_id: peer_id,
1384
0
                            user_data: connection_info.user_data,
1385
0
                        });
1386
                    }
1387
                }
1388
1389
0
                collection::Event::InboundError { .. } => {
1390
0
                    // TODO: report the error for diagnostic purposes, but revisit the concept of "InboundError"
1391
0
                }
1392
1393
                collection::Event::InboundNegotiated {
1394
0
                    id,
1395
0
                    substream_id,
1396
0
                    protocol_name,
1397
                } => {
1398
                    // An inbound substream opened by the remote would like to negotiate the given
1399
                    // protocol. We must decide whether to accept this protocol or instead reject
1400
                    // the substream.
1401
                    // If accepted, we must also save the protocol somewhere in `self` in order to
1402
                    // load it later once things happen on this substream.
1403
0
                    let Ok(protocol) = self.recognize_protocol(&protocol_name) else {
1404
0
                        self.inner.reject_inbound(substream_id);
1405
0
                        continue;
1406
                    };
1407
1408
0
                    let inbound_type = match protocol {
1409
0
                        Protocol::Identify => collection::InboundTy::Request {
1410
0
                            request_max_size: None,
1411
0
                        },
1412
0
                        Protocol::Ping => collection::InboundTy::Ping,
1413
0
                        Protocol::Notifications(NotificationsProtocol::Grandpa { chain_index })
1414
0
                            if self.chains[chain_index].grandpa_protocol_config.is_none() =>
1415
                        {
1416
0
                            self.inner.reject_inbound(substream_id);
1417
0
                            continue;
1418
                        }
1419
0
                        Protocol::Notifications(p) => collection::InboundTy::Notifications {
1420
0
                            max_handshake_size: self.notifications_protocol_max_handshake_size(p),
1421
0
                        },
1422
0
                        Protocol::Sync { chain_index }
1423
0
                            if self.chains[chain_index].allow_inbound_block_requests =>
1424
                        {
1425
0
                            collection::InboundTy::Request {
1426
0
                                request_max_size: Some(1024),
1427
0
                            }
1428
                        }
1429
                        Protocol::Sync { .. } => {
1430
0
                            self.inner.reject_inbound(substream_id);
1431
0
                            continue;
1432
                        }
1433
1434
                        // TODO: the protocols below are not supported yet
1435
                        Protocol::LightUnknown { .. }
1436
                        | Protocol::Kad { .. }
1437
                        | Protocol::SyncWarp { .. }
1438
                        | Protocol::State { .. } => {
1439
0
                            self.inner.reject_inbound(substream_id);
1440
0
                            continue;
1441
                        }
1442
1443
                        Protocol::LightStorage { .. } | Protocol::LightCall { .. } => {
1444
0
                            unreachable!()
1445
                        }
1446
                    };
1447
1448
0
                    self.inner.accept_inbound(substream_id, inbound_type);
1449
1450
0
                    let _prev_value = self.substreams.insert(
1451
0
                        substream_id,
1452
0
                        SubstreamInfo {
1453
0
                            connection_id: id,
1454
0
                            protocol: Some(protocol),
1455
0
                        },
1456
                    );
1457
0
                    debug_assert!(_prev_value.is_none());
1458
                }
1459
1460
                collection::Event::InboundNegotiatedCancel { .. } => {
1461
                    // Because we immediately accept or reject substreams, this event can never
1462
                    // happen.
1463
0
                    unreachable!()
1464
                }
1465
1466
0
                collection::Event::InboundAcceptedCancel { substream_id } => {
1467
                    // An inbound substream has been aborted after having been accepted.
1468
                    // Since we don't report any event to the API user when a substream is
1469
                    // accepted, we have nothing to do but clean up our local state.
1470
0
                    let _was_in = self.substreams.remove(&substream_id);
1471
0
                    debug_assert!(_was_in.is_some());
1472
                }
1473
1474
                collection::Event::Response {
1475
0
                    substream_id,
1476
0
                    response,
1477
                } => {
1478
                    // Received a response to a request in a request-response protocol.
1479
0
                    let substream_info = self
1480
0
                        .substreams
1481
0
                        .remove(&substream_id)
1482
0
                        .unwrap_or_else(|| unreachable!());
1483
0
                    let peer_index = *self.inner[substream_info.connection_id]
1484
0
                        .peer_index
1485
0
                        .as_ref()
1486
0
                        .unwrap_or_else(|| unreachable!());
1487
1488
                    // Decode/verify the response.
1489
0
                    let (response, chain_index) = match substream_info.protocol {
1490
0
                        None => continue,
1491
0
                        Some(Protocol::Identify) => todo!(), // TODO: we don't send identify requests yet, so it's fine to leave this unimplemented
1492
0
                        Some(Protocol::Sync { chain_index, .. }) => (
1493
                            RequestResult::Blocks(
1494
0
                                response.map_err(BlocksRequestError::Request).and_then(
1495
                                    |response| {
1496
                                        codec::decode_block_response(&response)
1497
                                            .map_err(BlocksRequestError::Decode)
1498
                                    },
1499
                                ),
1500
                            ),
1501
0
                            chain_index,
1502
                        ),
1503
0
                        Some(Protocol::LightUnknown { .. }) => unreachable!(),
1504
0
                        Some(Protocol::LightStorage { chain_index, .. }) => (
1505
                            RequestResult::StorageProof(
1506
0
                                response
1507
0
                                    .map_err(StorageProofRequestError::Request)
1508
0
                                    .and_then(|payload| {
1509
                                        match codec::decode_storage_or_call_proof_response(
1510
                                            codec::StorageOrCallProof::StorageProof,
1511
                                            &payload,
1512
                                        ) {
1513
                                            Err(err) => Err(StorageProofRequestError::Decode(err)),
1514
                                            Ok(None) => {
1515
                                                Err(StorageProofRequestError::RemoteCouldntAnswer)
1516
                                            }
1517
                                            Ok(Some(_)) => Ok(EncodedMerkleProof(
1518
                                                payload,
1519
                                                codec::StorageOrCallProof::StorageProof,
1520
                                            )),
1521
                                        }
1522
                                    }),
1523
                            ),
1524
0
                            chain_index,
1525
                        ),
1526
0
                        Some(Protocol::LightCall { chain_index, .. }) => (
1527
                            RequestResult::CallProof(
1528
0
                                response.map_err(CallProofRequestError::Request).and_then(
1529
                                    |payload| match codec::decode_storage_or_call_proof_response(
1530
                                        codec::StorageOrCallProof::CallProof,
1531
                                        &payload,
1532
                                    ) {
1533
                                        Err(err) => Err(CallProofRequestError::Decode(err)),
1534
                                        Ok(None) => Err(CallProofRequestError::RemoteCouldntAnswer),
1535
                                        Ok(Some(_)) => Ok(EncodedMerkleProof(
1536
                                            payload,
1537
                                            codec::StorageOrCallProof::CallProof,
1538
                                        )),
1539
                                    },
1540
                                ),
1541
                            ),
1542
0
                            chain_index,
1543
                        ),
1544
0
                        Some(Protocol::Kad { chain_index, .. }) => (
1545
                            RequestResult::KademliaFindNode(
1546
0
                                response
1547
0
                                    .map_err(KademliaFindNodeError::RequestFailed)
1548
0
                                    .and_then(|payload| {
1549
                                        match codec::decode_find_node_response(&payload) {
1550
                                            Err(err) => {
1551
                                                Err(KademliaFindNodeError::DecodeError(err))
1552
                                            }
1553
                                            Ok(nodes) => Ok(nodes),
1554
                                        }
1555
                                    }),
1556
                            ),
1557
0
                            chain_index,
1558
                        ),
1559
0
                        Some(Protocol::SyncWarp { chain_index }) => (
1560
                            RequestResult::GrandpaWarpSync(
1561
0
                                response
1562
0
                                    .map_err(GrandpaWarpSyncRequestError::Request)
1563
0
                                    .and_then(|message| {
1564
                                        if let Err(err) = codec::decode_grandpa_warp_sync_response(
1565
                                            &message,
1566
                                            self.chains[chain_index].block_number_bytes,
1567
                                        ) {
1568
                                            Err(GrandpaWarpSyncRequestError::Decode(err))
1569
                                        } else {
1570
                                            Ok(EncodedGrandpaWarpSyncResponse {
1571
                                                message,
1572
                                                block_number_bytes: self.chains[chain_index]
1573
                                                    .block_number_bytes,
1574
                                            })
1575
                                        }
1576
                                    }),
1577
                            ),
1578
0
                            chain_index,
1579
                        ),
1580
0
                        Some(Protocol::State { chain_index, .. }) => (
1581
                            RequestResult::State(
1582
0
                                response
1583
0
                                    .map_err(StateRequestError::Request)
1584
0
                                    .and_then(|payload| {
1585
                                        if let Err(err) = codec::decode_state_response(&payload) {
1586
                                            Err(StateRequestError::Decode(err))
1587
                                        } else {
1588
                                            Ok(EncodedStateResponse(payload))
1589
                                        }
1590
                                    }),
1591
                            ),
1592
0
                            chain_index,
1593
                        ),
1594
1595
                        // The protocols below aren't request-response protocols.
1596
0
                        Some(Protocol::Ping) | Some(Protocol::Notifications(_)) => unreachable!(),
1597
                    };
1598
1599
0
                    return Some(Event::RequestResult {
1600
0
                        peer_id: self.peers[peer_index.0].clone(),
1601
0
                        chain_id: ChainId(chain_index),
1602
0
                        substream_id,
1603
0
                        response,
1604
0
                    });
1605
                }
1606
1607
                collection::Event::RequestIn {
1608
0
                    substream_id,
1609
0
                    request_payload,
1610
                } => {
1611
                    // Received a request on a request-response protocol.
1612
0
                    let substream_info = self
1613
0
                        .substreams
1614
0
                        .get(&substream_id)
1615
0
                        .unwrap_or_else(|| unreachable!());
1616
0
                    let peer_id = self.peers[self.inner[substream_info.connection_id]
1617
0
                        .peer_index
1618
0
                        .as_ref()
1619
0
                        .unwrap_or_else(|| unreachable!())
1620
                        .0]
1621
0
                        .clone();
1622
1623
0
                    match substream_info.protocol {
1624
0
                        None => {
1625
0
                            // Substream concerns a chain that has been removed.
1626
0
                            let _ = self.substreams.remove(&substream_id);
1627
0
                            self.inner.respond_in_request(substream_id, Err(()));
1628
0
                        }
1629
                        Some(Protocol::Identify) => {
1630
0
                            if request_payload.is_empty() {
1631
0
                                return Some(Event::IdentifyRequestIn {
1632
0
                                    peer_id,
1633
0
                                    substream_id,
1634
0
                                });
1635
                            } else {
1636
                                // TODO: can this actually be reached? isn't the inner code going to refuse a bad request anyway due to no length prefix?
1637
0
                                let _ = self.substreams.remove(&substream_id);
1638
0
                                self.inner.respond_in_request(substream_id, Err(()));
1639
0
                                return Some(Event::ProtocolError {
1640
0
                                    peer_id,
1641
0
                                    error: ProtocolError::BadIdentifyRequest,
1642
0
                                });
1643
                            }
1644
                        }
1645
0
                        Some(Protocol::Sync { chain_index }) => {
1646
0
                            match codec::decode_block_request(
1647
0
                                self.chains[chain_index].block_number_bytes,
1648
0
                                &request_payload,
1649
0
                            ) {
1650
0
                                Ok(config) => {
1651
0
                                    return Some(Event::BlocksRequestIn {
1652
0
                                        peer_id,
1653
0
                                        chain_id: ChainId(chain_index),
1654
0
                                        config,
1655
0
                                        substream_id,
1656
0
                                    });
1657
                                }
1658
0
                                Err(error) => {
1659
0
                                    let _ = self.substreams.remove(&substream_id);
1660
0
                                    self.inner.respond_in_request(substream_id, Err(()));
1661
0
                                    return Some(Event::ProtocolError {
1662
0
                                        peer_id,
1663
0
                                        error: ProtocolError::BadBlocksRequest(error),
1664
0
                                    });
1665
                                }
1666
                            }
1667
                        }
1668
                        // Any other protocol is declined when the protocol is negotiated.
1669
0
                        _ => unreachable!(),
1670
                    }
1671
                }
1672
1673
0
                collection::Event::RequestInCancel { substream_id } => {
1674
                    // The remote has cancelled a previously-emitted request. Propagate this event
1675
                    // to the API user.
1676
0
                    let _was_in = self.substreams.remove(&substream_id);
1677
0
                    debug_assert!(_was_in.is_some());
1678
0
                    return Some(Event::RequestInCancel { substream_id });
1679
                }
1680
1681
                // TODO: this whole block of code is too complex
1682
                collection::Event::NotificationsOutResult {
1683
0
                    substream_id,
1684
0
                    result,
1685
                } => {
1686
                    // Outgoing notifications substream has finished opening.
1687
                    // TODO: this if is pretty hacky
1688
0
                    let substream_info = if result.is_ok() {
1689
0
                        self.substreams
1690
0
                            .get(&substream_id)
1691
0
                            .unwrap_or_else(|| unreachable!())
1692
0
                            .clone()
1693
                    } else {
1694
0
                        self.substreams.remove(&substream_id).unwrap()
1695
                    };
1696
0
                    let connection_id = substream_info.connection_id;
1697
0
                    let peer_index = *self.inner[connection_id]
1698
0
                        .peer_index
1699
0
                        .as_ref()
1700
0
                        .unwrap_or_else(|| unreachable!());
1701
0
                    let Some(Protocol::Notifications(substream_protocol)) = substream_info.protocol
1702
                    else {
1703
                        // All outgoing substream attempts are cancelled when a chain is removed,
1704
                        // as such `protocol` can't be `None`.
1705
0
                        unreachable!();
1706
                    };
1707
1708
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
1709
0
                        substream_protocol,
1710
0
                        peer_index,
1711
0
                        SubstreamDirection::Out,
1712
0
                        NotificationsSubstreamState::Pending,
1713
0
                        substream_id,
1714
0
                    ));
1715
0
                    debug_assert!(_was_in);
1716
1717
                    // The behaviour is very specific to the protocol.
1718
0
                    match substream_protocol {
1719
0
                        NotificationsProtocol::BlockAnnounces { chain_index } => {
1720
                            // Parse the handshake to check whether it's correct.
1721
0
                            let result = match &result {
1722
0
                                Ok(handshake) => {
1723
0
                                    match codec::decode_block_announces_handshake(
1724
0
                                        self.chains[chain_index].block_number_bytes,
1725
0
                                        handshake,
1726
                                    ) {
1727
0
                                        Ok(decoded_handshake)
1728
0
                                            if *decoded_handshake.genesis_hash
1729
0
                                                == self.chains[chain_index].genesis_hash =>
1730
                                        {
1731
0
                                            Ok(decoded_handshake)
1732
                                        }
1733
0
                                        Ok(decoded_handshake) => {
1734
0
                                            Err(GossipConnectError::GenesisMismatch {
1735
0
                                                local_genesis: self.chains[chain_index]
1736
0
                                                    .genesis_hash,
1737
0
                                                remote_genesis: *decoded_handshake.genesis_hash,
1738
0
                                            })
1739
                                        }
1740
0
                                        Err(err) => Err(GossipConnectError::HandshakeDecode(err)),
1741
                                    }
1742
                                }
1743
0
                                Err(err) => Err(GossipConnectError::Substream(err.clone())),
1744
                            };
1745
1746
0
                            match result {
1747
0
                                Ok(decoded_handshake) => {
1748
0
                                    let _was_inserted =
1749
0
                                        self.notification_substreams_by_peer_id.insert((
1750
0
                                            NotificationsProtocol::BlockAnnounces { chain_index },
1751
0
                                            peer_index,
1752
0
                                            SubstreamDirection::Out,
1753
0
                                            NotificationsSubstreamState::Open {
1754
0
                                                asked_to_leave: false,
1755
0
                                            },
1756
0
                                            substream_id,
1757
0
                                        ));
1758
0
                                    debug_assert!(_was_inserted);
1759
1760
0
                                    for other_protocol in
1761
0
                                        iter::once(NotificationsProtocol::Transactions {
1762
0
                                            chain_index,
1763
0
                                        })
1764
0
                                        .chain(
1765
0
                                            self.chains[chain_index]
1766
0
                                                .grandpa_protocol_config
1767
0
                                                .is_some()
1768
0
                                                .then(|| NotificationsProtocol::Grandpa {
1769
                                                    chain_index,
1770
                                                }),
1771
                                        )
1772
                                    {
1773
0
                                        if self
1774
0
                                            .notification_substreams_by_peer_id
1775
0
                                            .range(
1776
0
                                                (
1777
0
                                                    other_protocol,
1778
0
                                                    peer_index,
1779
0
                                                    SubstreamDirection::Out,
1780
0
                                                    NotificationsSubstreamState::MIN,
1781
0
                                                    SubstreamId::MIN,
1782
0
                                                )
1783
0
                                                    ..=(
1784
0
                                                        other_protocol,
1785
0
                                                        peer_index,
1786
0
                                                        SubstreamDirection::Out,
1787
0
                                                        NotificationsSubstreamState::MAX,
1788
0
                                                        SubstreamId::MAX,
1789
0
                                                    ),
1790
0
                                            )
1791
0
                                            .next()
1792
0
                                            .is_some()
1793
                                        {
1794
0
                                            continue;
1795
0
                                        }
1796
1797
0
                                        let new_substream_id = self.inner.open_out_notifications(
1798
0
                                            connection_id,
1799
0
                                            codec::encode_protocol_name_string(
1800
0
                                                match other_protocol {
1801
                                                    NotificationsProtocol::Transactions {
1802
0
                                                        chain_index,
1803
0
                                                    } => codec::ProtocolName::Transactions {
1804
0
                                                        genesis_hash: self.chains[chain_index]
1805
0
                                                            .genesis_hash,
1806
0
                                                        fork_id: self.chains[chain_index]
1807
0
                                                            .fork_id
1808
0
                                                            .as_deref(),
1809
0
                                                    },
1810
                                                    NotificationsProtocol::Grandpa {
1811
0
                                                        chain_index,
1812
0
                                                    } => codec::ProtocolName::Grandpa {
1813
0
                                                        genesis_hash: self.chains[chain_index]
1814
0
                                                            .genesis_hash,
1815
0
                                                        fork_id: self.chains[chain_index]
1816
0
                                                            .fork_id
1817
0
                                                            .as_deref(),
1818
0
                                                    },
1819
0
                                                    _ => unreachable!(),
1820
                                                },
1821
                                            ),
1822
0
                                            self.notifications_protocol_handshake_timeout(
1823
0
                                                other_protocol,
1824
                                            ),
1825
0
                                            self.notifications_protocol_handshake(other_protocol),
1826
0
                                            self.notifications_protocol_max_handshake_size(
1827
0
                                                other_protocol,
1828
                                            ),
1829
                                        );
1830
1831
0
                                        self.substreams.insert(
1832
0
                                            new_substream_id,
1833
0
                                            SubstreamInfo {
1834
0
                                                connection_id,
1835
0
                                                protocol: Some(Protocol::Notifications(
1836
0
                                                    other_protocol,
1837
0
                                                )),
1838
0
                                            },
1839
                                        );
1840
1841
0
                                        self.notification_substreams_by_peer_id.insert((
1842
0
                                            other_protocol,
1843
0
                                            peer_index,
1844
0
                                            SubstreamDirection::Out,
1845
0
                                            NotificationsSubstreamState::Pending,
1846
0
                                            new_substream_id,
1847
0
                                        ));
1848
                                    }
1849
1850
0
                                    return Some(Event::GossipConnected {
1851
0
                                        peer_id: self.peers[peer_index.0].clone(),
1852
0
                                        chain_id: ChainId(chain_index),
1853
0
                                        kind: GossipKind::ConsensusTransactions,
1854
0
                                        role: decoded_handshake.role,
1855
0
                                        best_number: decoded_handshake.best_number,
1856
0
                                        best_hash: *decoded_handshake.best_hash,
1857
0
                                    });
1858
                                }
1859
0
                                Err(error) => {
1860
0
                                    if self
1861
0
                                        .connections_by_peer_id
1862
0
                                        .range(
1863
0
                                            (peer_index, ConnectionId::MIN)
1864
0
                                                ..=(peer_index, ConnectionId::MIN),
1865
0
                                        )
1866
0
                                        .any(|(_, c)| {
1867
                                            let state = self.inner.connection_state(*c);
1868
                                            state.established && !state.shutting_down
1869
                                        })
1870
0
                                        && self.gossip_desired_peers_by_chain.contains(&(
1871
0
                                            chain_index,
1872
0
                                            GossipKind::ConsensusTransactions,
1873
0
                                            peer_index,
1874
0
                                        ))
1875
                                    {
1876
0
                                        debug_assert!(self
1877
0
                                            .notification_substreams_by_peer_id
1878
0
                                            .range(
1879
0
                                                (
1880
0
                                                    NotificationsProtocol::BlockAnnounces {
1881
0
                                                        chain_index
1882
0
                                                    },
1883
0
                                                    peer_index,
1884
0
                                                    SubstreamDirection::Out,
1885
0
                                                    NotificationsSubstreamState::OPEN_MIN_VALUE,
1886
0
                                                    SubstreamId::MIN,
1887
0
                                                )
1888
0
                                                    ..=(
1889
0
                                                        NotificationsProtocol::BlockAnnounces {
1890
0
                                                            chain_index
1891
0
                                                        },
1892
0
                                                        peer_index,
1893
0
                                                        SubstreamDirection::Out,
1894
0
                                                        NotificationsSubstreamState::OPEN_MAX_VALUE,
1895
0
                                                        SubstreamId::MAX,
1896
0
                                                    ),
1897
0
                                            )
1898
0
                                            .next()
1899
0
                                            .is_none());
1900
1901
0
                                        self.connected_unopened_gossip_desired.insert((
1902
0
                                            peer_index,
1903
0
                                            ChainId(chain_index),
1904
0
                                            GossipKind::ConsensusTransactions,
1905
0
                                        ));
1906
0
                                    }
1907
1908
0
                                    self.opened_gossip_undesired.remove(&(
1909
0
                                        ChainId(chain_index),
1910
0
                                        peer_index,
1911
0
                                        GossipKind::ConsensusTransactions,
1912
0
                                    ));
1913
1914
                                    // TODO: pretty hacky
1915
                                    if let GossipConnectError::HandshakeDecode(_)
1916
0
                                    | GossipConnectError::GenesisMismatch { .. } = error
1917
0
                                    {
1918
0
                                        self.inner.close_out_notifications(substream_id);
1919
0
                                        self.substreams.remove(&substream_id).unwrap();
1920
0
                                    }
1921
1922
                                    // Close all the notification substreams of that chain.
1923
0
                                    for other_protocol in [
1924
0
                                        NotificationsProtocol::BlockAnnounces { chain_index },
1925
0
                                        NotificationsProtocol::Transactions { chain_index },
1926
0
                                        NotificationsProtocol::Grandpa { chain_index },
1927
                                    ] {
1928
0
                                        for (substream_id, direction, state) in self
1929
0
                                            .notification_substreams_by_peer_id
1930
0
                                            .range(
1931
0
                                                (
1932
0
                                                    other_protocol,
1933
0
                                                    peer_index,
1934
0
                                                    SubstreamDirection::MIN,
1935
0
                                                    NotificationsSubstreamState::MIN,
1936
0
                                                    SubstreamId::MIN,
1937
0
                                                )
1938
0
                                                    ..=(
1939
0
                                                        other_protocol,
1940
0
                                                        peer_index,
1941
0
                                                        SubstreamDirection::MAX,
1942
0
                                                        NotificationsSubstreamState::MAX,
1943
0
                                                        SubstreamId::MAX,
1944
0
                                                    ),
1945
                                            )
1946
0
                                            .map(|(_, _, dir, state, s)| (*s, *dir, *state))
1947
0
                                            .collect::<Vec<_>>()
1948
                                        {
1949
0
                                            match (direction, state) {
1950
                                                (SubstreamDirection::Out, _) => {
1951
0
                                                    self.inner
1952
0
                                                        .close_out_notifications(substream_id);
1953
1954
0
                                                    let _was_in = self
1955
0
                                                        .notification_substreams_by_peer_id
1956
0
                                                        .remove(&(
1957
0
                                                            other_protocol,
1958
0
                                                            peer_index,
1959
0
                                                            direction,
1960
0
                                                            state,
1961
0
                                                            substream_id,
1962
0
                                                        ));
1963
0
                                                    debug_assert!(_was_in);
1964
0
                                                    let _was_in =
1965
0
                                                        self.substreams.remove(&substream_id);
1966
0
                                                    debug_assert!(_was_in.is_some());
1967
                                                }
1968
                                                (
1969
                                                    SubstreamDirection::In,
1970
                                                    NotificationsSubstreamState::Pending,
1971
                                                ) => {
1972
0
                                                    self.inner
1973
0
                                                        .reject_in_notifications(substream_id);
1974
1975
0
                                                    let _was_in = self
1976
0
                                                        .notification_substreams_by_peer_id
1977
0
                                                        .remove(&(
1978
0
                                                            other_protocol,
1979
0
                                                            peer_index,
1980
0
                                                            direction,
1981
0
                                                            state,
1982
0
                                                            substream_id,
1983
0
                                                        ));
1984
0
                                                    debug_assert!(_was_in);
1985
0
                                                    let _was_in =
1986
0
                                                        self.substreams.remove(&substream_id);
1987
0
                                                    debug_assert!(_was_in.is_some());
1988
                                                }
1989
                                                (
1990
                                                    SubstreamDirection::In,
1991
                                                    NotificationsSubstreamState::Open {
1992
                                                        asked_to_leave: false,
1993
                                                    },
1994
                                                ) => {
1995
0
                                                    self.inner.start_close_in_notifications(
1996
0
                                                        substream_id,
1997
0
                                                        Duration::from_secs(5),
1998
                                                    ); // TODO: arbitrary constant
1999
2000
0
                                                    let _was_removed = self
2001
0
                                                        .notification_substreams_by_peer_id
2002
0
                                                        .remove(&(
2003
0
                                                            other_protocol,
2004
0
                                                            peer_index,
2005
0
                                                            SubstreamDirection::In,
2006
0
                                                            NotificationsSubstreamState::Open {
2007
0
                                                                asked_to_leave: false,
2008
0
                                                            },
2009
0
                                                            substream_id,
2010
0
                                                        ));
2011
0
                                                    debug_assert!(_was_removed);
2012
0
                                                    let _was_inserted = self
2013
0
                                                        .notification_substreams_by_peer_id
2014
0
                                                        .insert((
2015
0
                                                            other_protocol,
2016
0
                                                            peer_index,
2017
0
                                                            SubstreamDirection::In,
2018
0
                                                            NotificationsSubstreamState::Open {
2019
0
                                                                asked_to_leave: true,
2020
0
                                                            },
2021
0
                                                            substream_id,
2022
0
                                                        ));
2023
0
                                                    debug_assert!(_was_inserted);
2024
                                                }
2025
                                                (
2026
                                                    SubstreamDirection::In,
2027
                                                    NotificationsSubstreamState::Open {
2028
                                                        asked_to_leave: true,
2029
                                                    },
2030
0
                                                ) => {
2031
0
                                                    // Nothing to do.
2032
0
                                                }
2033
                                            }
2034
                                        }
2035
                                    }
2036
2037
0
                                    return Some(Event::GossipOpenFailed {
2038
0
                                        peer_id: self.peers[peer_index.0].clone(),
2039
0
                                        chain_id: ChainId(chain_index),
2040
0
                                        kind: GossipKind::ConsensusTransactions,
2041
0
                                        error,
2042
0
                                    });
2043
                                }
2044
                            }
2045
                        }
2046
2047
0
                        NotificationsProtocol::Transactions { chain_index }
2048
0
                        | NotificationsProtocol::Grandpa { chain_index } => {
2049
                            // TODO: doesn't check the handshakes
2050
2051
                            // This can only happen if we have a block announces substream with
2052
                            // that peer, otherwise the substream opening attempt should have
2053
                            // been cancelled.
2054
0
                            debug_assert!(
2055
0
                                self.notification_substreams_by_peer_id
2056
0
                                    .range(
2057
0
                                        (
2058
0
                                            NotificationsProtocol::BlockAnnounces { chain_index },
2059
0
                                            peer_index,
2060
0
                                            SubstreamDirection::Out,
2061
0
                                            NotificationsSubstreamState::OPEN_MIN_VALUE,
2062
0
                                            SubstreamId::MIN
2063
0
                                        )
2064
0
                                            ..=(
2065
0
                                                NotificationsProtocol::BlockAnnounces {
2066
0
                                                    chain_index
2067
0
                                                },
2068
0
                                                peer_index,
2069
0
                                                SubstreamDirection::Out,
2070
0
                                                NotificationsSubstreamState::OPEN_MAX_VALUE,
2071
0
                                                SubstreamId::MAX
2072
0
                                            )
2073
0
                                    )
2074
0
                                    .next()
2075
0
                                    .is_some()
2076
                            );
2077
2078
                            // If the substream failed to open, we simply try again.
2079
                            // Trying again means that we might be hammering the remote with
2080
                            // substream requests, however as of the writing of this text this is
2081
                            // necessary in order to bypass an issue in Substrate.
2082
                            // Note that in the situation where the connection is shutting down,
2083
                            // we don't re-open the substream on a different connection, but
2084
                            // that's ok as the block announces substream should be closed soon.
2085
0
                            if result.is_err() {
2086
0
                                if self.inner.connection_state(connection_id).shutting_down {
2087
0
                                    continue;
2088
0
                                }
2089
2090
0
                                let new_substream_id = self.inner.open_out_notifications(
2091
0
                                    connection_id,
2092
0
                                    codec::encode_protocol_name_string(match substream_protocol {
2093
                                        NotificationsProtocol::Transactions { .. } => {
2094
0
                                            codec::ProtocolName::Transactions {
2095
0
                                                genesis_hash: self.chains[chain_index].genesis_hash,
2096
0
                                                fork_id: self.chains[chain_index]
2097
0
                                                    .fork_id
2098
0
                                                    .as_deref(),
2099
0
                                            }
2100
                                        }
2101
                                        NotificationsProtocol::Grandpa { .. } => {
2102
0
                                            codec::ProtocolName::Grandpa {
2103
0
                                                genesis_hash: self.chains[chain_index].genesis_hash,
2104
0
                                                fork_id: self.chains[chain_index]
2105
0
                                                    .fork_id
2106
0
                                                    .as_deref(),
2107
0
                                            }
2108
                                        }
2109
0
                                        _ => unreachable!(),
2110
                                    }),
2111
0
                                    self.notifications_protocol_handshake_timeout(
2112
0
                                        substream_protocol,
2113
                                    ),
2114
0
                                    self.notifications_protocol_handshake(substream_protocol),
2115
0
                                    self.notifications_protocol_max_handshake_size(
2116
0
                                        substream_protocol,
2117
                                    ),
2118
                                );
2119
0
                                let _was_inserted =
2120
0
                                    self.notification_substreams_by_peer_id.insert((
2121
0
                                        substream_protocol,
2122
0
                                        peer_index,
2123
0
                                        SubstreamDirection::Out,
2124
0
                                        NotificationsSubstreamState::Pending,
2125
0
                                        new_substream_id,
2126
0
                                    ));
2127
0
                                debug_assert!(_was_inserted);
2128
0
                                let _prev_value = self.substreams.insert(
2129
0
                                    new_substream_id,
2130
0
                                    SubstreamInfo {
2131
0
                                        connection_id,
2132
0
                                        protocol: substream_info.protocol,
2133
0
                                    },
2134
                                );
2135
0
                                debug_assert!(_prev_value.is_none());
2136
0
                                continue;
2137
0
                            }
2138
2139
0
                            let _was_inserted = self.notification_substreams_by_peer_id.insert((
2140
0
                                substream_protocol,
2141
0
                                peer_index,
2142
0
                                SubstreamDirection::Out,
2143
0
                                NotificationsSubstreamState::Open {
2144
0
                                    asked_to_leave: false,
2145
0
                                },
2146
0
                                substream_id,
2147
0
                            ));
2148
0
                            debug_assert!(_was_inserted);
2149
2150
                            // In case of Grandpa, we immediately send a neighbor packet with
2151
                            // the current local state.
2152
0
                            if matches!(substream_protocol, NotificationsProtocol::Grandpa { .. }) {
2153
0
                                let grandpa_state = &self.chains[chain_index]
2154
0
                                    .grandpa_protocol_config
2155
0
                                    .as_ref()
2156
0
                                    .unwrap();
2157
0
                                let packet = codec::GrandpaNotificationRef::Neighbor(
2158
0
                                    codec::NeighborPacket {
2159
0
                                        round_number: grandpa_state.round_number,
2160
0
                                        set_id: grandpa_state.set_id,
2161
0
                                        commit_finalized_height: grandpa_state
2162
0
                                            .commit_finalized_height,
2163
0
                                    },
2164
0
                                )
2165
0
                                .scale_encoding(self.chains[chain_index].block_number_bytes)
2166
0
                                .fold(Vec::new(), |mut a, b| {
2167
                                    a.extend_from_slice(b.as_ref());
2168
                                    a
2169
                                });
2170
0
                                match self.inner.queue_notification(substream_id, packet) {
2171
0
                                    Ok(()) => {}
2172
                                    Err(collection::QueueNotificationError::QueueFull) => {
2173
0
                                        unreachable!()
2174
                                    }
2175
                                }
2176
0
                            }
2177
                        }
2178
                    }
2179
                }
2180
2181
0
                collection::Event::NotificationsOutCloseDemanded { substream_id }
2182
0
                | collection::Event::NotificationsOutReset { substream_id } => {
2183
                    // Outgoing notifications substream has been closed or must be closed.
2184
                    // These two situations are handled together, as we immediately react to a
2185
                    // demanded closing by performing the closing. The rest of the code is thus
2186
                    // the same for both situations.
2187
2188
                    // If the request demands the closing, we immediately comply.
2189
0
                    if matches!(
2190
0
                        inner_event,
2191
                        collection::Event::NotificationsOutCloseDemanded { .. }
2192
0
                    ) {
2193
0
                        self.inner.close_out_notifications(substream_id);
2194
0
                    }
2195
2196
                    // Load various information about the substream and connection.
2197
0
                    let substream_info = self
2198
0
                        .substreams
2199
0
                        .remove(&substream_id)
2200
0
                        .unwrap_or_else(|| unreachable!());
2201
0
                    let connection_id = substream_info.connection_id;
2202
0
                    let peer_index = *self.inner[connection_id]
2203
0
                        .peer_index
2204
0
                        .as_ref()
2205
0
                        .unwrap_or_else(|| unreachable!());
2206
2207
                    // All outgoing substream attempts are cancelled when a chain is removed, as
2208
                    // such `protocol` can't be `None`.
2209
0
                    let Some(Protocol::Notifications(substream_protocol)) = substream_info.protocol
2210
                    else {
2211
0
                        unreachable!();
2212
                    };
2213
2214
                    // Clean up the local state.
2215
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
2216
0
                        substream_protocol,
2217
0
                        peer_index,
2218
0
                        SubstreamDirection::Out,
2219
0
                        NotificationsSubstreamState::Open {
2220
0
                            asked_to_leave: false,
2221
0
                        },
2222
0
                        substream_id,
2223
0
                    ));
2224
0
                    debug_assert!(_was_in);
2225
2226
                    // Rest of the code depends on the protocol.
2227
0
                    match substream_protocol {
2228
0
                        NotificationsProtocol::BlockAnnounces { chain_index } => {
2229
0
                            self.opened_gossip_undesired.remove(&(
2230
0
                                ChainId(chain_index),
2231
0
                                peer_index,
2232
0
                                GossipKind::ConsensusTransactions,
2233
0
                            ));
2234
2235
                            // Insert back in `connected_unopened_gossip_desired` if relevant.
2236
0
                            if self.gossip_desired_peers_by_chain.contains(&(
2237
0
                                chain_index,
2238
0
                                GossipKind::ConsensusTransactions,
2239
0
                                peer_index,
2240
0
                            )) && self
2241
0
                                .connections_by_peer_id
2242
0
                                .range(
2243
0
                                    (peer_index, ConnectionId::MIN)
2244
0
                                        ..=(peer_index, ConnectionId::MAX),
2245
0
                                )
2246
0
                                .any(|(_, connection_id)| {
2247
                                    let state = self.inner.connection_state(*connection_id);
2248
                                    state.established && !state.shutting_down
2249
                                })
2250
                            {
2251
0
                                debug_assert!(
2252
0
                                    self.notification_substreams_by_peer_id
2253
0
                                        .range(
2254
0
                                            (
2255
0
                                                NotificationsProtocol::BlockAnnounces {
2256
0
                                                    chain_index
2257
0
                                                },
2258
0
                                                peer_index,
2259
0
                                                SubstreamDirection::Out,
2260
0
                                                NotificationsSubstreamState::MIN,
2261
0
                                                SubstreamId::MIN,
2262
0
                                            )
2263
0
                                                ..=(
2264
0
                                                    NotificationsProtocol::BlockAnnounces {
2265
0
                                                        chain_index
2266
0
                                                    },
2267
0
                                                    peer_index,
2268
0
                                                    SubstreamDirection::Out,
2269
0
                                                    NotificationsSubstreamState::MAX,
2270
0
                                                    SubstreamId::MAX,
2271
0
                                                ),
2272
0
                                        )
2273
0
                                        .next()
2274
0
                                        .is_none()
2275
                                );
2276
2277
0
                                let _was_inserted =
2278
0
                                    self.connected_unopened_gossip_desired.insert((
2279
0
                                        peer_index,
2280
0
                                        ChainId(chain_index),
2281
0
                                        GossipKind::ConsensusTransactions,
2282
0
                                    ));
2283
0
                                debug_assert!(_was_inserted);
2284
0
                            }
2285
2286
                            // The transactions and Grandpa protocols are tied to the block
2287
                            // announces substream. As such, we also close any transactions or
2288
                            // grandpa substream, either pending or fully opened.
2289
0
                            for proto in [
2290
0
                                NotificationsProtocol::Transactions { chain_index },
2291
0
                                NotificationsProtocol::Grandpa { chain_index },
2292
                            ] {
2293
0
                                for (substream_direction, substream_state, substream_id) in self
2294
0
                                    .notification_substreams_by_peer_id
2295
0
                                    .range(
2296
0
                                        (
2297
0
                                            proto,
2298
0
                                            peer_index,
2299
0
                                            SubstreamDirection::MIN,
2300
0
                                            NotificationsSubstreamState::MIN,
2301
0
                                            SubstreamId::MIN,
2302
0
                                        )
2303
0
                                            ..=(
2304
0
                                                proto,
2305
0
                                                peer_index,
2306
0
                                                SubstreamDirection::MAX,
2307
0
                                                NotificationsSubstreamState::MAX,
2308
0
                                                SubstreamId::MAX,
2309
0
                                            ),
2310
                                    )
2311
0
                                    .map(|(_, _, direction, state, substream_id)| {
2312
                                        (*direction, *state, *substream_id)
2313
                                    })
2314
0
                                    .collect::<Vec<_>>()
2315
                                {
2316
0
                                    match (substream_direction, substream_state) {
2317
                                        (SubstreamDirection::Out, _) => {
2318
0
                                            self.inner.close_out_notifications(substream_id);
2319
0
                                            let _was_removed =
2320
0
                                                self.notification_substreams_by_peer_id.remove(&(
2321
0
                                                    proto,
2322
0
                                                    peer_index,
2323
0
                                                    SubstreamDirection::Out,
2324
0
                                                    substream_state,
2325
0
                                                    substream_id,
2326
0
                                                ));
2327
0
                                            debug_assert!(_was_removed);
2328
0
                                            self.substreams.remove(&substream_id);
2329
                                        }
2330
                                        (
2331
                                            SubstreamDirection::In,
2332
                                            NotificationsSubstreamState::Pending,
2333
                                        ) => {
2334
                                            // Inbound notification substreams are always accepted
2335
                                            // or rejected immediately when a gossip link is open.
2336
0
                                            unreachable!()
2337
                                        }
2338
                                        (
2339
                                            SubstreamDirection::In,
2340
                                            NotificationsSubstreamState::Open {
2341
                                                asked_to_leave: true,
2342
                                            },
2343
0
                                        ) => {
2344
0
                                            // Nothing to do.
2345
0
                                        }
2346
                                        (
2347
                                            SubstreamDirection::In,
2348
                                            NotificationsSubstreamState::Open {
2349
                                                asked_to_leave: false,
2350
                                            },
2351
                                        ) => {
2352
0
                                            self.inner.start_close_in_notifications(
2353
0
                                                substream_id,
2354
0
                                                Duration::from_secs(5), // TODO: arbitrary constant
2355
                                            );
2356
0
                                            let _was_removed =
2357
0
                                                self.notification_substreams_by_peer_id.remove(&(
2358
0
                                                    proto,
2359
0
                                                    peer_index,
2360
0
                                                    SubstreamDirection::In,
2361
0
                                                    NotificationsSubstreamState::Open {
2362
0
                                                        asked_to_leave: false,
2363
0
                                                    },
2364
0
                                                    substream_id,
2365
0
                                                ));
2366
0
                                            debug_assert!(_was_removed);
2367
0
                                            let _was_inserted =
2368
0
                                                self.notification_substreams_by_peer_id.insert((
2369
0
                                                    proto,
2370
0
                                                    peer_index,
2371
0
                                                    SubstreamDirection::In,
2372
0
                                                    NotificationsSubstreamState::Open {
2373
0
                                                        asked_to_leave: true,
2374
0
                                                    },
2375
0
                                                    substream_id,
2376
0
                                                ));
2377
0
                                            debug_assert!(_was_inserted);
2378
                                        }
2379
                                    }
2380
                                }
2381
                            }
2382
2383
0
                            return Some(Event::GossipDisconnected {
2384
0
                                peer_id: self.peers[peer_index.0].clone(),
2385
0
                                chain_id: ChainId(chain_index),
2386
0
                                kind: GossipKind::ConsensusTransactions,
2387
0
                            });
2388
                        }
2389
2390
                        // The transactions and grandpa protocols are tied to the block announces
2391
                        // substream. If there is a block announce substream with the peer, we try
2392
                        // to reopen these two substreams.
2393
                        NotificationsProtocol::Transactions { .. }
2394
                        | NotificationsProtocol::Grandpa { .. } => {
2395
                            // Don't actually try to reopen if the connection is shutting down.
2396
                            // Note that we don't try to reopen on a different connection, as the
2397
                            // block announces substream will very soon be closed too anyway.
2398
0
                            if self.inner.connection_state(connection_id).shutting_down {
2399
0
                                continue;
2400
0
                            }
2401
2402
0
                            let new_substream_id = self.inner.open_out_notifications(
2403
0
                                connection_id,
2404
0
                                codec::encode_protocol_name_string(match substream_protocol {
2405
0
                                    NotificationsProtocol::Transactions { chain_index } => {
2406
0
                                        codec::ProtocolName::Transactions {
2407
0
                                            genesis_hash: self.chains[chain_index].genesis_hash,
2408
0
                                            fork_id: self.chains[chain_index].fork_id.as_deref(),
2409
0
                                        }
2410
                                    }
2411
0
                                    NotificationsProtocol::Grandpa { chain_index } => {
2412
0
                                        codec::ProtocolName::Grandpa {
2413
0
                                            genesis_hash: self.chains[chain_index].genesis_hash,
2414
0
                                            fork_id: self.chains[chain_index].fork_id.as_deref(),
2415
0
                                        }
2416
                                    }
2417
0
                                    _ => unreachable!(),
2418
                                }),
2419
0
                                self.notifications_protocol_handshake_timeout(substream_protocol),
2420
0
                                self.notifications_protocol_handshake(substream_protocol),
2421
0
                                self.notifications_protocol_max_handshake_size(substream_protocol),
2422
                            );
2423
0
                            self.substreams.insert(
2424
0
                                new_substream_id,
2425
0
                                SubstreamInfo {
2426
0
                                    connection_id,
2427
0
                                    protocol: Some(Protocol::Notifications(substream_protocol)),
2428
0
                                },
2429
                            );
2430
0
                            self.notification_substreams_by_peer_id.insert((
2431
0
                                substream_protocol,
2432
0
                                peer_index,
2433
0
                                SubstreamDirection::Out,
2434
0
                                NotificationsSubstreamState::Pending,
2435
0
                                new_substream_id,
2436
0
                            ));
2437
                        }
2438
                    }
2439
                }
2440
2441
0
                collection::Event::NotificationsInOpen { substream_id, .. } => {
2442
                    // Remote would like to open a notifications substream with us.
2443
2444
                    // There exists three possible ways to handle this event:
2445
                    //
2446
                    // - Accept the demand immediately. This happens if the API user has opened
2447
                    //   a gossip substream in the past or is currently trying to open a gossip
2448
                    //   substream with this peer.
2449
                    // - Refuse the demand immediately. This happens if there already exists a
2450
                    //   pending inbound notifications substream. Opening multiple notification
2451
                    //   substreams of the same protocol is a protocol violation. This also happens
2452
                    //   for transactions and grandpa substreams if no block announce substream is
2453
                    //   open.
2454
                    // - Generate an event to ask the API user whether to accept the demand. This
2455
                    //   happens specifically for block announce substreams.
2456
2457
                    // Extract various bits of information about the substream.
2458
                    // Instantly reject the substream if it concerns a chain that has since then
2459
                    // been removed from `self`, which can happen if the protocol name was already
2460
                    // negotiated when the chain was removed.
2461
0
                    let substream_info = self
2462
0
                        .substreams
2463
0
                        .get(&substream_id)
2464
0
                        .unwrap_or_else(|| unreachable!());
2465
0
                    let peer_index = *self.inner[substream_info.connection_id]
2466
0
                        .peer_index
2467
0
                        .as_ref()
2468
0
                        .unwrap_or_else(|| unreachable!());
2469
0
                    let Some(substream_protocol) = substream_info.protocol else {
2470
0
                        self.inner.reject_in_notifications(substream_id);
2471
0
                        self.substreams.remove(&substream_id);
2472
0
                        continue;
2473
                    };
2474
0
                    let Protocol::Notifications(substream_protocol) = substream_protocol else {
2475
0
                        unreachable!()
2476
                    };
2477
0
                    let (NotificationsProtocol::BlockAnnounces { chain_index }
2478
0
                    | NotificationsProtocol::Transactions { chain_index }
2479
0
                    | NotificationsProtocol::Grandpa { chain_index }) = substream_protocol;
2480
2481
                    // Check whether a substream with the same protocol already exists with that
2482
                    // peer, and if so deny the request.
2483
                    // Note that substreams with `asked_to_leave` equal to `true` are ignored when
2484
                    // searching, as in this case it's not a protocol violation.
2485
0
                    if self
2486
0
                        .notification_substreams_by_peer_id
2487
0
                        .range(
2488
0
                            (
2489
0
                                substream_protocol,
2490
0
                                peer_index,
2491
0
                                SubstreamDirection::In,
2492
0
                                NotificationsSubstreamState::MIN,
2493
0
                                SubstreamId::MIN,
2494
0
                            )
2495
0
                                ..(
2496
0
                                    substream_protocol,
2497
0
                                    peer_index,
2498
0
                                    SubstreamDirection::In,
2499
0
                                    NotificationsSubstreamState::Open {
2500
0
                                        asked_to_leave: true,
2501
0
                                    },
2502
0
                                    SubstreamId::MIN,
2503
0
                                ),
2504
0
                        )
2505
0
                        .next()
2506
0
                        .is_some()
2507
                    {
2508
0
                        self.inner.reject_in_notifications(substream_id);
2509
0
                        let _was_removed = self.substreams.remove(&substream_id);
2510
0
                        debug_assert!(_was_removed.is_some());
2511
0
                        continue;
2512
0
                    }
2513
2514
                    // If an outgoing block announces notifications protocol (either pending or
2515
                    // fully open) exists, accept the substream immediately.
2516
0
                    if self
2517
0
                        .notification_substreams_by_peer_id
2518
0
                        .range(
2519
0
                            (
2520
0
                                NotificationsProtocol::BlockAnnounces { chain_index },
2521
0
                                peer_index,
2522
0
                                SubstreamDirection::Out,
2523
0
                                NotificationsSubstreamState::MIN,
2524
0
                                SubstreamId::MIN,
2525
0
                            )
2526
0
                                ..=(
2527
0
                                    NotificationsProtocol::BlockAnnounces { chain_index },
2528
0
                                    peer_index,
2529
0
                                    SubstreamDirection::Out,
2530
0
                                    NotificationsSubstreamState::MAX,
2531
0
                                    SubstreamId::MAX,
2532
0
                                ),
2533
0
                        )
2534
0
                        .next()
2535
0
                        .is_some()
2536
                    {
2537
0
                        let _was_inserted = self.notification_substreams_by_peer_id.insert((
2538
0
                            substream_protocol,
2539
0
                            peer_index,
2540
0
                            SubstreamDirection::In,
2541
0
                            NotificationsSubstreamState::Open {
2542
0
                                asked_to_leave: false,
2543
0
                            },
2544
0
                            substream_id,
2545
0
                        ));
2546
0
                        debug_assert!(_was_inserted);
2547
0
                        self.inner.accept_in_notifications(
2548
0
                            substream_id,
2549
0
                            self.notifications_protocol_handshake(substream_protocol),
2550
0
                            self.notifications_protocol_max_notification_size(substream_protocol),
2551
                        );
2552
0
                        continue;
2553
0
                    }
2554
2555
                    // It is forbidden to cold-open a substream other than the block announces
2556
                    // substream.
2557
0
                    if !matches!(
2558
0
                        substream_protocol,
2559
                        NotificationsProtocol::BlockAnnounces { .. }
2560
                    ) {
2561
0
                        self.inner.reject_in_notifications(substream_id);
2562
0
                        let _was_removed = self.substreams.remove(&substream_id);
2563
0
                        debug_assert!(_was_removed.is_some());
2564
0
                        continue;
2565
0
                    }
2566
2567
                    // Update the local state and return the event.
2568
0
                    debug_assert!(matches!(
2569
0
                        substream_protocol,
2570
                        NotificationsProtocol::BlockAnnounces { .. }
2571
                    ));
2572
0
                    self.notification_substreams_by_peer_id.insert((
2573
0
                        substream_protocol,
2574
0
                        peer_index,
2575
0
                        SubstreamDirection::In,
2576
0
                        NotificationsSubstreamState::Pending,
2577
0
                        substream_id,
2578
0
                    ));
2579
0
                    return Some(Event::GossipInDesired {
2580
0
                        peer_id: self.peers[peer_index.0].clone(),
2581
0
                        chain_id: ChainId(chain_index),
2582
0
                        kind: GossipKind::ConsensusTransactions,
2583
0
                    });
2584
                }
2585
2586
0
                collection::Event::NotificationsInOpenCancel { substream_id } => {
2587
                    // Remote has cancelled a pending `NotificationsInOpen`.
2588
2589
0
                    let substream_info = self
2590
0
                        .substreams
2591
0
                        .remove(&substream_id)
2592
0
                        .unwrap_or_else(|| unreachable!());
2593
0
                    let peer_index = *self.inner[substream_info.connection_id]
2594
0
                        .peer_index
2595
0
                        .as_ref()
2596
0
                        .unwrap_or_else(|| unreachable!());
2597
2598
                    // All incoming notification substreams are immediately accepted/rejected
2599
                    // except for block announce substreams. Additionally, when a chain is removed,
2600
                    // all its pending block announce substreams are rejected. Therefore, this
2601
                    // event can only happen for block announce substreams.
2602
                    let Some(Protocol::Notifications(NotificationsProtocol::BlockAnnounces {
2603
0
                        chain_index,
2604
0
                    })) = substream_info.protocol
2605
                    else {
2606
0
                        unreachable!()
2607
                    };
2608
2609
                    // Clean up the local state.
2610
0
                    let _was_in = self.notification_substreams_by_peer_id.remove(&(
2611
0
                        NotificationsProtocol::BlockAnnounces { chain_index },
2612
0
                        peer_index,
2613
0
                        SubstreamDirection::In,
2614
0
                        NotificationsSubstreamState::Pending,
2615
0
                        substream_id,
2616
0
                    ));
2617
0
                    debug_assert!(_was_in);
2618
2619
                    // Notify API user.
2620
0
                    return Some(Event::GossipInDesiredCancel {
2621
0
                        peer_id: self.peers[peer_index.0].clone(),
2622
0
                        chain_id: ChainId(chain_index),
2623
0
                        kind: GossipKind::ConsensusTransactions,
2624
0
                    });
2625
                }
2626
2627
                collection::Event::NotificationsIn {
2628
0
                    substream_id,
2629
0
                    notification,
2630
                } => {
2631
                    // Received a notification from a remote.
2632
0
                    let substream_info = self
2633
0
                        .substreams
2634
0
                        .get(&substream_id)
2635
0
                        .unwrap_or_else(|| unreachable!());
2636
0
                    let substream_protocol = match substream_info.protocol {
2637
                        None => {
2638
                            // Substream concerns a chain that has been removed.
2639
                            // Ignore the notification.
2640
0
                            continue;
2641
                        }
2642
0
                        Some(Protocol::Notifications(p)) => p,
2643
0
                        Some(_) => unreachable!(),
2644
                    };
2645
0
                    let (NotificationsProtocol::BlockAnnounces { chain_index }
2646
0
                    | NotificationsProtocol::Transactions { chain_index }
2647
0
                    | NotificationsProtocol::Grandpa { chain_index }) = substream_protocol;
2648
0
                    let peer_index = *self.inner[substream_info.connection_id]
2649
0
                        .peer_index
2650
0
                        .as_ref()
2651
0
                        .unwrap_or_else(|| unreachable!());
2652
2653
                    // Check whether there is an open outgoing block announces substream, as this
2654
                    // means that we are "gossip-connected". If not, then the notification is
2655
                    // silently discarded.
2656
0
                    if self
2657
0
                        .notification_substreams_by_peer_id
2658
0
                        .range(
2659
0
                            (
2660
0
                                NotificationsProtocol::BlockAnnounces { chain_index },
2661
0
                                peer_index,
2662
0
                                SubstreamDirection::Out,
2663
0
                                NotificationsSubstreamState::OPEN_MIN_VALUE,
2664
0
                                collection::SubstreamId::MIN,
2665
0
                            )
2666
0
                                ..=(
2667
0
                                    NotificationsProtocol::BlockAnnounces { chain_index },
2668
0
                                    peer_index,
2669
0
                                    SubstreamDirection::Out,
2670
0
                                    NotificationsSubstreamState::OPEN_MAX_VALUE,
2671
0
                                    collection::SubstreamId::MAX,
2672
0
                                ),
2673
0
                        )
2674
0
                        .next()
2675
0
                        .is_none()
2676
                    {
2677
0
                        continue;
2678
0
                    }
2679
2680
                    // Decode the notification and return an event.
2681
0
                    match substream_protocol {
2682
                        NotificationsProtocol::BlockAnnounces { .. } => {
2683
0
                            if let Err(err) = codec::decode_block_announce(
2684
0
                                &notification,
2685
0
                                self.chains[chain_index].block_number_bytes,
2686
0
                            ) {
2687
0
                                return Some(Event::ProtocolError {
2688
0
                                    error: ProtocolError::BadBlockAnnounce(err),
2689
0
                                    peer_id: self.peers[peer_index.0].clone(),
2690
0
                                });
2691
0
                            }
2692
2693
0
                            return Some(Event::BlockAnnounce {
2694
0
                                chain_id: ChainId(chain_index),
2695
0
                                peer_id: self.peers[peer_index.0].clone(),
2696
0
                                announce: EncodedBlockAnnounce {
2697
0
                                    message: notification,
2698
0
                                    block_number_bytes: self.chains[chain_index].block_number_bytes,
2699
0
                                },
2700
0
                            });
2701
                        }
2702
0
                        NotificationsProtocol::Transactions { .. } => {
2703
0
                            // TODO: not implemented
2704
0
                        }
2705
                        NotificationsProtocol::Grandpa { .. } => {
2706
0
                            let decoded_notif = match codec::decode_grandpa_notification(
2707
0
                                &notification,
2708
0
                                self.chains[chain_index].block_number_bytes,
2709
0
                            ) {
2710
0
                                Ok(n) => n,
2711
0
                                Err(err) => {
2712
0
                                    return Some(Event::ProtocolError {
2713
0
                                        error: ProtocolError::BadGrandpaNotification(err),
2714
0
                                        peer_id: self.peers[peer_index.0].clone(),
2715
0
                                    });
2716
                                }
2717
                            };
2718
2719
0
                            match decoded_notif {
2720
                                codec::GrandpaNotificationRef::Commit(_) => {
2721
0
                                    return Some(Event::GrandpaCommitMessage {
2722
0
                                        chain_id: ChainId(chain_index),
2723
0
                                        peer_id: self.peers[peer_index.0].clone(),
2724
0
                                        message: EncodedGrandpaCommitMessage {
2725
0
                                            message: notification,
2726
0
                                            block_number_bytes: self.chains[chain_index]
2727
0
                                                .block_number_bytes,
2728
0
                                        },
2729
0
                                    });
2730
                                }
2731
0
                                codec::GrandpaNotificationRef::Neighbor(n) => {
2732
0
                                    return Some(Event::GrandpaNeighborPacket {
2733
0
                                        chain_id: ChainId(chain_index),
2734
0
                                        peer_id: self.peers[peer_index.0].clone(),
2735
0
                                        state: GrandpaState {
2736
0
                                            round_number: n.round_number,
2737
0
                                            set_id: n.set_id,
2738
0
                                            commit_finalized_height: n.commit_finalized_height,
2739
0
                                        },
2740
0
                                    });
2741
                                }
2742
0
                                _ => {
2743
0
                                    // Any other type of message is currently ignored. Support
2744
0
                                    // for them could be added in the future.
2745
0
                                }
2746
                            }
2747
                        }
2748
                    }
2749
                }
2750
2751
0
                collection::Event::NotificationsInClose { substream_id, .. } => {
2752
                    // An incoming notifications substream has been closed.
2753
                    // Nothing to do except clean up the local state.
2754
0
                    let Some(substream_info) = self.substreams.remove(&substream_id) else {
2755
0
                        unreachable!()
2756
                    };
2757
0
                    let peer_index = *self.inner[substream_info.connection_id]
2758
0
                        .peer_index
2759
0
                        .as_ref()
2760
0
                        .unwrap_or_else(|| unreachable!());
2761
0
                    let Some(protocol) = substream_info.protocol else {
2762
                        // Substream concerns a chain that has since then been removed.
2763
0
                        continue;
2764
                    };
2765
0
                    let Protocol::Notifications(protocol) = protocol else {
2766
0
                        unreachable!()
2767
                    };
2768
2769
                    // Clean up with both `asked_to_leave` equal to `true` or `false`, as we don't
2770
                    // know in which of the two the substream is.
2771
0
                    let _was_in1 = self.notification_substreams_by_peer_id.remove(&(
2772
0
                        protocol,
2773
0
                        peer_index,
2774
0
                        SubstreamDirection::In,
2775
0
                        NotificationsSubstreamState::Open {
2776
0
                            asked_to_leave: false,
2777
0
                        },
2778
0
                        substream_id,
2779
0
                    ));
2780
0
                    let _was_in2 = self.notification_substreams_by_peer_id.remove(&(
2781
0
                        protocol,
2782
0
                        peer_index,
2783
0
                        SubstreamDirection::In,
2784
0
                        NotificationsSubstreamState::Open {
2785
0
                            asked_to_leave: true,
2786
0
                        },
2787
0
                        substream_id,
2788
0
                    ));
2789
0
                    debug_assert!(_was_in1 || _was_in2);
2790
                }
2791
2792
0
                collection::Event::PingOutSuccess { id, ping_time } => {
2793
                    // The connection is necessarily past its handshake phase, and thus
2794
                    // the `peer_index` is necessarily known and valid.
2795
0
                    let Some(peer_index) = self.inner[id].peer_index else {
2796
0
                        unreachable!()
2797
                    };
2798
0
                    return Some(Event::PingOutSuccess {
2799
0
                        id,
2800
0
                        peer_id: self.peers[peer_index.0].clone(),
2801
0
                        ping_time,
2802
0
                    });
2803
                }
2804
            }
2805
        }
2806
138
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE10next_eventB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE10next_eventB24_
2807
2808
    /// Sends a blocks request to the given peer.
2809
    ///
2810
    /// The code in this module does not verify the response in any way. The blocks might be
2811
    /// completely different from the ones requested, or might be missing some information. In
2812
    /// other words, the response is completely untrusted.
2813
    ///
2814
    /// This function might generate a message destined a connection. Use
2815
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
2816
    ///
2817
    /// # Panic
2818
    ///
2819
    /// Panics if the [`ChainId`] is invalid.
2820
    ///
2821
    // TODO: more docs
2822
0
    pub fn start_blocks_request(
2823
0
        &mut self,
2824
0
        target: &PeerId,
2825
0
        chain_id: ChainId,
2826
0
        config: codec::BlocksRequestConfig,
2827
0
        timeout: Duration,
2828
0
    ) -> Result<SubstreamId, StartRequestError> {
2829
0
        let request_data = codec::build_block_request(
2830
0
            self.chains[chain_id.0].block_number_bytes,
2831
0
            &config,
2832
        )
2833
0
        .fold(Vec::new(), |mut a, b| {
2834
0
            a.extend_from_slice(b.as_ref());
2835
0
            a
2836
0
        });
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE20start_blocks_request0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE20start_blocks_request0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE20start_blocks_request0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE20start_blocks_request0B26_
2837
2838
0
        self.start_request(
2839
0
            target,
2840
0
            request_data,
2841
0
            Protocol::Sync {
2842
0
                chain_index: chain_id.0,
2843
0
            },
2844
0
            timeout,
2845
        )
2846
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE20start_blocks_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE20start_blocks_requestB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE20start_blocks_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE20start_blocks_requestB24_
2847
2848
    ///
2849
    /// # Panic
2850
    ///
2851
    /// Panics if the [`ChainId`] is invalid.
2852
    ///
2853
    // TODO: docs
2854
0
    pub fn start_grandpa_warp_sync_request(
2855
0
        &mut self,
2856
0
        target: &PeerId,
2857
0
        chain_id: ChainId,
2858
0
        begin_hash: [u8; 32],
2859
0
        timeout: Duration,
2860
0
    ) -> Result<SubstreamId, StartRequestError> {
2861
0
        let request_data = begin_hash.to_vec();
2862
2863
0
        self.start_request(
2864
0
            target,
2865
0
            request_data,
2866
0
            Protocol::SyncWarp {
2867
0
                chain_index: chain_id.0,
2868
0
            },
2869
0
            timeout,
2870
        )
2871
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE31start_grandpa_warp_sync_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE31start_grandpa_warp_sync_requestB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE31start_grandpa_warp_sync_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE31start_grandpa_warp_sync_requestB24_
2872
2873
    /// Sends a state request to a peer.
2874
    ///
2875
    /// A state request makes it possible to download the storage of the chain at a given block.
2876
    /// The response is not unverified by this function. In other words, the peer is free to send
2877
    /// back erroneous data. It is the responsibility of the API user to verify the storage by
2878
    /// calculating the state trie root hash and comparing it with the value stored in the
2879
    /// block's header.
2880
    ///
2881
    /// Because response have a size limit, it is unlikely that a single request will return the
2882
    /// entire storage of the chain at once. Instead, call this function multiple times, each call
2883
    /// passing a `start_key` that follows the last key of the previous response.
2884
    ///
2885
    /// This function might generate a message destined a connection. Use
2886
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
2887
    ///
2888
    /// # Panic
2889
    ///
2890
    /// Panics if the [`ChainId`] is invalid.
2891
    ///
2892
0
    pub fn start_state_request(
2893
0
        &mut self,
2894
0
        target: &PeerId,
2895
0
        chain_id: ChainId,
2896
0
        block_hash: &[u8; 32],
2897
0
        start_key: codec::StateRequestStart,
2898
0
        timeout: Duration,
2899
0
    ) -> Result<SubstreamId, StartRequestError> {
2900
0
        let request_data = codec::build_state_request(codec::StateRequest {
2901
0
            block_hash,
2902
0
            start_key,
2903
0
        })
2904
0
        .fold(Vec::new(), |mut a, b| {
2905
0
            a.extend_from_slice(b.as_ref());
2906
0
            a
2907
0
        });
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE19start_state_request0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE19start_state_request0Bb_
2908
2909
0
        self.start_request(
2910
0
            target,
2911
0
            request_data,
2912
0
            Protocol::State {
2913
0
                chain_index: chain_id.0,
2914
0
            },
2915
0
            timeout,
2916
        )
2917
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE19start_state_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE19start_state_requestB9_
2918
2919
    /// Sends a storage request to the given peer.
2920
    ///
2921
    /// This function might generate a message destined a connection. Use
2922
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
2923
    ///
2924
    /// # Panic
2925
    ///
2926
    /// Panics if the [`ChainId`] is invalid.
2927
    ///
2928
    // TODO: more docs
2929
0
    pub fn start_storage_proof_request(
2930
0
        &mut self,
2931
0
        target: &PeerId,
2932
0
        chain_id: ChainId,
2933
0
        config: codec::StorageProofRequestConfig<impl Iterator<Item = impl AsRef<[u8]> + Clone>>,
2934
0
        timeout: Duration,
2935
0
    ) -> Result<SubstreamId, StartRequestMaybeTooLargeError> {
2936
0
        let request_data =
2937
0
            codec::build_storage_proof_request(config).fold(Vec::new(), |mut a, b| {
2938
0
                a.extend_from_slice(b.as_ref());
2939
0
                a
2940
0
            });
Unexecuted instantiation: _RNCINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB8_12ChainNetworkpppE27start_storage_proof_requestppE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBc_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE27start_storage_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB4G_9into_iter8IntoIterB4D_EE0B1c_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkpppE27start_storage_proof_requestppE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBc_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE27start_storage_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB5F_9into_iter8IntoIterB5C_EE0B27_
2941
2942
        // The request data can possibly by higher than the protocol limit, especially due to the
2943
        // call data.
2944
        // TODO: check limit
2945
2946
0
        Ok(self.start_request(
2947
0
            target,
2948
0
            request_data,
2949
0
            Protocol::LightStorage {
2950
0
                chain_index: chain_id.0,
2951
0
            },
2952
0
            timeout,
2953
0
        )?)
2954
0
    }
Unexecuted instantiation: _RINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB6_12ChainNetworkpppE27start_storage_proof_requestppEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBa_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE27start_storage_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB4E_9into_iter8IntoIterB4B_EEB1a_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkpppE27start_storage_proof_requestppEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBa_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE27start_storage_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB5D_9into_iter8IntoIterB5A_EEB25_
2955
2956
    /// Sends a call proof request to the given peer.
2957
    ///
2958
    /// This request is similar to [`ChainNetwork::start_storage_proof_request`]. Instead of
2959
    /// requesting specific keys, we request the list of all the keys that are accessed for a
2960
    /// specific runtime call.
2961
    ///
2962
    /// There exists no guarantee that the proof is complete (i.e. that it contains all the
2963
    /// necessary entries), as it is impossible to know this from just the proof itself. As such,
2964
    /// this method is just an optimization. When performing the actual call, regular storage proof
2965
    /// requests should be performed if the key is not present in the call proof response.
2966
    ///
2967
    /// This function might generate a message destined a connection. Use
2968
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
2969
    ///
2970
    /// # Panic
2971
    ///
2972
    /// Panics if the [`ChainId`] is invalid.
2973
    ///
2974
0
    pub fn start_call_proof_request(
2975
0
        &mut self,
2976
0
        target: &PeerId,
2977
0
        chain_id: ChainId,
2978
0
        config: codec::CallProofRequestConfig<'_, impl Iterator<Item = impl AsRef<[u8]>>>,
2979
0
        timeout: Duration,
2980
0
    ) -> Result<SubstreamId, StartRequestMaybeTooLargeError> {
2981
0
        let request_data = codec::build_call_proof_request(config).fold(Vec::new(), |mut a, b| {
2982
0
            a.extend_from_slice(b.as_ref());
2983
0
            a
2984
0
        });
Unexecuted instantiation: _RNCINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB8_12ChainNetworkpppE24start_call_proof_requestppE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBc_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE24start_call_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB4D_9into_iter8IntoIterB4A_EE0B1c_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkpppE24start_call_proof_requestppE0Bc_
Unexecuted instantiation: _RNCINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB8_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBc_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE24start_call_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB5C_9into_iter8IntoIterB5z_EE0B27_
2985
2986
        // The request data can possibly by higher than the protocol limit, especially due to the
2987
        // call data.
2988
        // TODO: check limit
2989
2990
0
        Ok(self.start_request(
2991
0
            target,
2992
0
            request_data,
2993
0
            Protocol::LightCall {
2994
0
                chain_index: chain_id.0,
2995
0
            },
2996
0
            timeout,
2997
0
        )?)
2998
0
    }
Unexecuted instantiation: _RINvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB6_12ChainNetworkpppE24start_call_proof_requestppEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBa_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE24start_call_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB4B_9into_iter8IntoIterB4y_EEB1a_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkpppE24start_call_proof_requestppEBa_
Unexecuted instantiation: _RINvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB6_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBa_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE24start_call_proof_requestINtNtCsaFPxhswmqCN_5alloc3vec3VechEINtNtB5A_9into_iter8IntoIterB5x_EEB25_
2999
3000
    /// Sends a Kademlia find node request to the given peer.
3001
    ///
3002
    /// This function might generate a message destined a connection. Use
3003
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
3004
    ///
3005
    /// # Panic
3006
    ///
3007
    /// Panics if the [`ChainId`] is invalid.
3008
    ///
3009
0
    pub fn start_kademlia_find_node_request(
3010
0
        &mut self,
3011
0
        target: &PeerId,
3012
0
        chain_id: ChainId,
3013
0
        peer_id_to_find: &PeerId,
3014
0
        timeout: Duration,
3015
0
    ) -> Result<SubstreamId, StartRequestError> {
3016
0
        let request_data = codec::build_find_node_request(peer_id_to_find.as_bytes());
3017
3018
        // The request data can possibly by higher than the protocol limit, especially due to the
3019
        // call data.
3020
        // TODO: check limit
3021
3022
0
        self.start_request(
3023
0
            target,
3024
0
            request_data,
3025
0
            Protocol::Kad {
3026
0
                chain_index: chain_id.0,
3027
0
            },
3028
0
            timeout,
3029
        )
3030
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE32start_kademlia_find_node_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32start_kademlia_find_node_requestB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE32start_kademlia_find_node_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32start_kademlia_find_node_requestB24_
3031
3032
    /// Underlying implementation of all the functions that start requests.
3033
0
    fn start_request(
3034
0
        &mut self,
3035
0
        target: &PeerId,
3036
0
        request_data: Vec<u8>,
3037
0
        protocol: Protocol,
3038
0
        timeout: Duration,
3039
0
    ) -> Result<SubstreamId, StartRequestError> {
3040
0
        let Some(&peer_index) = self.peers_by_peer_id.get(target) else {
3041
            // If the `PeerId` is unknown, then we also don't have any connection to it.
3042
0
            return Err(StartRequestError::NoConnection);
3043
        };
3044
3045
        // TODO: this is O(n) but is it really a problem? you're only supposed to have max 1 or 2 connections per PeerId
3046
0
        let connection_id = self
3047
0
            .connections_by_peer_id
3048
0
            .range(
3049
0
                (peer_index, collection::ConnectionId::MIN)
3050
0
                    ..=(peer_index, collection::ConnectionId::MAX),
3051
            )
3052
0
            .map(|(_, connection_id)| *connection_id)
3053
0
            .find(|connection_id| {
3054
0
                let state = self.inner.connection_state(*connection_id);
3055
0
                state.established && !state.shutting_down
3056
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE13start_requests_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE13start_requests_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE13start_requests_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE13start_requests_0B26_
3057
0
            .ok_or(StartRequestError::NoConnection)?;
3058
3059
0
        let protocol_name = {
3060
0
            let protocol_name = match protocol {
3061
0
                Protocol::Identify => codec::ProtocolName::Identify,
3062
0
                Protocol::Ping => codec::ProtocolName::Ping,
3063
0
                Protocol::Notifications(NotificationsProtocol::BlockAnnounces { chain_index }) => {
3064
0
                    let chain_info = &self.chains[chain_index];
3065
0
                    codec::ProtocolName::BlockAnnounces {
3066
0
                        genesis_hash: chain_info.genesis_hash,
3067
0
                        fork_id: chain_info.fork_id.as_deref(),
3068
0
                    }
3069
                }
3070
0
                Protocol::Notifications(NotificationsProtocol::Transactions { chain_index }) => {
3071
0
                    let chain_info = &self.chains[chain_index];
3072
0
                    codec::ProtocolName::Transactions {
3073
0
                        genesis_hash: chain_info.genesis_hash,
3074
0
                        fork_id: chain_info.fork_id.as_deref(),
3075
0
                    }
3076
                }
3077
0
                Protocol::Notifications(NotificationsProtocol::Grandpa { chain_index }) => {
3078
0
                    let chain_info = &self.chains[chain_index];
3079
0
                    codec::ProtocolName::Grandpa {
3080
0
                        genesis_hash: chain_info.genesis_hash,
3081
0
                        fork_id: chain_info.fork_id.as_deref(),
3082
0
                    }
3083
                }
3084
0
                Protocol::Sync { chain_index } => {
3085
0
                    let chain_info = &self.chains[chain_index];
3086
0
                    codec::ProtocolName::Sync {
3087
0
                        genesis_hash: chain_info.genesis_hash,
3088
0
                        fork_id: chain_info.fork_id.as_deref(),
3089
0
                    }
3090
                }
3091
0
                Protocol::LightUnknown { chain_index } => {
3092
0
                    let chain_info = &self.chains[chain_index];
3093
0
                    codec::ProtocolName::Light {
3094
0
                        genesis_hash: chain_info.genesis_hash,
3095
0
                        fork_id: chain_info.fork_id.as_deref(),
3096
0
                    }
3097
                }
3098
0
                Protocol::LightStorage { chain_index } => {
3099
0
                    let chain_info = &self.chains[chain_index];
3100
0
                    codec::ProtocolName::Light {
3101
0
                        genesis_hash: chain_info.genesis_hash,
3102
0
                        fork_id: chain_info.fork_id.as_deref(),
3103
0
                    }
3104
                }
3105
0
                Protocol::LightCall { chain_index } => {
3106
0
                    let chain_info = &self.chains[chain_index];
3107
0
                    codec::ProtocolName::Light {
3108
0
                        genesis_hash: chain_info.genesis_hash,
3109
0
                        fork_id: chain_info.fork_id.as_deref(),
3110
0
                    }
3111
                }
3112
0
                Protocol::Kad { chain_index } => {
3113
0
                    let chain_info = &self.chains[chain_index];
3114
0
                    codec::ProtocolName::Kad {
3115
0
                        genesis_hash: chain_info.genesis_hash,
3116
0
                        fork_id: chain_info.fork_id.as_deref(),
3117
0
                    }
3118
                }
3119
0
                Protocol::SyncWarp { chain_index } => {
3120
0
                    let chain_info = &self.chains[chain_index];
3121
0
                    codec::ProtocolName::SyncWarp {
3122
0
                        genesis_hash: chain_info.genesis_hash,
3123
0
                        fork_id: chain_info.fork_id.as_deref(),
3124
0
                    }
3125
                }
3126
0
                Protocol::State { chain_index } => {
3127
0
                    let chain_info = &self.chains[chain_index];
3128
0
                    codec::ProtocolName::State {
3129
0
                        genesis_hash: chain_info.genesis_hash,
3130
0
                        fork_id: chain_info.fork_id.as_deref(),
3131
0
                    }
3132
                }
3133
            };
3134
3135
0
            codec::encode_protocol_name_string(protocol_name)
3136
        };
3137
3138
0
        let substream_id = self.inner.start_request(
3139
0
            connection_id,
3140
0
            protocol_name,
3141
0
            Some(request_data),
3142
0
            timeout,
3143
0
            16 * 1024 * 1024,
3144
        );
3145
3146
0
        let _prev_value = self.substreams.insert(
3147
0
            substream_id,
3148
0
            SubstreamInfo {
3149
0
                connection_id,
3150
0
                protocol: Some(protocol),
3151
0
            },
3152
        );
3153
0
        debug_assert!(_prev_value.is_none());
3154
3155
0
        Ok(substream_id)
3156
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE13start_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE13start_requestB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE13start_requestB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE13start_requestB24_
3157
3158
    /// Responds to an identify request. Call this function in response to
3159
    /// a [`Event::IdentifyRequestIn`].
3160
    ///
3161
    /// Only the `agent_version` needs to be specified. The other fields are automatically
3162
    /// filled by the [`ChainNetwork`].
3163
    ///
3164
    /// This function might generate a message destined a connection. Use
3165
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
3166
    ///
3167
    /// # Panic
3168
    ///
3169
    /// Panics if the [`SubstreamId`] is invalid or doesn't correspond to a blocks request or
3170
    /// if the request has been cancelled with a [`Event::RequestInCancel`].
3171
    ///
3172
0
    pub fn respond_identify(&mut self, substream_id: SubstreamId, agent_version: &str) {
3173
0
        let substream_info = self.substreams.remove(&substream_id).unwrap();
3174
0
        assert!(matches!(
3175
0
            substream_info.protocol,
3176
            Some(Protocol::Identify { .. })
3177
        ));
3178
3179
0
        let response = {
3180
0
            let observed_addr = &self.inner[substream_info.connection_id].address;
3181
0
            let ed25519_public_key = &self.inner[substream_info.connection_id].ed25519_public_key;
3182
3183
0
            let supported_protocols = [codec::ProtocolName::Ping, codec::ProtocolName::Identify]
3184
0
                .into_iter()
3185
0
                .chain(self.chains.iter().flat_map(|(_, chain)| {
3186
0
                    [
3187
0
                        codec::ProtocolName::BlockAnnounces {
3188
0
                            genesis_hash: chain.genesis_hash,
3189
0
                            fork_id: chain.fork_id.as_deref(),
3190
0
                        },
3191
0
                        codec::ProtocolName::Transactions {
3192
0
                            genesis_hash: chain.genesis_hash,
3193
0
                            fork_id: chain.fork_id.as_deref(),
3194
0
                        },
3195
0
                    ]
3196
0
                    .into_iter()
3197
0
                    .chain(
3198
0
                        chain
3199
0
                            .grandpa_protocol_config
3200
0
                            .is_some()
3201
0
                            .then_some(codec::ProtocolName::Grandpa {
3202
0
                                genesis_hash: chain.genesis_hash,
3203
0
                                fork_id: chain.fork_id.as_deref(),
3204
0
                            })
3205
0
                            .into_iter(),
3206
                    )
3207
0
                    .chain(
3208
0
                        chain
3209
0
                            .allow_inbound_block_requests
3210
0
                            .then_some(codec::ProtocolName::Sync {
3211
0
                                genesis_hash: chain.genesis_hash,
3212
0
                                fork_id: chain.fork_id.as_deref(),
3213
0
                            })
3214
0
                            .into_iter(),
3215
                    )
3216
0
                }));
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identify0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE16respond_identify0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identify0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE16respond_identify0B26_
3217
3218
0
            let supported_protocols_names = supported_protocols
3219
0
                .map(codec::encode_protocol_name_string)
3220
0
                .collect::<Vec<_>>();
3221
3222
0
            codec::build_identify_response(codec::IdentifyResponse {
3223
0
                protocol_version: "/substrate/1.0", // TODO: same value as in Substrate, see also https://github.com/paritytech/substrate/issues/14331
3224
0
                agent_version,
3225
0
                ed25519_public_key: *ed25519_public_key,
3226
0
                listen_addrs: iter::empty(), // TODO:
3227
0
                observed_addr,
3228
0
                protocols: supported_protocols_names.iter().map(|p| &p[..]),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identifys_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE16respond_identifys_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identifys_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE16respond_identifys_0B26_
3229
            })
3230
0
            .fold(Vec::new(), |mut a, b| {
3231
0
                a.extend_from_slice(b.as_ref());
3232
0
                a
3233
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identifys0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE16respond_identifys0_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE16respond_identifys0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE16respond_identifys0_0B26_
3234
        };
3235
3236
0
        self.inner.respond_in_request(substream_id, Ok(response));
3237
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE16respond_identifyB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE16respond_identifyB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE16respond_identifyB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE16respond_identifyB24_
3238
3239
    /// Responds to a blocks request. Call this function in response to
3240
    /// a [`Event::BlocksRequestIn`].
3241
    ///
3242
    /// Pass `None` in order to deny the request. Do this if blocks aren't available locally.
3243
    ///
3244
    /// This function might generate a message destined a connection. Use
3245
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
3246
    ///
3247
    /// # Panic
3248
    ///
3249
    /// Panics if the [`SubstreamId`] is invalid or doesn't correspond to a blocks request or
3250
    /// if the request has been cancelled with a [`Event::RequestInCancel`].
3251
    ///
3252
    // TOOD: more zero-cost parameter
3253
0
    pub fn respond_blocks(
3254
0
        &mut self,
3255
0
        substream_id: SubstreamId,
3256
0
        response: Option<Vec<codec::BlockData>>,
3257
0
    ) {
3258
0
        let substream_info = self.substreams.remove(&substream_id).unwrap();
3259
0
        assert!(matches!(
3260
0
            substream_info.protocol,
3261
            Some(Protocol::Sync { .. })
3262
        ));
3263
3264
0
        let response = if let Some(response) = response {
3265
            Ok(
3266
0
                codec::build_block_response(response).fold(Vec::new(), |mut a, b| {
3267
0
                    a.extend_from_slice(b.as_ref());
3268
0
                    a
3269
0
                }),
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE14respond_blocks0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE14respond_blocks0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE14respond_blocks0Bb_
3270
            )
3271
        } else {
3272
0
            Err(())
3273
        };
3274
3275
0
        self.inner.respond_in_request(substream_id, response);
3276
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE14respond_blocksB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE14respond_blocksB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE14respond_blocksB9_
3277
3278
    /// Returns the list of all peers for a [`Event::GossipConnected`] event of the given kind has
3279
    /// been emitted.
3280
    /// It is possible to send gossip notifications to these peers.
3281
    ///
3282
    /// # Panic
3283
    ///
3284
    /// Panics if the [`ChainId`] is invalid.
3285
    ///
3286
97
    pub fn gossip_connected_peers(
3287
97
        &self,
3288
97
        chain_id: ChainId,
3289
97
        kind: GossipKind,
3290
97
    ) -> impl Iterator<Item = &PeerId> {
3291
97
        assert!(self.chains.contains(chain_id.0));
3292
97
        let GossipKind::ConsensusTransactions = kind;
3293
3294
97
        self.notification_substreams_by_peer_id
3295
97
            .range(
3296
97
                (
3297
97
                    NotificationsProtocol::BlockAnnounces {
3298
97
                        chain_index: chain_id.0,
3299
97
                    },
3300
97
                    PeerIndex(usize::MIN),
3301
97
                    SubstreamDirection::Out,
3302
97
                    NotificationsSubstreamState::MIN,
3303
97
                    SubstreamId::MIN,
3304
97
                )
3305
97
                    ..=(
3306
97
                        NotificationsProtocol::BlockAnnounces {
3307
97
                            chain_index: chain_id.0,
3308
97
                        },
3309
97
                        PeerIndex(usize::MAX),
3310
97
                        SubstreamDirection::Out,
3311
97
                        NotificationsSubstreamState::MAX,
3312
97
                        SubstreamId::MAX,
3313
97
                    ),
3314
            )
3315
97
            .filter(move |(_, _, d, s, _)| 
{0
3316
0
                *d == SubstreamDirection::Out
3317
0
                    && matches!(*s, NotificationsSubstreamState::Open { .. })
3318
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE22gossip_connected_peers0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE22gossip_connected_peers0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE22gossip_connected_peers0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE22gossip_connected_peers0B26_
3319
97
            .map(|(_, peer_index, _, _, _)| &
self.peers[peer_index.0]0
)
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE22gossip_connected_peerss_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE22gossip_connected_peerss_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE22gossip_connected_peerss_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE22gossip_connected_peerss_0B26_
3320
97
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE22gossip_connected_peersB9_
_RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE22gossip_connected_peersB19_
Line
Count
Source
3286
97
    pub fn gossip_connected_peers(
3287
97
        &self,
3288
97
        chain_id: ChainId,
3289
97
        kind: GossipKind,
3290
97
    ) -> impl Iterator<Item = &PeerId> {
3291
97
        assert!(self.chains.contains(chain_id.0));
3292
97
        let GossipKind::ConsensusTransactions = kind;
3293
3294
97
        self.notification_substreams_by_peer_id
3295
97
            .range(
3296
97
                (
3297
97
                    NotificationsProtocol::BlockAnnounces {
3298
97
                        chain_index: chain_id.0,
3299
97
                    },
3300
97
                    PeerIndex(usize::MIN),
3301
97
                    SubstreamDirection::Out,
3302
97
                    NotificationsSubstreamState::MIN,
3303
97
                    SubstreamId::MIN,
3304
97
                )
3305
97
                    ..=(
3306
97
                        NotificationsProtocol::BlockAnnounces {
3307
97
                            chain_index: chain_id.0,
3308
97
                        },
3309
97
                        PeerIndex(usize::MAX),
3310
97
                        SubstreamDirection::Out,
3311
97
                        NotificationsSubstreamState::MAX,
3312
97
                        SubstreamId::MAX,
3313
97
                    ),
3314
            )
3315
97
            .filter(move |(_, _, d, s, _)| {
3316
                *d == SubstreamDirection::Out
3317
                    && matches!(*s, NotificationsSubstreamState::Open { .. })
3318
            })
3319
97
            .map(|(_, peer_index, _, _, _)| &self.peers[peer_index.0])
3320
97
    }
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE22gossip_connected_peersB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE22gossip_connected_peersB24_
3321
3322
    /// Returns the list of all peers for a [`Event::GossipConnected`] event of the given kind has
3323
    /// been emitted.
3324
    /// It is possible to send gossip notifications to these peers.
3325
    ///
3326
    /// # Panic
3327
    ///
3328
    /// Panics if the [`ChainId`] is invalid.
3329
    ///
3330
0
    pub fn gossip_is_connected(
3331
0
        &self,
3332
0
        chain_id: ChainId,
3333
0
        target: &PeerId,
3334
0
        kind: GossipKind,
3335
0
    ) -> bool {
3336
0
        assert!(self.chains.contains(chain_id.0));
3337
0
        let GossipKind::ConsensusTransactions = kind;
3338
3339
0
        let Some(&peer_index) = self.peers_by_peer_id.get(target) else {
3340
            // If the `PeerId` is unknown, then we also don't have any gossip link to it.
3341
0
            return false;
3342
        };
3343
3344
0
        self.notification_substreams_by_peer_id
3345
0
            .range(
3346
0
                (
3347
0
                    NotificationsProtocol::BlockAnnounces {
3348
0
                        chain_index: chain_id.0,
3349
0
                    },
3350
0
                    peer_index,
3351
0
                    SubstreamDirection::Out,
3352
0
                    NotificationsSubstreamState::OPEN_MIN_VALUE,
3353
0
                    SubstreamId::MIN,
3354
0
                )
3355
0
                    ..=(
3356
0
                        NotificationsProtocol::BlockAnnounces {
3357
0
                            chain_index: chain_id.0,
3358
0
                        },
3359
0
                        peer_index,
3360
0
                        SubstreamDirection::Out,
3361
0
                        NotificationsSubstreamState::OPEN_MAX_VALUE,
3362
0
                        SubstreamId::MAX,
3363
0
                    ),
3364
0
            )
3365
0
            .next()
3366
0
            .is_some()
3367
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE19gossip_is_connectedB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE19gossip_is_connectedB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE19gossip_is_connectedB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE19gossip_is_connectedB24_
3368
3369
    /// Open a gossiping substream with the given peer on the given chain.
3370
    ///
3371
    /// Either a [`Event::GossipConnected`] or [`Event::GossipOpenFailed`] is guaranteed to later
3372
    /// be generated, unless [`ChainNetwork::gossip_close`] is called in the meanwhile.
3373
    ///
3374
    /// # Panic
3375
    ///
3376
    /// Panics if the [`ChainId`] is invalid.
3377
    ///
3378
0
    pub fn gossip_open(
3379
0
        &mut self,
3380
0
        chain_id: ChainId,
3381
0
        target: &PeerId,
3382
0
        kind: GossipKind,
3383
0
    ) -> Result<(), OpenGossipError> {
3384
0
        let GossipKind::ConsensusTransactions = kind;
3385
3386
0
        let Some(&peer_index) = self.peers_by_peer_id.get(target) else {
3387
            // If the `PeerId` is unknown, then we also don't have any connection to it.
3388
0
            return Err(OpenGossipError::NoConnection);
3389
        };
3390
3391
0
        let chain_info = &self.chains[chain_id.0];
3392
3393
        // It is forbidden to open more than one gossip notifications substream with any given
3394
        // peer.
3395
0
        if self
3396
0
            .notification_substreams_by_peer_id
3397
0
            .range(
3398
0
                (
3399
0
                    NotificationsProtocol::BlockAnnounces {
3400
0
                        chain_index: chain_id.0,
3401
0
                    },
3402
0
                    peer_index,
3403
0
                    SubstreamDirection::Out,
3404
0
                    NotificationsSubstreamState::MIN,
3405
0
                    SubstreamId::MIN,
3406
0
                )
3407
0
                    ..=(
3408
0
                        NotificationsProtocol::BlockAnnounces {
3409
0
                            chain_index: chain_id.0,
3410
0
                        },
3411
0
                        peer_index,
3412
0
                        SubstreamDirection::Out,
3413
0
                        NotificationsSubstreamState::MAX,
3414
0
                        SubstreamId::MAX,
3415
0
                    ),
3416
0
            )
3417
0
            .next()
3418
0
            .is_some()
3419
        {
3420
0
            return Err(OpenGossipError::AlreadyOpened);
3421
0
        }
3422
3423
        // Choose the connection on which to open the substream.
3424
        // This is done ahead of time, as we don't want to do anything before potentially
3425
        // returning an error.
3426
        // TODO: this is O(n) but is it really a problem? you're only supposed to have max 1 or 2 connections per PeerId
3427
0
        let connection_id = self
3428
0
            .connections_by_peer_id
3429
0
            .range(
3430
0
                (peer_index, collection::ConnectionId::MIN)
3431
0
                    ..=(peer_index, collection::ConnectionId::MAX),
3432
            )
3433
0
            .map(|(_, connection_id)| *connection_id)
3434
0
            .find(|connection_id| {
3435
0
                let state = self.inner.connection_state(*connection_id);
3436
0
                state.established && !state.shutting_down
3437
0
            })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE11gossip_opens_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE11gossip_opens_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE11gossip_opens_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE11gossip_opens_0B26_
3438
0
            .ok_or(OpenGossipError::NoConnection)?;
3439
3440
        // Accept inbound substreams.
3441
0
        for (protocol, in_substream_id) in [
3442
0
            NotificationsProtocol::BlockAnnounces {
3443
0
                chain_index: chain_id.0,
3444
0
            },
3445
0
            NotificationsProtocol::Transactions {
3446
0
                chain_index: chain_id.0,
3447
0
            },
3448
0
            NotificationsProtocol::Grandpa {
3449
0
                chain_index: chain_id.0,
3450
0
            },
3451
0
        ]
3452
0
        .into_iter()
3453
0
        .flat_map(|protocol| {
3454
0
            self.notification_substreams_by_peer_id
3455
0
                .range(
3456
0
                    (
3457
0
                        protocol,
3458
0
                        peer_index,
3459
0
                        SubstreamDirection::In,
3460
0
                        NotificationsSubstreamState::Pending,
3461
0
                        SubstreamId::MIN,
3462
0
                    )
3463
0
                        ..=(
3464
0
                            protocol,
3465
0
                            peer_index,
3466
0
                            SubstreamDirection::In,
3467
0
                            NotificationsSubstreamState::Pending,
3468
0
                            SubstreamId::MAX,
3469
0
                        ),
3470
                )
3471
0
                .map(move |&(_, _, _, _, substream_id)| (protocol, substream_id))
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB9_12ChainNetworkpppE11gossip_opens0_00Bd_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE11gossip_opens0_00B1d_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkpppE11gossip_opens0_00Bd_
Unexecuted instantiation: _RNCNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB9_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBd_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE11gossip_opens0_00B28_
3472
0
        })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE11gossip_opens0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE11gossip_opens0_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE11gossip_opens0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE11gossip_opens0_0B26_
3473
0
        .collect::<Vec<_>>()
3474
        {
3475
0
            let _was_removed = self.notification_substreams_by_peer_id.remove(&(
3476
0
                protocol,
3477
0
                peer_index,
3478
0
                SubstreamDirection::In,
3479
0
                NotificationsSubstreamState::Pending,
3480
0
                in_substream_id,
3481
0
            ));
3482
0
            debug_assert!(_was_removed);
3483
3484
0
            let _was_inserted = self.notification_substreams_by_peer_id.insert((
3485
0
                protocol,
3486
0
                peer_index,
3487
0
                SubstreamDirection::In,
3488
0
                NotificationsSubstreamState::Open {
3489
0
                    asked_to_leave: false,
3490
0
                },
3491
0
                in_substream_id,
3492
0
            ));
3493
0
            debug_assert!(_was_inserted);
3494
3495
0
            self.inner.accept_in_notifications(
3496
0
                in_substream_id,
3497
0
                self.notifications_protocol_handshake(protocol),
3498
0
                self.notifications_protocol_max_notification_size(protocol),
3499
            )
3500
        }
3501
3502
        // Open the block announces substream.
3503
0
        let substream_id = self.inner.open_out_notifications(
3504
0
            connection_id,
3505
0
            codec::encode_protocol_name_string(codec::ProtocolName::BlockAnnounces {
3506
0
                genesis_hash: chain_info.genesis_hash,
3507
0
                fork_id: chain_info.fork_id.as_deref(),
3508
0
            }),
3509
0
            self.notifications_protocol_handshake_timeout(NotificationsProtocol::BlockAnnounces {
3510
0
                chain_index: chain_id.0,
3511
0
            }),
3512
0
            self.notifications_protocol_handshake(NotificationsProtocol::BlockAnnounces {
3513
0
                chain_index: chain_id.0,
3514
0
            }),
3515
0
            self.notifications_protocol_max_handshake_size(NotificationsProtocol::BlockAnnounces {
3516
0
                chain_index: chain_id.0,
3517
0
            }),
3518
        );
3519
0
        let _prev_value = self.substreams.insert(
3520
0
            substream_id,
3521
0
            SubstreamInfo {
3522
0
                connection_id,
3523
0
                protocol: Some(Protocol::Notifications(
3524
0
                    NotificationsProtocol::BlockAnnounces {
3525
0
                        chain_index: chain_id.0,
3526
0
                    },
3527
0
                )),
3528
0
            },
3529
        );
3530
0
        debug_assert!(_prev_value.is_none());
3531
0
        let _was_inserted = self.notification_substreams_by_peer_id.insert((
3532
0
            NotificationsProtocol::BlockAnnounces {
3533
0
                chain_index: chain_id.0,
3534
0
            },
3535
0
            peer_index,
3536
0
            SubstreamDirection::Out,
3537
0
            NotificationsSubstreamState::Pending,
3538
0
            substream_id,
3539
0
        ));
3540
0
        debug_assert!(_was_inserted);
3541
3542
        // Update the desired peers tracking.
3543
0
        if !self
3544
0
            .gossip_desired_peers
3545
0
            .contains(&(peer_index, kind, chain_id.0))
3546
        {
3547
0
            let _was_inserted = self.opened_gossip_undesired.insert((
3548
0
                chain_id,
3549
0
                peer_index,
3550
0
                GossipKind::ConsensusTransactions,
3551
0
            ));
3552
0
            debug_assert!(_was_inserted);
3553
0
        }
3554
0
        self.connected_unopened_gossip_desired
3555
0
            .remove(&(peer_index, chain_id, kind));
3556
3557
0
        Ok(())
3558
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE11gossip_openB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE11gossip_openB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE11gossip_openB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE11gossip_openB24_
3559
3560
    /// Switches the gossip link to the given peer to the "closed" state.
3561
    ///
3562
    /// This can be used:
3563
    ///
3564
    /// - To close a opening in progress after having called [`ChainNetwork::gossip_open`], in
3565
    /// which case no [`Event::GossipConnected`] or [`Event::GossipOpenFailed`] is generated.
3566
    /// - To close a fully open gossip link. All the notifications that have been queued are still
3567
    /// delivered. No event is generated.
3568
    /// - To respond to a [`Event::GossipInDesired`] by rejecting the request.
3569
    ///
3570
    /// # Panic
3571
    ///
3572
    /// Panics if [`ChainId`] is invalid.
3573
    ///
3574
0
    pub fn gossip_close(
3575
0
        &mut self,
3576
0
        chain_id: ChainId,
3577
0
        peer_id: &PeerId,
3578
0
        kind: GossipKind,
3579
0
    ) -> Result<(), CloseGossipError> {
3580
0
        let GossipKind::ConsensusTransactions = kind;
3581
3582
0
        let Some(&peer_index) = self.peers_by_peer_id.get(peer_id) else {
3583
            // If the `PeerId` is unknown, then we also don't have any gossip link to it.
3584
0
            return Err(CloseGossipError::NotOpen);
3585
        };
3586
3587
        // An `assert!` is necessary because we don't actually access the chain information
3588
        // anywhere, but still want to panic if the chain is invalid.
3589
0
        assert!(self.chains.contains(chain_id.0));
3590
3591
        // Track whether this function closed anything in order to know whether to return an
3592
        // error at the end.
3593
0
        let mut has_closed_something = false;
3594
3595
        // Close all substreams, pending or open.
3596
0
        for protocol in [
3597
0
            NotificationsProtocol::BlockAnnounces {
3598
0
                chain_index: chain_id.0,
3599
0
            },
3600
0
            NotificationsProtocol::Transactions {
3601
0
                chain_index: chain_id.0,
3602
0
            },
3603
0
            NotificationsProtocol::Grandpa {
3604
0
                chain_index: chain_id.0,
3605
0
            },
3606
        ] {
3607
0
            for (substream_id, direction, state) in self
3608
0
                .notification_substreams_by_peer_id
3609
0
                .range(
3610
0
                    (
3611
0
                        protocol,
3612
0
                        peer_index,
3613
0
                        SubstreamDirection::In,
3614
0
                        NotificationsSubstreamState::MIN,
3615
0
                        SubstreamId::MIN,
3616
0
                    )
3617
0
                        ..=(
3618
0
                            protocol,
3619
0
                            peer_index,
3620
0
                            SubstreamDirection::Out,
3621
0
                            NotificationsSubstreamState::MAX,
3622
0
                            SubstreamId::MAX,
3623
0
                        ),
3624
                )
3625
0
                .map(|(_, _, dir, state, sub_id)| (*sub_id, *dir, *state))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE12gossip_close0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE12gossip_close0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE12gossip_close0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE12gossip_close0B26_
3626
0
                .collect::<Vec<_>>()
3627
            {
3628
0
                has_closed_something = true;
3629
3630
0
                match (direction, state) {
3631
                    (SubstreamDirection::Out, _) => {
3632
0
                        self.inner.close_out_notifications(substream_id);
3633
3634
0
                        let _was_in = self.notification_substreams_by_peer_id.remove(&(
3635
0
                            protocol,
3636
0
                            peer_index,
3637
0
                            direction,
3638
0
                            state,
3639
0
                            substream_id,
3640
0
                        ));
3641
0
                        debug_assert!(_was_in);
3642
0
                        let _was_in = self.substreams.remove(&substream_id);
3643
0
                        debug_assert!(_was_in.is_some());
3644
                    }
3645
                    (SubstreamDirection::In, NotificationsSubstreamState::Pending) => {
3646
0
                        self.inner.reject_in_notifications(substream_id);
3647
3648
0
                        let _was_in = self.notification_substreams_by_peer_id.remove(&(
3649
0
                            protocol,
3650
0
                            peer_index,
3651
0
                            direction,
3652
0
                            state,
3653
0
                            substream_id,
3654
0
                        ));
3655
0
                        debug_assert!(_was_in);
3656
0
                        let _was_in = self.substreams.remove(&substream_id);
3657
0
                        debug_assert!(_was_in.is_some());
3658
                    }
3659
                    (
3660
                        SubstreamDirection::In,
3661
                        NotificationsSubstreamState::Open {
3662
                            asked_to_leave: false,
3663
                        },
3664
                    ) => {
3665
0
                        self.inner
3666
0
                            .start_close_in_notifications(substream_id, Duration::from_secs(5)); // TODO: arbitrary constant
3667
3668
0
                        let _was_removed = self.notification_substreams_by_peer_id.remove(&(
3669
0
                            protocol,
3670
0
                            peer_index,
3671
0
                            SubstreamDirection::In,
3672
0
                            NotificationsSubstreamState::Open {
3673
0
                                asked_to_leave: false,
3674
0
                            },
3675
0
                            substream_id,
3676
0
                        ));
3677
0
                        debug_assert!(_was_removed);
3678
0
                        let _was_inserted = self.notification_substreams_by_peer_id.insert((
3679
0
                            protocol,
3680
0
                            peer_index,
3681
0
                            SubstreamDirection::In,
3682
0
                            NotificationsSubstreamState::Open {
3683
0
                                asked_to_leave: true,
3684
0
                            },
3685
0
                            substream_id,
3686
0
                        ));
3687
0
                        debug_assert!(_was_inserted);
3688
                    }
3689
                    (
3690
                        SubstreamDirection::In,
3691
                        NotificationsSubstreamState::Open {
3692
                            asked_to_leave: true,
3693
                        },
3694
0
                    ) => {
3695
0
                        // Nothing to do.
3696
0
                    }
3697
                }
3698
            }
3699
        }
3700
3701
        // Desired peers tracking update.
3702
0
        self.opened_gossip_undesired.remove(&(
3703
0
            chain_id,
3704
0
            peer_index,
3705
0
            GossipKind::ConsensusTransactions,
3706
0
        ));
3707
3708
0
        if has_closed_something {
3709
0
            Ok(())
3710
        } else {
3711
0
            Err(CloseGossipError::NotOpen)
3712
        }
3713
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE12gossip_closeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE12gossip_closeB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE12gossip_closeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE12gossip_closeB24_
3714
3715
    /// Update the state of the local node with regards to GrandPa rounds.
3716
    ///
3717
    /// Calling this method does two things:
3718
    ///
3719
    /// - Send on all the active GrandPa substreams a "neighbor packet" indicating the state of
3720
    ///   the local node.
3721
    /// - Update the neighbor packet that is automatically sent to peers when a GrandPa substream
3722
    ///   gets opened.
3723
    ///
3724
    /// In other words, calling this function atomically informs all the present and future peers
3725
    /// of the state of the local node regarding the GrandPa protocol.
3726
    ///
3727
    /// > **Note**: The information passed as parameter isn't validated in any way by this method.
3728
    ///
3729
    /// This function might generate a message destined to connections. Use
3730
    /// [`ChainNetwork::pull_message_to_connection`] to process these messages after it has
3731
    /// returned.
3732
    ///
3733
    /// # Panic
3734
    ///
3735
    /// Panics if [`ChainId`] is invalid, or if the chain has GrandPa disabled.
3736
    ///
3737
0
    pub fn gossip_broadcast_grandpa_state_and_update(
3738
0
        &mut self,
3739
0
        chain_id: ChainId,
3740
0
        grandpa_state: GrandpaState,
3741
0
    ) {
3742
        // Bytes of the neighbor packet to send out.
3743
0
        let packet = codec::GrandpaNotificationRef::Neighbor(codec::NeighborPacket {
3744
0
            round_number: grandpa_state.round_number,
3745
0
            set_id: grandpa_state.set_id,
3746
0
            commit_finalized_height: grandpa_state.commit_finalized_height,
3747
0
        })
3748
0
        .scale_encoding(self.chains[chain_id.0].block_number_bytes)
3749
0
        .fold(Vec::new(), |mut a, b| {
3750
0
            a.extend_from_slice(b.as_ref());
3751
0
            a
3752
0
        });
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_update0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_update0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE41gossip_broadcast_grandpa_state_and_update0B26_
3753
3754
        // Now sending out to all the grandpa substreams that exist.
3755
        // TODO: O(n)
3756
0
        for (_, _, _, _, substream_id) in
3757
0
            self.notification_substreams_by_peer_id
3758
0
                .iter()
3759
0
                .filter(|(p, _, d, s, _)| {
3760
0
                    *p == NotificationsProtocol::Grandpa {
3761
0
                        chain_index: chain_id.0,
3762
0
                    } && *d == SubstreamDirection::Out
3763
0
                        && matches!(*s, NotificationsSubstreamState::Open { .. })
3764
0
                })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_updates_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_updates_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE41gossip_broadcast_grandpa_state_and_updates_0B26_
3765
        {
3766
0
            match self.inner.queue_notification(*substream_id, packet.clone()) {
3767
0
                Ok(()) => {}
3768
0
                Err(collection::QueueNotificationError::QueueFull) => {}
3769
            }
3770
        }
3771
3772
        // Update the locally-stored state.
3773
0
        *self.chains[chain_id.0]
3774
0
            .grandpa_protocol_config
3775
0
            .as_mut()
3776
0
            .unwrap() = grandpa_state;
3777
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_updateB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE41gossip_broadcast_grandpa_state_and_updateB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE41gossip_broadcast_grandpa_state_and_updateB24_
3778
3779
    /// Sends a block announce gossip message to the given peer.
3780
    ///
3781
    /// If no [`Event::GossipConnected`] event of kind [`GossipKind::ConsensusTransactions`] has
3782
    /// been emitted for the given peer, then a [`QueueNotificationError::NoConnection`] will be
3783
    /// returned.
3784
    ///
3785
    /// This function might generate a message destined a connection. Use
3786
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
3787
    ///
3788
    /// # Panic
3789
    ///
3790
    /// Panics if the [`ChainId`] is invalid.
3791
    ///
3792
    // TODO: there this extra parameter in block announces that is unused on many chains but not always
3793
0
    pub fn gossip_send_block_announce(
3794
0
        &mut self,
3795
0
        target: &PeerId,
3796
0
        chain_id: ChainId,
3797
0
        scale_encoded_header: &[u8],
3798
0
        is_best: bool,
3799
0
    ) -> Result<(), QueueNotificationError> {
3800
0
        let notification = codec::encode_block_announce(codec::BlockAnnounceRef {
3801
0
            scale_encoded_header,
3802
0
            is_best,
3803
0
        })
3804
0
        .fold(Vec::new(), |mut a, b| {
3805
0
            a.extend_from_slice(b.as_ref());
3806
0
            a
3807
0
        });
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE26gossip_send_block_announce0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE26gossip_send_block_announce0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE26gossip_send_block_announce0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE26gossip_send_block_announce0B26_
3808
3809
0
        self.queue_notification(
3810
0
            target,
3811
0
            NotificationsProtocol::BlockAnnounces {
3812
0
                chain_index: chain_id.0,
3813
0
            },
3814
0
            notification,
3815
        )
3816
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE26gossip_send_block_announceB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE26gossip_send_block_announceB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE26gossip_send_block_announceB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE26gossip_send_block_announceB24_
3817
3818
    /// Sends a transaction gossip message to the given peer.
3819
    ///
3820
    /// Must be passed the SCALE-encoded transaction.
3821
    ///
3822
    /// If no [`Event::GossipConnected`] event of kind [`GossipKind::ConsensusTransactions`] has
3823
    /// been emitted for the given peer, then a [`QueueNotificationError::NoConnection`] will be
3824
    /// returned.
3825
    ///
3826
    /// This function might generate a message destined connections. Use
3827
    /// [`ChainNetwork::pull_message_to_connection`] to process messages after it has returned.
3828
    ///
3829
    /// # Panic
3830
    ///
3831
    /// Panics if the [`ChainId`] is invalid.
3832
    ///
3833
    // TODO: function is awkward due to tx substream not being necessarily always open
3834
0
    pub fn gossip_send_transaction(
3835
0
        &mut self,
3836
0
        target: &PeerId,
3837
0
        chain_id: ChainId,
3838
0
        extrinsic: &[u8],
3839
0
    ) -> Result<(), QueueNotificationError> {
3840
0
        let mut val = Vec::with_capacity(1 + extrinsic.len());
3841
0
        val.extend_from_slice(util::encode_scale_compact_usize(1).as_ref());
3842
0
        val.extend_from_slice(extrinsic);
3843
0
        self.queue_notification(
3844
0
            target,
3845
0
            NotificationsProtocol::Transactions {
3846
0
                chain_index: chain_id.0,
3847
0
            },
3848
0
            val,
3849
        )
3850
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE23gossip_send_transactionB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE23gossip_send_transactionB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE23gossip_send_transactionB24_
3851
3852
    /// Inner implementation for all the notifications sends.
3853
0
    fn queue_notification(
3854
0
        &mut self,
3855
0
        target: &PeerId,
3856
0
        protocol: NotificationsProtocol,
3857
0
        notification: Vec<u8>,
3858
0
    ) -> Result<(), QueueNotificationError> {
3859
0
        let Some(&peer_index) = self.peers_by_peer_id.get(target) else {
3860
            // If the `PeerId` is unknown, then we also don't have any gossip link to it.
3861
0
            return Err(QueueNotificationError::NoConnection);
3862
        };
3863
3864
0
        let chain_index = match protocol {
3865
0
            NotificationsProtocol::BlockAnnounces { chain_index } => chain_index,
3866
0
            NotificationsProtocol::Transactions { chain_index } => chain_index,
3867
0
            NotificationsProtocol::Grandpa { chain_index } => chain_index,
3868
        };
3869
3870
0
        assert!(self.chains.contains(chain_index));
3871
3872
        // We first find a block announces substream for that peer.
3873
        // TODO: only relevant for GossipKind::ConsensusTransactions
3874
        // If none is found, then we are not considered "gossip-connected", and return an error
3875
        // no matter what, even if a substream of the requested protocol exists.
3876
0
        let block_announces_substream = self
3877
0
            .notification_substreams_by_peer_id
3878
0
            .range(
3879
0
                (
3880
0
                    NotificationsProtocol::BlockAnnounces { chain_index },
3881
0
                    peer_index,
3882
0
                    SubstreamDirection::Out,
3883
0
                    NotificationsSubstreamState::OPEN_MIN_VALUE,
3884
0
                    SubstreamId::MIN,
3885
0
                )
3886
0
                    ..=(
3887
0
                        NotificationsProtocol::BlockAnnounces { chain_index },
3888
0
                        peer_index,
3889
0
                        SubstreamDirection::Out,
3890
0
                        NotificationsSubstreamState::OPEN_MAX_VALUE,
3891
0
                        SubstreamId::MAX,
3892
0
                    ),
3893
0
            )
3894
0
            .next()
3895
0
            .map(|(_, _, _, _, substream_id)| *substream_id)
3896
0
            .ok_or(QueueNotificationError::NoConnection)?;
3897
3898
        // Now find a substream of the requested protocol.
3899
0
        let substream_id = if matches!(protocol, NotificationsProtocol::BlockAnnounces { .. }) {
3900
0
            block_announces_substream
3901
        } else {
3902
0
            let id = self
3903
0
                .notification_substreams_by_peer_id
3904
0
                .range(
3905
0
                    (
3906
0
                        protocol,
3907
0
                        peer_index,
3908
0
                        SubstreamDirection::Out,
3909
0
                        NotificationsSubstreamState::OPEN_MIN_VALUE,
3910
0
                        SubstreamId::MIN,
3911
0
                    )
3912
0
                        ..=(
3913
0
                            protocol,
3914
0
                            peer_index,
3915
0
                            SubstreamDirection::Out,
3916
0
                            NotificationsSubstreamState::OPEN_MAX_VALUE,
3917
0
                            SubstreamId::MAX,
3918
0
                        ),
3919
0
                )
3920
0
                .next()
3921
0
                .map(|(_, _, _, _, substream_id)| *substream_id);
3922
            // If we are "gossip-connected" but no open transaction/grandpa substream exists, we
3923
            // silently discard the notification.
3924
            // TODO: this is a questionable behavior
3925
0
            let Some(id) = id else { return Ok(()) };
3926
0
            id
3927
        };
3928
3929
0
        match self.inner.queue_notification(substream_id, notification) {
3930
0
            Ok(()) => Ok(()),
3931
            Err(collection::QueueNotificationError::QueueFull) => {
3932
0
                Err(QueueNotificationError::QueueFull)
3933
            }
3934
        }
3935
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE18queue_notificationB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18queue_notificationB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE18queue_notificationB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18queue_notificationB24_
3936
3937
0
    fn recognize_protocol(&self, protocol_name: &str) -> Result<Protocol, ()> {
3938
0
        Ok(match codec::decode_protocol_name(protocol_name)? {
3939
0
            codec::ProtocolName::Identify => Protocol::Identify,
3940
0
            codec::ProtocolName::Ping => Protocol::Ping,
3941
            codec::ProtocolName::BlockAnnounces {
3942
0
                genesis_hash,
3943
0
                fork_id,
3944
            } => Protocol::Notifications(NotificationsProtocol::BlockAnnounces {
3945
0
                chain_index: *self
3946
0
                    .chains_by_protocol_info
3947
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocol0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocol0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocol0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocol0B26_
3948
0
                    .ok_or(())?,
3949
            }),
3950
            codec::ProtocolName::Transactions {
3951
0
                genesis_hash,
3952
0
                fork_id,
3953
            } => Protocol::Notifications(NotificationsProtocol::Transactions {
3954
0
                chain_index: *self
3955
0
                    .chains_by_protocol_info
3956
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols_0B26_
3957
0
                    .ok_or(())?,
3958
            }),
3959
            codec::ProtocolName::Grandpa {
3960
0
                genesis_hash,
3961
0
                fork_id,
3962
            } => Protocol::Notifications(NotificationsProtocol::Grandpa {
3963
0
                chain_index: *self
3964
0
                    .chains_by_protocol_info
3965
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols0_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols0_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols0_0B26_
3966
0
                    .ok_or(())?,
3967
            }),
3968
            codec::ProtocolName::Sync {
3969
0
                genesis_hash,
3970
0
                fork_id,
3971
            } => Protocol::Sync {
3972
0
                chain_index: *self
3973
0
                    .chains_by_protocol_info
3974
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols1_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols1_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols1_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols1_0B26_
3975
0
                    .ok_or(())?,
3976
            },
3977
            codec::ProtocolName::Light {
3978
0
                genesis_hash,
3979
0
                fork_id,
3980
            } => Protocol::LightUnknown {
3981
0
                chain_index: *self
3982
0
                    .chains_by_protocol_info
3983
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols2_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols2_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols2_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols2_0B26_
3984
0
                    .ok_or(())?,
3985
            },
3986
            codec::ProtocolName::Kad {
3987
0
                genesis_hash,
3988
0
                fork_id,
3989
            } => Protocol::Kad {
3990
0
                chain_index: *self
3991
0
                    .chains_by_protocol_info
3992
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols3_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols3_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols3_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols3_0B26_
3993
0
                    .ok_or(())?,
3994
            },
3995
            codec::ProtocolName::SyncWarp {
3996
0
                genesis_hash,
3997
0
                fork_id,
3998
            } => Protocol::SyncWarp {
3999
0
                chain_index: *self
4000
0
                    .chains_by_protocol_info
4001
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols4_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols4_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols4_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols4_0B26_
4002
0
                    .ok_or(())?,
4003
            },
4004
            codec::ProtocolName::State {
4005
0
                genesis_hash,
4006
0
                fork_id,
4007
            } => Protocol::State {
4008
0
                chain_index: *self
4009
0
                    .chains_by_protocol_info
4010
0
                    .get(&(genesis_hash, fork_id.map(|fork_id| fork_id.to_owned())))
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols5_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocols5_0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE18recognize_protocols5_0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocols5_0B26_
4011
0
                    .ok_or(())?,
4012
            },
4013
        })
4014
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE18recognize_protocolB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE18recognize_protocolB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE18recognize_protocolB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE18recognize_protocolB24_
4015
4016
    /// Returns the [`PeerIndex`] of the given [`PeerId`], inserting it if isn't present in the
4017
    /// list yet.
4018
0
    fn peer_index_or_insert(&mut self, peer_id: PeerId) -> PeerIndex {
4019
0
        debug_assert_eq!(self.peers.len(), self.peers_by_peer_id.len());
4020
0
        match self.peers_by_peer_id.entry(peer_id) {
4021
0
            hashbrown::hash_map::Entry::Occupied(e) => *e.get(),
4022
0
            hashbrown::hash_map::Entry::Vacant(e) => {
4023
0
                let peer_index = PeerIndex(self.peers.insert(e.key().clone()));
4024
0
                *e.insert(peer_index)
4025
            }
4026
        }
4027
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE20peer_index_or_insertB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE20peer_index_or_insertB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE20peer_index_or_insertB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE20peer_index_or_insertB24_
4028
4029
    /// Checks whether the given [`PeerIndex`] is still in use, and if no removes it from
4030
    /// [`ChainNetwork::peers`].
4031
0
    fn try_clean_up_peer(&mut self, peer_index: PeerIndex) {
4032
0
        if self
4033
0
            .connections_by_peer_id
4034
0
            .range(
4035
0
                (peer_index, collection::ConnectionId::MIN)
4036
0
                    ..=(peer_index, collection::ConnectionId::MAX),
4037
0
            )
4038
0
            .next()
4039
0
            .is_some()
4040
        {
4041
0
            return;
4042
0
        }
4043
4044
0
        if self
4045
0
            .gossip_desired_peers
4046
0
            .range(
4047
0
                (peer_index, GossipKind::ConsensusTransactions, usize::MIN)
4048
0
                    ..=(peer_index, GossipKind::ConsensusTransactions, usize::MAX),
4049
0
            )
4050
0
            .next()
4051
0
            .is_some()
4052
        {
4053
0
            return;
4054
0
        }
4055
4056
0
        let peer_id = self.peers.remove(peer_index.0);
4057
0
        let _was_in = self.peers_by_peer_id.remove(&peer_id);
4058
0
        debug_assert_eq!(_was_in, Some(peer_index));
4059
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE17try_clean_up_peerB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE17try_clean_up_peerB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE17try_clean_up_peerB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE17try_clean_up_peerB24_
4060
4061
    /// Returns the maximum allowed size (in bytes) of the handshake of the given protocol.
4062
0
    fn notifications_protocol_max_handshake_size(&self, protocol: NotificationsProtocol) -> usize {
4063
        // TODO: these numbers are arbitrary, must be made to match Substrate
4064
0
        match protocol {
4065
0
            NotificationsProtocol::BlockAnnounces { .. } => 64 * 1024,
4066
            NotificationsProtocol::Transactions { .. } | NotificationsProtocol::Grandpa { .. } => {
4067
0
                32
4068
            }
4069
        }
4070
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE41notifications_protocol_max_handshake_sizeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE41notifications_protocol_max_handshake_sizeB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE41notifications_protocol_max_handshake_sizeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE41notifications_protocol_max_handshake_sizeB24_
4071
4072
    /// Returns the maximum allowed size (in bytes) of a notification of the given protocol.
4073
0
    fn notifications_protocol_max_notification_size(
4074
0
        &self,
4075
0
        _protocol: NotificationsProtocol,
4076
0
    ) -> usize {
4077
        // TODO: this number is arbitrary, must be made to match Substrate
4078
0
        1024 * 1024 // TODO:
4079
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE44notifications_protocol_max_notification_sizeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE44notifications_protocol_max_notification_sizeB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE44notifications_protocol_max_notification_sizeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE44notifications_protocol_max_notification_sizeB24_
4080
4081
    /// Returns the timeout allowed for the remote to send back the handshake of the given
4082
    /// protocol.
4083
0
    fn notifications_protocol_handshake_timeout(
4084
0
        &self,
4085
0
        _protocol: NotificationsProtocol,
4086
0
    ) -> Duration {
4087
0
        Duration::from_secs(10)
4088
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE40notifications_protocol_handshake_timeoutB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE40notifications_protocol_handshake_timeoutB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE40notifications_protocol_handshake_timeoutB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE40notifications_protocol_handshake_timeoutB24_
4089
4090
    /// Builds the handshake to send to the remote when opening a notifications protocol.
4091
0
    fn notifications_protocol_handshake(&self, protocol: NotificationsProtocol) -> Vec<u8> {
4092
0
        let handshake = match protocol {
4093
0
            NotificationsProtocol::BlockAnnounces { chain_index } => {
4094
0
                codec::encode_block_announces_handshake(
4095
0
                    codec::BlockAnnouncesHandshakeRef {
4096
0
                        best_hash: &self.chains[chain_index].best_hash,
4097
0
                        best_number: self.chains[chain_index].best_number,
4098
0
                        role: self.chains[chain_index].role,
4099
0
                        genesis_hash: &self.chains[chain_index].genesis_hash,
4100
0
                    },
4101
0
                    self.chains[chain_index].block_number_bytes,
4102
                )
4103
0
                .fold(Vec::new(), |mut a, b| {
4104
0
                    a.extend_from_slice(b.as_ref());
4105
0
                    a
4106
0
                })
Unexecuted instantiation: _RNCNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB7_12ChainNetworkpppE32notifications_protocol_handshake0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32notifications_protocol_handshake0B1b_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkpppE32notifications_protocol_handshake0Bb_
Unexecuted instantiation: _RNCNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB7_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtBb_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32notifications_protocol_handshake0B26_
4107
            }
4108
0
            NotificationsProtocol::Transactions { chain_index, .. }
4109
0
            | NotificationsProtocol::Grandpa { chain_index } => {
4110
0
                self.chains[chain_index].role.scale_encoding().to_vec()
4111
            }
4112
        };
4113
4114
0
        debug_assert!(handshake.len() <= self.notifications_protocol_max_handshake_size(protocol));
4115
0
        handshake
4116
0
    }
Unexecuted instantiation: _RNvMs0_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceINtB5_12ChainNetworkpppE32notifications_protocol_handshakeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantE32notifications_protocol_handshakeB19_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkpppE32notifications_protocol_handshakeB9_
Unexecuted instantiation: _RNvMs0_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationE32notifications_protocol_handshakeB24_
4117
}
4118
4119
impl<TChain, TConn, TNow> ops::Index<ChainId> for ChainNetwork<TChain, TConn, TNow> {
4120
    type Output = TChain;
4121
4122
138
    fn index(&self, index: ChainId) -> &Self::Output {
4123
138
        &self.chains[index.0].user_data
4124
138
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot7network7services1_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtB5_7ChainIdE5indexB9_
_RNvXs1_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtB5_7ChainIdE5indexB19_
Line
Count
Source
4122
138
    fn index(&self, index: ChainId) -> &Self::Output {
4123
138
        &self.chains[index.0].user_data
4124
138
    }
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot7network7services1_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtB5_7ChainIdE5indexB9_
Unexecuted instantiation: _RNvXs1_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationEINtNtNtB4y_3ops5index5IndexNtB5_7ChainIdE5indexB24_
4125
}
4126
4127
impl<TChain, TConn, TNow> ops::IndexMut<ChainId> for ChainNetwork<TChain, TConn, TNow> {
4128
0
    fn index_mut(&mut self, index: ChainId) -> &mut Self::Output {
4129
0
        &mut self.chains[index.0].user_data
4130
0
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot7network7services2_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtB5_7ChainIdE9index_mutB9_
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot7network7services2_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtB5_7ChainIdE9index_mutB9_
Unexecuted instantiation: _RNvXs2_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationEINtNtNtB4y_3ops5index8IndexMutNtB5_7ChainIdE9index_mutB24_
4131
}
4132
4133
impl<TChain, TConn, TNow> ops::Index<ConnectionId> for ChainNetwork<TChain, TConn, TNow> {
4134
    type Output = TConn;
4135
4136
0
    fn index(&self, index: ConnectionId) -> &Self::Output {
4137
0
        &self.inner[index].user_data
4138
0
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot7network7services3_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtNtNtB9_6libp2p10collection12ConnectionIdE5indexB9_
Unexecuted instantiation: _RNvXs3_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkNtNtCsfFWJyR6nd6r_17smoldot_full_node15network_service5ChainINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs21ZxWzNybR_3std4time7InstantEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtB2I_12ConnectionIdE5indexB19_
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot7network7services3_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index5IndexNtNtNtB9_6libp2p10collection12ConnectionIdE5indexB9_
Unexecuted instantiation: _RNvXs3_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceINtB5_12ChainNetworkINtNtCs508CmrSPkZh_13smoldot_light15network_service5ChainNtNtCs7snhGEhbuap_18smoldot_light_wasm8platform11PlatformRefEINtCs9gZ5A4YX5Xm_13async_channel6SenderNtNtNtB9_6libp2p10collection23CoordinatorToConnectionENtNtCs1p5UDGgVI4d_4core4time8DurationEINtNtNtB4y_3ops5index5IndexNtB3E_12ConnectionIdE5indexB24_
4139
}
4140
4141
impl<TChain, TConn, TNow> ops::IndexMut<ConnectionId> for ChainNetwork<TChain, TConn, TNow> {
4142
0
    fn index_mut(&mut self, index: ConnectionId) -> &mut Self::Output {
4143
0
        &mut self.inner[index].user_data
4144
0
    }
Unexecuted instantiation: _RNvXININtNtCsjlkOsLH0Zfj_7smoldot7network7services4_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtNtNtB9_6libp2p10collection12ConnectionIdE9index_mutB9_
Unexecuted instantiation: _RNvXININtNtCsc1ywvx6YAnK_7smoldot7network7services4_0pppEINtB5_12ChainNetworkpppEINtNtNtCs1p5UDGgVI4d_4core3ops5index8IndexMutNtNtNtB9_6libp2p10collection12ConnectionIdE9index_mutB9_
4145
}
4146
4147
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
4148
pub enum GossipKind {
4149
    ConsensusTransactions,
4150
}
4151
4152
/// Error returned by [`ChainNetwork::add_chain`].
4153
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
4154
pub enum AddChainError {
4155
    /// The genesis hash and fork id are identical to the ones of an existing chain.
4156
    #[display("Genesis hash and fork id are identical to the ones of an existing chain.")]
4157
    Duplicate {
4158
        /// Identifier of the chain that uses the same genesis hash and fork id.
4159
        existing_identical: ChainId,
4160
    },
4161
}
4162
4163
/// Error returned by [`ChainNetwork::remove_chain`].
4164
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
4165
pub enum RemoveChainError {
4166
    /// Chain is still in use.
4167
    InUse,
4168
}
4169
4170
/// Event generated by [`ChainNetwork::next_event`].
4171
#[derive(Debug)]
4172
pub enum Event<TConn> {
4173
    /// A connection that was added with [`ChainNetwork::add_single_stream_connection`] or
4174
    /// [`ChainNetwork::add_multi_stream_connection`] has now finished its handshake phase.
4175
    /// Its [`PeerId`] is now known which certainty.
4176
    HandshakeFinished {
4177
        /// Identifier of the connection.
4178
        id: ConnectionId,
4179
        /// Parameter that was passed to [`ChainNetwork::add_single_stream_connection`] or
4180
        /// [`ChainNetwork::add_multi_stream_connection`].
4181
        expected_peer_id: Option<PeerId>,
4182
        /// Actual [`PeerId`] of the connection.
4183
        peer_id: PeerId,
4184
    },
4185
4186
    /// A connection has shut down before finishing its handshake.
4187
    PreHandshakeDisconnected {
4188
        /// Identifier of the connection.
4189
        id: ConnectionId,
4190
        /// Parameter that was passed to [`ChainNetwork::add_single_stream_connection`] or
4191
        /// [`ChainNetwork::add_multi_stream_connection`].
4192
        address: Vec<u8>,
4193
        /// Parameter that was passed to [`ChainNetwork::add_single_stream_connection`] or
4194
        /// [`ChainNetwork::add_multi_stream_connection`].
4195
        expected_peer_id: Option<PeerId>,
4196
        /// User data that was passed to [`ChainNetwork::add_single_stream_connection`] or
4197
        /// [`ChainNetwork::add_multi_stream_connection`].
4198
        user_data: TConn,
4199
    },
4200
4201
    /// A connection has shut down after finishing its handshake.
4202
    Disconnected {
4203
        /// Identifier of the connection.
4204
        id: ConnectionId,
4205
        /// Parameter that was passed to [`ChainNetwork::add_single_stream_connection`] or
4206
        /// [`ChainNetwork::add_multi_stream_connection`].
4207
        address: Vec<u8>,
4208
        /// Peer that was connected.
4209
        peer_id: PeerId,
4210
        /// User data that was passed to [`ChainNetwork::add_single_stream_connection`] or
4211
        /// [`ChainNetwork::add_multi_stream_connection`].
4212
        user_data: TConn,
4213
    },
4214
4215
    /// The ping of a connection has been measured.
4216
    PingOutSuccess {
4217
        /// Identifier of the connection.
4218
        id: ConnectionId,
4219
        /// [`PeerId`] of the connection.
4220
        peer_id: PeerId,
4221
        /// Time between sending the ping and receiving the pong.
4222
        ping_time: Duration,
4223
    },
4224
4225
    /// Now connected to the given peer for gossiping purposes.
4226
    ///
4227
    /// This event can only happen as a result of a call to [`ChainNetwork::gossip_open`].
4228
    GossipConnected {
4229
        /// Peer we are now connected to.
4230
        peer_id: PeerId,
4231
        /// Chain of the gossip connection.
4232
        chain_id: ChainId,
4233
        /// Which kind of gossip link is concerned.
4234
        kind: GossipKind,
4235
        /// Role the node reports playing on the network.
4236
        role: Role,
4237
        /// Height of the best block according to this node.
4238
        best_number: u64,
4239
        /// Hash of the best block according to this node.
4240
        best_hash: [u8; 32],
4241
    },
4242
4243
    /// An attempt has been made to open the given chain, but something wrong happened.
4244
    ///
4245
    /// This event can only happen as a result of a call to [`ChainNetwork::gossip_open`].
4246
    GossipOpenFailed {
4247
        /// Peer concerned by the event.
4248
        peer_id: PeerId,
4249
        /// Chain of the gossip connection.
4250
        chain_id: ChainId,
4251
        /// Which kind of gossip link is concerned.
4252
        kind: GossipKind,
4253
        /// Problem that happened.
4254
        error: GossipConnectError,
4255
    },
4256
4257
    /// No longer connected to the given peer for gossiping purposes.
4258
    GossipDisconnected {
4259
        /// Peer we are no longer connected to.
4260
        peer_id: PeerId,
4261
        /// Chain of the gossip connection.
4262
        chain_id: ChainId,
4263
        /// Which kind of gossip link is concerned.
4264
        kind: GossipKind,
4265
    },
4266
4267
    /// A peer would like to open a gossiping link with the local node.
4268
    // TODO: document what to do
4269
    // TODO: include handshake content?
4270
    GossipInDesired {
4271
        /// Peer concerned by the event.
4272
        peer_id: PeerId,
4273
        /// Chain of the gossip connection.
4274
        chain_id: ChainId,
4275
        /// Which kind of gossip link is concerned.
4276
        kind: GossipKind,
4277
    },
4278
4279
    /// A previously-emitted [`Event::GossipInDesired`] is no longer relevant as the peer has
4280
    /// stopped the opening attempt.
4281
    GossipInDesiredCancel {
4282
        /// Peer concerned by the event.
4283
        peer_id: PeerId,
4284
        /// Chain of the gossip connection.
4285
        chain_id: ChainId,
4286
        /// Which kind of gossip link is concerned.
4287
        kind: GossipKind,
4288
    },
4289
4290
    /// An outgoing request has finished, either successfully or not.
4291
    RequestResult {
4292
        /// Peer that has answered the request.
4293
        peer_id: PeerId,
4294
        /// Index of the chain the request relates to.
4295
        chain_id: ChainId,
4296
        /// Identifier of the request that was returned by the function that started the request.
4297
        substream_id: SubstreamId,
4298
        /// Outcome of the request.
4299
        response: RequestResult,
4300
    },
4301
4302
    /// Received a new block announce from a peer.
4303
    ///
4304
    /// Can only happen after a [`Event::GossipConnected`] with the given [`PeerId`] and [`ChainId`]
4305
    /// combination has happened.
4306
    BlockAnnounce {
4307
        /// Identity of the sender of the block announce.
4308
        peer_id: PeerId,
4309
        /// Index of the chain the block relates to.
4310
        chain_id: ChainId,
4311
        announce: EncodedBlockAnnounce,
4312
    },
4313
4314
    /// Received a GrandPa neighbor packet from the network. This contains an update to the
4315
    /// finality state of the given peer.
4316
    ///
4317
    /// Can only happen after a [`Event::GossipConnected`] with the given [`PeerId`] and [`ChainId`]
4318
    /// combination has happened.
4319
    GrandpaNeighborPacket {
4320
        /// Identity of the sender of the message.
4321
        peer_id: PeerId,
4322
        /// Index of the chain the message relates to.
4323
        chain_id: ChainId,
4324
        /// State of the remote.
4325
        state: GrandpaState,
4326
    },
4327
4328
    /// Received a GrandPa commit message from the network.
4329
    ///
4330
    /// Can only happen after a [`Event::GossipConnected`] with the given [`PeerId`] and [`ChainId`]
4331
    /// combination has happened.
4332
    GrandpaCommitMessage {
4333
        /// Identity of the sender of the message.
4334
        peer_id: PeerId,
4335
        /// Index of the chain the commit message relates to.
4336
        chain_id: ChainId,
4337
        message: EncodedGrandpaCommitMessage,
4338
    },
4339
4340
    /// Error in the protocol in a connection, such as failure to decode a message. This event
4341
    /// doesn't have any consequence on the health of the connection, and is purely for diagnostic
4342
    /// purposes.
4343
    // TODO: review the concept of protocol error
4344
    ProtocolError {
4345
        /// Peer that has caused the protocol error.
4346
        peer_id: PeerId,
4347
        /// Error that happened.
4348
        error: ProtocolError,
4349
    },
4350
4351
    /// A remote has sent a request for identification information.
4352
    ///
4353
    /// You are strongly encouraged to call [`ChainNetwork::respond_identify`].
4354
    IdentifyRequestIn {
4355
        /// Remote that has sent the request.
4356
        peer_id: PeerId,
4357
        /// Identifier of the request. Necessary to send back the answer.
4358
        substream_id: SubstreamId,
4359
    },
4360
4361
    /// A remote has sent a request for blocks.
4362
    ///
4363
    /// Can only happen for chains where [`ChainConfig::allow_inbound_block_requests`] is `true`.
4364
    ///
4365
    /// You are strongly encouraged to call [`ChainNetwork::respond_blocks`].
4366
    BlocksRequestIn {
4367
        /// Remote that has sent the request.
4368
        peer_id: PeerId,
4369
        /// Index of the chain concerned by the request.
4370
        chain_id: ChainId,
4371
        /// Information about the request.
4372
        config: codec::BlocksRequestConfig,
4373
        /// Identifier of the request. Necessary to send back the answer.
4374
        substream_id: SubstreamId,
4375
    },
4376
4377
    /// A remote is no longer interested in the response to a request.
4378
    ///
4379
    /// Calling [`ChainNetwork::respond_identify`], [`ChainNetwork::respond_blocks`], or similar
4380
    /// will now panic.
4381
    RequestInCancel {
4382
        /// Identifier of the request.
4383
        ///
4384
        /// This [`SubstreamId`] is considered dead and no longer valid.
4385
        substream_id: SubstreamId,
4386
    },
4387
    /*Transactions {
4388
        peer_id: PeerId,
4389
        transactions: EncodedTransactions,
4390
    }*/
4391
}
4392
4393
/// See [`Event::ProtocolError`].
4394
// TODO: reexport these error types
4395
#[derive(Debug, derive_more::Display, derive_more::Error)]
4396
pub enum ProtocolError {
4397
    /// Error in an incoming substream.
4398
    #[display("Error in an incoming substream: {_0}")]
4399
    InboundError(InboundError),
4400
    /// Error while decoding the handshake of the block announces substream.
4401
    #[display("Error while decoding the handshake of the block announces substream: {_0}")]
4402
    BadBlockAnnouncesHandshake(BlockAnnouncesHandshakeDecodeError),
4403
    /// Error while decoding a received block announce.
4404
    #[display("Error while decoding a received block announce: {_0}")]
4405
    BadBlockAnnounce(codec::DecodeBlockAnnounceError),
4406
    /// Error while decoding a received Grandpa notification.
4407
    #[display("Error while decoding a received Grandpa notification: {_0}")]
4408
    BadGrandpaNotification(codec::DecodeGrandpaNotificationError),
4409
    /// Received an invalid identify request.
4410
    BadIdentifyRequest,
4411
    /// Error while decoding a received blocks request.
4412
    #[display("Error while decoding a received blocks request: {_0}")]
4413
    BadBlocksRequest(codec::DecodeBlockRequestError),
4414
}
4415
4416
/// Error potentially returned by [`ChainNetwork::gossip_open`].
4417
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4418
pub enum OpenGossipError {
4419
    /// No healthy established connection is available to open the link.
4420
    NoConnection,
4421
    /// There already is a pending or fully opened gossip link with the given peer.
4422
    AlreadyOpened,
4423
}
4424
4425
/// Error potentially returned by [`ChainNetwork::gossip_close`].
4426
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4427
pub enum CloseGossipError {
4428
    /// There exists no outgoing nor ingoing attempt at a gossip link.
4429
    NotOpen,
4430
}
4431
4432
/// Error potentially returned when starting a request.
4433
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4434
pub enum StartRequestError {
4435
    /// There is no valid connection to the given peer on which the request can be started.
4436
    NoConnection,
4437
}
4438
4439
/// Error potentially returned when starting a request that might be too large.
4440
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4441
pub enum StartRequestMaybeTooLargeError {
4442
    /// There is no valid connection to the given peer on which the request can be started.
4443
    NoConnection,
4444
    /// Size of the request is over maximum allowed by the protocol.
4445
    RequestTooLarge,
4446
}
4447
4448
impl From<StartRequestError> for StartRequestMaybeTooLargeError {
4449
0
    fn from(err: StartRequestError) -> StartRequestMaybeTooLargeError {
4450
0
        match err {
4451
0
            StartRequestError::NoConnection => StartRequestMaybeTooLargeError::NoConnection,
4452
        }
4453
0
    }
Unexecuted instantiation: _RNvXs5_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_30StartRequestMaybeTooLargeErrorINtNtCs1p5UDGgVI4d_4core7convert4FromNtB5_17StartRequestErrorE4from
Unexecuted instantiation: _RNvXs5_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_30StartRequestMaybeTooLargeErrorINtNtCs1p5UDGgVI4d_4core7convert4FromNtB5_17StartRequestErrorE4from
4454
}
4455
4456
/// Response to an outgoing request.
4457
///
4458
/// See [`Event::RequestResult`̀].
4459
#[derive(Debug)]
4460
pub enum RequestResult {
4461
    Blocks(Result<Vec<codec::BlockData>, BlocksRequestError>),
4462
    GrandpaWarpSync(Result<EncodedGrandpaWarpSyncResponse, GrandpaWarpSyncRequestError>),
4463
    State(Result<EncodedStateResponse, StateRequestError>),
4464
    StorageProof(Result<EncodedMerkleProof, StorageProofRequestError>),
4465
    CallProof(Result<EncodedMerkleProof, CallProofRequestError>),
4466
    KademliaFindNode(Result<Vec<(peer_id::PeerId, Vec<Vec<u8>>)>, KademliaFindNodeError>),
4467
}
4468
4469
/// Error returned by [`ChainNetwork::start_blocks_request`].
4470
#[derive(Debug, derive_more::Display, derive_more::Error)]
4471
pub enum BlocksRequestError {
4472
    /// Error while waiting for the response from the peer.
4473
    #[display("{_0}")]
4474
    Request(RequestError),
4475
    /// Error while decoding the response returned by the peer.
4476
    #[display("Response decoding error: {_0}")]
4477
    Decode(codec::DecodeBlockResponseError),
4478
}
4479
4480
/// Error returned by [`ChainNetwork::start_storage_proof_request`].
4481
#[derive(Debug, derive_more::Display, derive_more::Error, Clone)]
4482
pub enum StorageProofRequestError {
4483
    #[display("{_0}")]
4484
    Request(RequestError),
4485
    #[display("Response decoding error: {_0}")]
4486
    Decode(codec::DecodeStorageCallProofResponseError),
4487
    /// The remote is incapable of answering this specific request.
4488
    RemoteCouldntAnswer,
4489
}
4490
4491
/// Error returned by [`ChainNetwork::start_call_proof_request`].
4492
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4493
pub enum CallProofRequestError {
4494
    #[display("{_0}")]
4495
    Request(RequestError),
4496
    #[display("Response decoding error: {_0}")]
4497
    Decode(codec::DecodeStorageCallProofResponseError),
4498
    /// The remote is incapable of answering this specific request.
4499
    RemoteCouldntAnswer,
4500
}
4501
4502
impl CallProofRequestError {
4503
    /// Returns `true` if this is caused by networking issues, as opposed to a consensus-related
4504
    /// issue.
4505
0
    pub fn is_network_problem(&self) -> bool {
4506
0
        match self {
4507
0
            CallProofRequestError::Request(_) => true,
4508
0
            CallProofRequestError::Decode(_) => false,
4509
0
            CallProofRequestError::RemoteCouldntAnswer => true,
4510
        }
4511
0
    }
Unexecuted instantiation: _RNvMs6_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_21CallProofRequestError18is_network_problem
Unexecuted instantiation: _RNvMs6_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_21CallProofRequestError18is_network_problem
4512
}
4513
4514
/// Error returned by [`ChainNetwork::start_grandpa_warp_sync_request`].
4515
#[derive(Debug, derive_more::Display, derive_more::Error)]
4516
pub enum GrandpaWarpSyncRequestError {
4517
    #[display("{_0}")]
4518
    Request(RequestError),
4519
    #[display("Response decoding error: {_0}")]
4520
    Decode(codec::DecodeGrandpaWarpSyncResponseError),
4521
}
4522
4523
/// Error returned by [`ChainNetwork::start_state_request`].
4524
#[derive(Debug, derive_more::Display, derive_more::Error)]
4525
pub enum StateRequestError {
4526
    #[display("{_0}")]
4527
    Request(RequestError),
4528
    #[display("Response decoding error: {_0}")]
4529
    Decode(codec::DecodeStateResponseError),
4530
}
4531
4532
/// Error during [`ChainNetwork::start_kademlia_find_node_request`].
4533
#[derive(Debug, derive_more::Display, derive_more::Error)]
4534
pub enum KademliaFindNodeError {
4535
    /// Error during the request.
4536
    #[display("{_0}")]
4537
    RequestFailed(RequestError),
4538
    /// Failed to decode the response.
4539
    #[display("Response decoding error: {_0}")]
4540
    DecodeError(codec::DecodeFindNodeResponseError),
4541
}
4542
4543
/// Error potentially returned when queueing a notification.
4544
#[derive(Debug, derive_more::Display, derive_more::Error)]
4545
pub enum QueueNotificationError {
4546
    /// There is no valid substream to the given peer on which the notification can be sent.
4547
    NoConnection,
4548
    /// Queue of notifications with that peer is full.
4549
    QueueFull,
4550
}
4551
4552
/// Undecoded but valid block announce.
4553
#[derive(Clone)]
4554
pub struct EncodedBlockAnnounce {
4555
    message: Vec<u8>,
4556
    block_number_bytes: usize,
4557
}
4558
4559
impl EncodedBlockAnnounce {
4560
    /// Returns the decoded version of the announcement.
4561
0
    pub fn decode(&self) -> codec::BlockAnnounceRef {
4562
0
        codec::decode_block_announce(&self.message, self.block_number_bytes).unwrap()
4563
0
    }
Unexecuted instantiation: _RNvMs7_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_20EncodedBlockAnnounce6decode
Unexecuted instantiation: _RNvMs7_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_20EncodedBlockAnnounce6decode
4564
}
4565
4566
impl fmt::Debug for EncodedBlockAnnounce {
4567
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4568
0
        fmt::Debug::fmt(&self.decode(), f)
4569
0
    }
Unexecuted instantiation: _RNvXs8_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_20EncodedBlockAnnounceNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXs8_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_20EncodedBlockAnnounceNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4570
}
4571
4572
/// Undecoded but valid Merkle proof.
4573
#[derive(Clone)]
4574
pub struct EncodedMerkleProof(Vec<u8>, codec::StorageOrCallProof);
4575
4576
impl EncodedMerkleProof {
4577
    /// Returns the SCALE-encoded Merkle proof.
4578
0
    pub fn decode(&self) -> &[u8] {
4579
0
        codec::decode_storage_or_call_proof_response(self.1, &self.0)
4580
0
            .unwrap()
4581
0
            .unwrap()
4582
0
    }
Unexecuted instantiation: _RNvMs9_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_18EncodedMerkleProof6decode
Unexecuted instantiation: _RNvMs9_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_18EncodedMerkleProof6decode
4583
}
4584
4585
impl fmt::Debug for EncodedMerkleProof {
4586
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4587
0
        fmt::Debug::fmt(&self.decode(), f)
4588
0
    }
Unexecuted instantiation: _RNvXsa_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_18EncodedMerkleProofNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsa_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_18EncodedMerkleProofNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4589
}
4590
4591
/// Undecoded but valid GrandPa warp sync response.
4592
#[derive(Clone)]
4593
pub struct EncodedGrandpaWarpSyncResponse {
4594
    message: Vec<u8>,
4595
    block_number_bytes: usize,
4596
}
4597
4598
impl EncodedGrandpaWarpSyncResponse {
4599
    /// Returns the encoded bytes of the warp sync message.
4600
0
    pub fn as_encoded(&self) -> &[u8] {
4601
0
        &self.message
4602
0
    }
Unexecuted instantiation: _RNvMsb_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponse10as_encoded
Unexecuted instantiation: _RNvMsb_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponse10as_encoded
4603
4604
    /// Returns the decoded version of the warp sync message.
4605
0
    pub fn decode(&self) -> codec::GrandpaWarpSyncResponse {
4606
0
        match codec::decode_grandpa_warp_sync_response(&self.message, self.block_number_bytes) {
4607
0
            Ok(msg) => msg,
4608
0
            _ => unreachable!(),
4609
        }
4610
0
    }
Unexecuted instantiation: _RNvMsb_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponse6decode
Unexecuted instantiation: _RNvMsb_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponse6decode
4611
}
4612
4613
impl fmt::Debug for EncodedGrandpaWarpSyncResponse {
4614
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4615
0
        fmt::Debug::fmt(&self.decode(), f)
4616
0
    }
Unexecuted instantiation: _RNvXsc_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponseNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsc_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_30EncodedGrandpaWarpSyncResponseNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4617
}
4618
4619
/// Undecoded but valid state response.
4620
// TODO: merge with EncodedMerkleProof?
4621
#[derive(Clone)]
4622
pub struct EncodedStateResponse(Vec<u8>);
4623
4624
impl EncodedStateResponse {
4625
    /// Returns the Merkle proof of the state response.
4626
0
    pub fn decode(&self) -> &[u8] {
4627
0
        match codec::decode_state_response(&self.0) {
4628
0
            Ok(r) => r,
4629
0
            Err(_) => unreachable!(),
4630
        }
4631
0
    }
Unexecuted instantiation: _RNvMsd_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_20EncodedStateResponse6decode
Unexecuted instantiation: _RNvMsd_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_20EncodedStateResponse6decode
4632
}
4633
4634
impl fmt::Debug for EncodedStateResponse {
4635
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4636
0
        fmt::Debug::fmt(&self.decode(), f)
4637
0
    }
Unexecuted instantiation: _RNvXse_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_20EncodedStateResponseNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXse_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_20EncodedStateResponseNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4638
}
4639
4640
#[derive(Debug, Copy, Clone)]
4641
// TODO: link to some doc about how GrandPa works: what is a round, what is the set id, etc.
4642
pub struct GrandpaState {
4643
    pub round_number: u64,
4644
    /// Set of authorities that will be used by the node to try finalize the children of the block
4645
    /// of [`GrandpaState::commit_finalized_height`].
4646
    pub set_id: u64,
4647
    /// Height of the highest block considered final by the node.
4648
    pub commit_finalized_height: u64,
4649
}
4650
4651
/// Undecoded but valid block announce handshake.
4652
pub struct EncodedBlockAnnounceHandshake {
4653
    handshake: Vec<u8>,
4654
    block_number_bytes: usize,
4655
}
4656
4657
impl EncodedBlockAnnounceHandshake {
4658
    /// Returns the decoded version of the handshake.
4659
0
    pub fn decode(&self) -> codec::BlockAnnouncesHandshakeRef {
4660
0
        codec::decode_block_announces_handshake(self.block_number_bytes, &self.handshake).unwrap()
4661
0
    }
Unexecuted instantiation: _RNvMsf_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_29EncodedBlockAnnounceHandshake6decode
Unexecuted instantiation: _RNvMsf_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_29EncodedBlockAnnounceHandshake6decode
4662
}
4663
4664
impl fmt::Debug for EncodedBlockAnnounceHandshake {
4665
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4666
0
        fmt::Debug::fmt(&self.decode(), f)
4667
0
    }
Unexecuted instantiation: _RNvXsg_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_29EncodedBlockAnnounceHandshakeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsg_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_29EncodedBlockAnnounceHandshakeNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4668
}
4669
4670
/// Error that can happen when trying to open an outbound block announces notifications substream.
4671
#[derive(Debug, Clone, derive_more::Display, derive_more::Error)]
4672
pub enum GossipConnectError {
4673
    /// Error in the underlying protocol.
4674
    #[display("{_0}")]
4675
    Substream(NotificationsOutErr),
4676
    /// Error decoding the block announces handshake.
4677
    HandshakeDecode(BlockAnnouncesHandshakeDecodeError),
4678
    /// Mismatch between the genesis hash of the remote and the local genesis hash.
4679
    #[display("Mismatch between the genesis hash of the remote and the local genesis hash")]
4680
    GenesisMismatch {
4681
        /// Hash of the genesis block of the chain according to the local node.
4682
        local_genesis: [u8; 32],
4683
        /// Hash of the genesis block of the chain according to the remote node.
4684
        remote_genesis: [u8; 32],
4685
    },
4686
}
4687
4688
/// Undecoded but valid GrandPa commit message.
4689
#[derive(Clone)]
4690
pub struct EncodedGrandpaCommitMessage {
4691
    message: Vec<u8>,
4692
    block_number_bytes: usize,
4693
}
4694
4695
impl EncodedGrandpaCommitMessage {
4696
    /// Returns the encoded bytes of the commit message.
4697
0
    pub fn into_encoded(mut self) -> Vec<u8> {
4698
        // Skip the first byte because `self.message` is a `GrandpaNotificationRef`.
4699
0
        self.message.remove(0);
4700
0
        self.message
4701
0
    }
Unexecuted instantiation: _RNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage12into_encoded
Unexecuted instantiation: _RNvMsh_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage12into_encoded
4702
4703
    /// Returns the encoded bytes of the commit message.
4704
0
    pub fn as_encoded(&self) -> &[u8] {
4705
        // Skip the first byte because `self.message` is a `GrandpaNotificationRef`.
4706
0
        &self.message[1..]
4707
0
    }
Unexecuted instantiation: _RNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage10as_encoded
Unexecuted instantiation: _RNvMsh_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage10as_encoded
4708
4709
    /// Returns the decoded version of the commit message.
4710
0
    pub fn decode(&self) -> codec::CommitMessageRef {
4711
0
        match codec::decode_grandpa_notification(&self.message, self.block_number_bytes) {
4712
0
            Ok(codec::GrandpaNotificationRef::Commit(msg)) => msg,
4713
0
            _ => unreachable!(),
4714
        }
4715
0
    }
Unexecuted instantiation: _RNvMsh_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage6decode
Unexecuted instantiation: _RNvMsh_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessage6decode
4716
}
4717
4718
impl fmt::Debug for EncodedGrandpaCommitMessage {
4719
0
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4720
0
        fmt::Debug::fmt(&self.decode(), f)
4721
0
    }
Unexecuted instantiation: _RNvXsi_NtNtCsjlkOsLH0Zfj_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessageNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
Unexecuted instantiation: _RNvXsi_NtNtCsc1ywvx6YAnK_7smoldot7network7serviceNtB5_27EncodedGrandpaCommitMessageNtNtCs1p5UDGgVI4d_4core3fmt5Debug3fmt
4722
}