/__w/smoldot/smoldot/repo/lib/src/network/basic_peering_strategy.rs
Line | Count | Source (jump to first uncovered line) |
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 | | //! Basic address book and slots assignments algorithm. |
19 | | //! |
20 | | //! The [`BasicPeeringStrategy`] contains a collection of network identities, identified by |
21 | | //! a [`PeerId`]. Each network identity is associated to one or more chains, identified by a |
22 | | //! `TChainId`. |
23 | | //! |
24 | | //! Each network-identity-chain association can be in one of these three states: |
25 | | //! |
26 | | //! - Normal. |
27 | | //! - Banned until a certain instant represented by `TInstant`. |
28 | | //! - Has a slot. |
29 | | //! |
30 | | //! "Normal" and "banned" network-identity-chain associations represent the potential peers to |
31 | | //! connect to, while "slot" represent pending or established gossip slots. |
32 | | //! |
33 | | //! Use [`BasicPeeringStrategy::pick_assignable_peer`] in order to assign a slot to a |
34 | | //! randomly-chosen network-identity that doesn't currently have one. |
35 | | //! |
36 | | //! If a gossip slot fails to be established with a certain peer, or if the peer misbehaves, |
37 | | //! use [`BasicPeeringStrategy::unassign_slot_and_ban`] to ban the peer, preventing it from |
38 | | //! obtaining a slot for a certain amount of time. |
39 | | //! |
40 | | //! Each network identity that is associated with at least one chain is associated with zero or |
41 | | //! more addresses. It is not possible to insert addresses to peers that aren't associated to at |
42 | | //! least one chain. The number of active connections of each address is also tracked. |
43 | | //! |
44 | | //! There exists a limit to the number of peers per chain and the number of addresses per peer, |
45 | | //! guaranteeing that the data structure only uses a bounded amount of memory. If these limits |
46 | | //! are reached, peers and addresses are removed randomly. Peers that have a slot and at least one |
47 | | //! connected address are never removed. |
48 | | //! |
49 | | |
50 | | use crate::util; |
51 | | use alloc::{ |
52 | | borrow::ToOwned as _, |
53 | | collections::{btree_map, BTreeMap, BTreeSet}, |
54 | | vec::Vec, |
55 | | }; |
56 | | use core::{hash::Hash, iter, ops}; |
57 | | use rand::seq::IteratorRandom as _; |
58 | | use rand_chacha::{ |
59 | | rand_core::{RngCore as _, SeedableRng as _}, |
60 | | ChaCha20Rng, |
61 | | }; |
62 | | |
63 | | pub use crate::libp2p::PeerId; |
64 | | |
65 | | #[derive(Debug)] |
66 | | pub struct BasicPeeringStrategy<TChainId, TInstant> { |
67 | | /// Contains all the `PeerId`s used throughout the collection. |
68 | | peer_ids: slab::Slab<PeerId>, |
69 | | |
70 | | /// Contains all the keys of [`BasicPeeringStrategy::peer_ids`] indexed differently. |
71 | | peer_ids_indices: hashbrown::HashMap<PeerId, usize, util::SipHasherBuild>, |
72 | | |
73 | | /// List of all known addresses, indexed by `peer_id_index`, with the number of connections to |
74 | | /// each address. The addresses are not intended to be in a particular order. |
75 | | addresses: BTreeMap<(usize, Vec<u8>), u32>, |
76 | | |
77 | | /// List of all chains throughout the collection. |
78 | | /// |
79 | | /// > **Note**: In principle this field is completely unnecessary. In practice, however, we |
80 | | /// > can't use `BTreeMap::range` with `TChainId`s because we don't know the minimum |
81 | | /// > and maximum values of a `TChainId`. In order to bypass this problem, |
82 | | /// > `TChainId`s are instead refered to as a `usize`. |
83 | | chains: slab::Slab<TChainId>, |
84 | | |
85 | | /// Contains all the keys of [`BasicPeeringStrategy::chains`] indexed differently. |
86 | | /// While a dumber hasher is in principle enough, we use a `SipHasherBuild` "just in case" |
87 | | /// as we don't know the properties of `TChainId`. |
88 | | chains_indices: hashbrown::HashMap<TChainId, usize, util::SipHasherBuild>, |
89 | | |
90 | | /// Collection of |
91 | | /// Keys are `(peer_id_index, chain_id_index)`. |
92 | | peers_chains: BTreeMap<(usize, usize), PeerChainState<TInstant>>, |
93 | | |
94 | | /// Entries are `(chain_id_index, state, peer_id_index)`. |
95 | | peers_chains_by_state: BTreeSet<(usize, PeerChainState<TInstant>, usize)>, |
96 | | |
97 | | /// Random number generator used to select peers to assign slots to and remove addresses/peers. |
98 | | randomness: ChaCha20Rng, |
99 | | } |
100 | | |
101 | | #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] |
102 | | enum PeerChainState<TInstant> { |
103 | | Assignable, |
104 | | Banned { expires: TInstant }, |
105 | | Slot, |
106 | | } |
107 | | |
108 | | /// Configuration passed to [`BasicPeeringStrategy::new`]. |
109 | | pub struct Config { |
110 | | /// Seed used for the randomness for choosing peers and addresses to connect to or remove. |
111 | | pub randomness_seed: [u8; 32], |
112 | | |
113 | | /// Number of peers, all chains together, to initially reserve memory for. |
114 | | pub peers_capacity: usize, |
115 | | |
116 | | /// Number of chains to initially reserve memory for. |
117 | | pub chains_capacity: usize, |
118 | | } |
119 | | |
120 | | impl<TChainId, TInstant> BasicPeeringStrategy<TChainId, TInstant> |
121 | | where |
122 | | TChainId: PartialOrd + Ord + Eq + Hash + Clone, |
123 | | TInstant: PartialOrd + Ord + Eq + Clone, |
124 | | { |
125 | | /// Creates a new empty [`BasicPeeringStrategy`]. |
126 | | /// |
127 | | /// Must be passed a seed for randomness used |
128 | | /// in [`BasicPeeringStrategy::pick_assignable_peer`]. |
129 | 25 | pub fn new(config: Config) -> Self { |
130 | 25 | let mut randomness = ChaCha20Rng::from_seed(config.randomness_seed); |
131 | 25 | |
132 | 25 | BasicPeeringStrategy { |
133 | 25 | peer_ids: slab::Slab::with_capacity(config.peers_capacity), |
134 | 25 | peer_ids_indices: hashbrown::HashMap::with_capacity_and_hasher( |
135 | 25 | config.peers_capacity, |
136 | 25 | util::SipHasherBuild::new({ |
137 | 25 | let mut seed = [0; 16]; |
138 | 25 | randomness.fill_bytes(&mut seed); |
139 | 25 | seed |
140 | 25 | }), |
141 | 25 | ), |
142 | 25 | addresses: BTreeMap::new(), |
143 | 25 | chains: slab::Slab::with_capacity(config.chains_capacity), |
144 | 25 | chains_indices: hashbrown::HashMap::with_capacity_and_hasher( |
145 | 25 | config.chains_capacity, |
146 | 25 | util::SipHasherBuild::new({ |
147 | 25 | let mut seed = [0; 16]; |
148 | 25 | randomness.fill_bytes(&mut seed); |
149 | 25 | seed |
150 | 25 | }), |
151 | 25 | ), |
152 | 25 | peers_chains: BTreeMap::new(), |
153 | 25 | peers_chains_by_state: BTreeSet::new(), |
154 | 25 | randomness, |
155 | 25 | } |
156 | 25 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE3newB6_ Line | Count | Source | 129 | 4 | pub fn new(config: Config) -> Self { | 130 | 4 | let mut randomness = ChaCha20Rng::from_seed(config.randomness_seed); | 131 | 4 | | 132 | 4 | BasicPeeringStrategy { | 133 | 4 | peer_ids: slab::Slab::with_capacity(config.peers_capacity), | 134 | 4 | peer_ids_indices: hashbrown::HashMap::with_capacity_and_hasher( | 135 | 4 | config.peers_capacity, | 136 | 4 | util::SipHasherBuild::new({ | 137 | 4 | let mut seed = [0; 16]; | 138 | 4 | randomness.fill_bytes(&mut seed); | 139 | 4 | seed | 140 | 4 | }), | 141 | 4 | ), | 142 | 4 | addresses: BTreeMap::new(), | 143 | 4 | chains: slab::Slab::with_capacity(config.chains_capacity), | 144 | 4 | chains_indices: hashbrown::HashMap::with_capacity_and_hasher( | 145 | 4 | config.chains_capacity, | 146 | 4 | util::SipHasherBuild::new({ | 147 | 4 | let mut seed = [0; 16]; | 148 | 4 | randomness.fill_bytes(&mut seed); | 149 | 4 | seed | 150 | 4 | }), | 151 | 4 | ), | 152 | 4 | peers_chains: BTreeMap::new(), | 153 | 4 | peers_chains_by_state: BTreeSet::new(), | 154 | 4 | randomness, | 155 | 4 | } | 156 | 4 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE3newCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE3newB6_ _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE3newCsiLzmwikkc22_14json_rpc_basic Line | Count | Source | 129 | 2 | pub fn new(config: Config) -> Self { | 130 | 2 | let mut randomness = ChaCha20Rng::from_seed(config.randomness_seed); | 131 | 2 | | 132 | 2 | BasicPeeringStrategy { | 133 | 2 | peer_ids: slab::Slab::with_capacity(config.peers_capacity), | 134 | 2 | peer_ids_indices: hashbrown::HashMap::with_capacity_and_hasher( | 135 | 2 | config.peers_capacity, | 136 | 2 | util::SipHasherBuild::new({ | 137 | 2 | let mut seed = [0; 16]; | 138 | 2 | randomness.fill_bytes(&mut seed); | 139 | 2 | seed | 140 | 2 | }), | 141 | 2 | ), | 142 | 2 | addresses: BTreeMap::new(), | 143 | 2 | chains: slab::Slab::with_capacity(config.chains_capacity), | 144 | 2 | chains_indices: hashbrown::HashMap::with_capacity_and_hasher( | 145 | 2 | config.chains_capacity, | 146 | 2 | util::SipHasherBuild::new({ | 147 | 2 | let mut seed = [0; 16]; | 148 | 2 | randomness.fill_bytes(&mut seed); | 149 | 2 | seed | 150 | 2 | }), | 151 | 2 | ), | 152 | 2 | peers_chains: BTreeMap::new(), | 153 | 2 | peers_chains_by_state: BTreeSet::new(), | 154 | 2 | randomness, | 155 | 2 | } | 156 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE3newCscDgN54JpMGG_6author _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE3newCsibGXYHQB8Ea_25json_rpc_general_requests Line | Count | Source | 129 | 19 | pub fn new(config: Config) -> Self { | 130 | 19 | let mut randomness = ChaCha20Rng::from_seed(config.randomness_seed); | 131 | 19 | | 132 | 19 | BasicPeeringStrategy { | 133 | 19 | peer_ids: slab::Slab::with_capacity(config.peers_capacity), | 134 | 19 | peer_ids_indices: hashbrown::HashMap::with_capacity_and_hasher( | 135 | 19 | config.peers_capacity, | 136 | 19 | util::SipHasherBuild::new({ | 137 | 19 | let mut seed = [0; 16]; | 138 | 19 | randomness.fill_bytes(&mut seed); | 139 | 19 | seed | 140 | 19 | }), | 141 | 19 | ), | 142 | 19 | addresses: BTreeMap::new(), | 143 | 19 | chains: slab::Slab::with_capacity(config.chains_capacity), | 144 | 19 | chains_indices: hashbrown::HashMap::with_capacity_and_hasher( | 145 | 19 | config.chains_capacity, | 146 | 19 | util::SipHasherBuild::new({ | 147 | 19 | let mut seed = [0; 16]; | 148 | 19 | randomness.fill_bytes(&mut seed); | 149 | 19 | seed | 150 | 19 | }), | 151 | 19 | ), | 152 | 19 | peers_chains: BTreeMap::new(), | 153 | 19 | peers_chains_by_state: BTreeSet::new(), | 154 | 19 | randomness, | 155 | 19 | } | 156 | 19 | } |
|
157 | | |
158 | | /// Removes all the chain assignments for the given chain. |
159 | | /// |
160 | | /// If a peer isn't assigned to any chain anymore and doesn't have any connected address, |
161 | | /// all of its addresses are also removed from the collection. |
162 | 0 | pub fn remove_chain_peers(&mut self, chain: &TChainId) { |
163 | 0 | let Some(chain_index) = self.chains_indices.remove(chain) else { |
164 | | // Chain didn't exist. |
165 | 0 | return; |
166 | | }; |
167 | 0 | self.chains.remove(chain_index); |
168 | 0 |
|
169 | 0 | let chain_peers = { |
170 | 0 | let mut in_chain_and_after_chain = self.peers_chains_by_state.split_off(&( |
171 | 0 | chain_index, |
172 | 0 | PeerChainState::Assignable, |
173 | 0 | usize::MIN, |
174 | 0 | )); |
175 | 0 | let mut after_chain = in_chain_and_after_chain.split_off(&( |
176 | 0 | chain_index + 1, |
177 | 0 | PeerChainState::Assignable, |
178 | 0 | usize::MIN, |
179 | 0 | )); |
180 | 0 | self.peers_chains_by_state.append(&mut after_chain); |
181 | 0 | in_chain_and_after_chain |
182 | | }; |
183 | | |
184 | 0 | for (_, _, peer_id_index) in chain_peers { |
185 | 0 | let _was_in = self.peers_chains.remove(&(peer_id_index, chain_index)); |
186 | 0 | debug_assert!(_was_in.is_some()); |
187 | 0 | self.try_clean_up_peer_id(peer_id_index); |
188 | | } |
189 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE18remove_chain_peersB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE18remove_chain_peersCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE18remove_chain_peersB6_ |
190 | | |
191 | | /// Inserts a chain-peer combination to the collection, indicating that the given peer belongs |
192 | | /// to the given chain. |
193 | | /// |
194 | | /// Has no effect if the peer is already assigned to the given chain, in which case |
195 | | /// [`InsertChainPeerResult::Duplicate`] is returned. |
196 | | /// |
197 | | /// A maximum number of peers per chain must be provided. If the peer is inserted and the |
198 | | /// limit is exceeded, a peer (other than the one that has just been inserted) that belongs |
199 | | /// to the given chain is randomly chosen and removed. Peers that have slots assigned to them |
200 | | /// are never removed. |
201 | 2 | pub fn insert_chain_peer( |
202 | 2 | &mut self, |
203 | 2 | chain: TChainId, |
204 | 2 | peer_id: PeerId, |
205 | 2 | max_peers_per_chain: usize, |
206 | 2 | ) -> InsertChainPeerResult { |
207 | 2 | let peer_id_index = self.get_or_insert_peer_index(&peer_id); |
208 | 2 | let chain_index = self.get_or_insert_chain_index(&chain); |
209 | | |
210 | 2 | if let btree_map::Entry::Vacant(entry) = |
211 | 2 | self.peers_chains.entry((peer_id_index, chain_index)) |
212 | | { |
213 | 2 | let peer_to_remove = if self |
214 | 2 | .peers_chains_by_state |
215 | 2 | .range( |
216 | 2 | (chain_index, PeerChainState::Assignable, usize::MIN) |
217 | 2 | ..=(chain_index, PeerChainState::Slot, usize::MAX), |
218 | 2 | ) |
219 | 2 | .count() |
220 | 2 | >= max_peers_per_chain |
221 | | { |
222 | 0 | self.peers_chains_by_state |
223 | 0 | .range( |
224 | 0 | (chain_index, PeerChainState::Assignable, usize::MIN) |
225 | 0 | ..(chain_index, PeerChainState::Slot, usize::MIN), |
226 | 0 | ) |
227 | 0 | .choose(&mut self.randomness) |
228 | 0 | .map(|(_, _, peer_index)| *peer_index) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peer0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peer0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE17insert_chain_peer0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peer0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peer0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peer0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peer0CsibGXYHQB8Ea_25json_rpc_general_requests |
229 | | } else { |
230 | 2 | None |
231 | | }; |
232 | | |
233 | 2 | let _was_inserted = self.peers_chains_by_state.insert(( |
234 | 2 | chain_index, |
235 | 2 | PeerChainState::Assignable, |
236 | 2 | peer_id_index, |
237 | 2 | )); |
238 | 2 | debug_assert!(_was_inserted); |
239 | | |
240 | 2 | entry.insert(PeerChainState::Assignable); |
241 | | |
242 | 2 | let peer_removed = if let Some(peer_to_remove0 ) = peer_to_remove { |
243 | 0 | let peer_id_to_remove = self.peer_ids[peer_to_remove].clone(); |
244 | 0 | let state = self |
245 | 0 | .peers_chains |
246 | 0 | .remove(&(peer_to_remove, chain_index)) |
247 | 0 | .unwrap_or_else(|| unreachable!()); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peers_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peers_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE17insert_chain_peers_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peers_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peers_0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peers_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peers_0CsibGXYHQB8Ea_25json_rpc_general_requests |
248 | 0 | debug_assert!(!matches!(state, PeerChainState::Slot)); |
249 | 0 | let _was_removed = |
250 | 0 | self.peers_chains_by_state |
251 | 0 | .remove(&(chain_index, state, peer_to_remove)); |
252 | 0 | debug_assert!(_was_removed); |
253 | 0 | self.try_clean_up_peer_id(peer_to_remove); |
254 | 0 | Some(peer_id_to_remove) |
255 | | } else { |
256 | 2 | None |
257 | | }; |
258 | | |
259 | 2 | InsertChainPeerResult::Inserted { peer_removed } |
260 | | } else { |
261 | 0 | InsertChainPeerResult::Duplicate |
262 | | } |
263 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peerB6_ Line | Count | Source | 201 | 2 | pub fn insert_chain_peer( | 202 | 2 | &mut self, | 203 | 2 | chain: TChainId, | 204 | 2 | peer_id: PeerId, | 205 | 2 | max_peers_per_chain: usize, | 206 | 2 | ) -> InsertChainPeerResult { | 207 | 2 | let peer_id_index = self.get_or_insert_peer_index(&peer_id); | 208 | 2 | let chain_index = self.get_or_insert_chain_index(&chain); | 209 | | | 210 | 2 | if let btree_map::Entry::Vacant(entry) = | 211 | 2 | self.peers_chains.entry((peer_id_index, chain_index)) | 212 | | { | 213 | 2 | let peer_to_remove = if self | 214 | 2 | .peers_chains_by_state | 215 | 2 | .range( | 216 | 2 | (chain_index, PeerChainState::Assignable, usize::MIN) | 217 | 2 | ..=(chain_index, PeerChainState::Slot, usize::MAX), | 218 | 2 | ) | 219 | 2 | .count() | 220 | 2 | >= max_peers_per_chain | 221 | | { | 222 | 0 | self.peers_chains_by_state | 223 | 0 | .range( | 224 | 0 | (chain_index, PeerChainState::Assignable, usize::MIN) | 225 | 0 | ..(chain_index, PeerChainState::Slot, usize::MIN), | 226 | 0 | ) | 227 | 0 | .choose(&mut self.randomness) | 228 | 0 | .map(|(_, _, peer_index)| *peer_index) | 229 | | } else { | 230 | 2 | None | 231 | | }; | 232 | | | 233 | 2 | let _was_inserted = self.peers_chains_by_state.insert(( | 234 | 2 | chain_index, | 235 | 2 | PeerChainState::Assignable, | 236 | 2 | peer_id_index, | 237 | 2 | )); | 238 | 2 | debug_assert!(_was_inserted); | 239 | | | 240 | 2 | entry.insert(PeerChainState::Assignable); | 241 | | | 242 | 2 | let peer_removed = if let Some(peer_to_remove0 ) = peer_to_remove { | 243 | 0 | let peer_id_to_remove = self.peer_ids[peer_to_remove].clone(); | 244 | 0 | let state = self | 245 | 0 | .peers_chains | 246 | 0 | .remove(&(peer_to_remove, chain_index)) | 247 | 0 | .unwrap_or_else(|| unreachable!()); | 248 | 0 | debug_assert!(!matches!(state, PeerChainState::Slot)); | 249 | 0 | let _was_removed = | 250 | 0 | self.peers_chains_by_state | 251 | 0 | .remove(&(chain_index, state, peer_to_remove)); | 252 | 0 | debug_assert!(_was_removed); | 253 | 0 | self.try_clean_up_peer_id(peer_to_remove); | 254 | 0 | Some(peer_id_to_remove) | 255 | | } else { | 256 | 2 | None | 257 | | }; | 258 | | | 259 | 2 | InsertChainPeerResult::Inserted { peer_removed } | 260 | | } else { | 261 | 0 | InsertChainPeerResult::Duplicate | 262 | | } | 263 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE17insert_chain_peerCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE17insert_chain_peerB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peerCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peerCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peerCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE17insert_chain_peerCsibGXYHQB8Ea_25json_rpc_general_requests |
264 | | |
265 | | /// Removes a peer-chain associated previously inserted with |
266 | | /// [`BasicPeeringStrategy::insert_chain_peer`]. |
267 | | /// |
268 | | /// Has no effect if the peer-chain association didn't exist. |
269 | | /// |
270 | | /// If the peer isn't assigned to any chain anymore and doesn't have any connected address, |
271 | | /// all of its addresses are also removed from the collection. |
272 | 2 | pub fn unassign_slot_and_remove_chain_peer( |
273 | 2 | &mut self, |
274 | 2 | chain: &TChainId, |
275 | 2 | peer_id: &PeerId, |
276 | 2 | ) -> UnassignSlotAndRemoveChainPeer<TInstant> { |
277 | 2 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { |
278 | | // If the `PeerId` is unknown, it means it wasn't assigned in the first place. |
279 | 0 | return UnassignSlotAndRemoveChainPeer::NotAssigned; |
280 | | }; |
281 | | |
282 | 2 | let Some(&chain_index) = self.chains_indices.get(chain) else { |
283 | | // If the `TChainId` is unknown, it means the peer wasn't assigned in the first place. |
284 | 0 | return UnassignSlotAndRemoveChainPeer::NotAssigned; |
285 | | }; |
286 | | |
287 | 2 | if let Some(state) = self.peers_chains.remove(&(peer_id_index, chain_index)) { |
288 | 2 | let _was_removed = |
289 | 2 | self.peers_chains_by_state |
290 | 2 | .remove(&(chain_index, state.clone(), peer_id_index)); |
291 | 2 | debug_assert!(_was_removed); |
292 | | |
293 | 2 | self.try_clean_up_peer_id(peer_id_index); |
294 | 2 | self.try_clean_up_chain(chain_index); |
295 | 2 | |
296 | 2 | match state { |
297 | 2 | PeerChainState::Assignable => UnassignSlotAndRemoveChainPeer::Assigned { |
298 | 2 | ban_expiration: None, |
299 | 2 | }, |
300 | 0 | PeerChainState::Banned { expires } => UnassignSlotAndRemoveChainPeer::Assigned { |
301 | 0 | ban_expiration: Some(expires), |
302 | 0 | }, |
303 | 0 | PeerChainState::Slot => UnassignSlotAndRemoveChainPeer::HadSlot, |
304 | | } |
305 | | } else { |
306 | 0 | UnassignSlotAndRemoveChainPeer::NotAssigned |
307 | | } |
308 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE35unassign_slot_and_remove_chain_peerB6_ Line | Count | Source | 272 | 2 | pub fn unassign_slot_and_remove_chain_peer( | 273 | 2 | &mut self, | 274 | 2 | chain: &TChainId, | 275 | 2 | peer_id: &PeerId, | 276 | 2 | ) -> UnassignSlotAndRemoveChainPeer<TInstant> { | 277 | 2 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { | 278 | | // If the `PeerId` is unknown, it means it wasn't assigned in the first place. | 279 | 0 | return UnassignSlotAndRemoveChainPeer::NotAssigned; | 280 | | }; | 281 | | | 282 | 2 | let Some(&chain_index) = self.chains_indices.get(chain) else { | 283 | | // If the `TChainId` is unknown, it means the peer wasn't assigned in the first place. | 284 | 0 | return UnassignSlotAndRemoveChainPeer::NotAssigned; | 285 | | }; | 286 | | | 287 | 2 | if let Some(state) = self.peers_chains.remove(&(peer_id_index, chain_index)) { | 288 | 2 | let _was_removed = | 289 | 2 | self.peers_chains_by_state | 290 | 2 | .remove(&(chain_index, state.clone(), peer_id_index)); | 291 | 2 | debug_assert!(_was_removed); | 292 | | | 293 | 2 | self.try_clean_up_peer_id(peer_id_index); | 294 | 2 | self.try_clean_up_chain(chain_index); | 295 | 2 | | 296 | 2 | match state { | 297 | 2 | PeerChainState::Assignable => UnassignSlotAndRemoveChainPeer::Assigned { | 298 | 2 | ban_expiration: None, | 299 | 2 | }, | 300 | 0 | PeerChainState::Banned { expires } => UnassignSlotAndRemoveChainPeer::Assigned { | 301 | 0 | ban_expiration: Some(expires), | 302 | 0 | }, | 303 | 0 | PeerChainState::Slot => UnassignSlotAndRemoveChainPeer::HadSlot, | 304 | | } | 305 | | } else { | 306 | 0 | UnassignSlotAndRemoveChainPeer::NotAssigned | 307 | | } | 308 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE35unassign_slot_and_remove_chain_peerCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE35unassign_slot_and_remove_chain_peerB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE35unassign_slot_and_remove_chain_peerCsiUjFBJteJ7x_17smoldot_full_node |
309 | | |
310 | | /// Returns the list of all peers that are known to belong to the given chain, in other |
311 | | /// words peers added through [`BasicPeeringStrategy::insert_chain_peer`]. |
312 | | /// |
313 | | /// The order of the yielded elements is unspecified. |
314 | 0 | pub fn chain_peers_unordered( |
315 | 0 | &'_ self, |
316 | 0 | chain: &TChainId, |
317 | 0 | ) -> impl Iterator<Item = &'_ PeerId> + '_ { |
318 | 0 | let Some(&chain_index) = self.chains_indices.get(chain) else { |
319 | | // If the `TChainId` is unknown, it means that it doesn't have any peer. |
320 | 0 | return either::Right(iter::empty()); |
321 | | }; |
322 | | |
323 | 0 | either::Left( |
324 | 0 | self.peers_chains_by_state |
325 | 0 | .range( |
326 | 0 | (chain_index, PeerChainState::Assignable, usize::MIN) |
327 | 0 | ..=(chain_index, PeerChainState::Slot, usize::MAX), |
328 | 0 | ) |
329 | 0 | .map(|(_, _, p)| &self.peer_ids[*p]), Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE21chain_peers_unordered0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE21chain_peers_unordered0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE21chain_peers_unordered0B8_ |
330 | 0 | ) |
331 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE21chain_peers_unorderedB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE21chain_peers_unorderedCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE21chain_peers_unorderedB6_ |
332 | | |
333 | | /// Inserts a new address for the given peer. |
334 | | /// |
335 | | /// If the address wasn't known yet, its number of connections is set to zero. |
336 | | /// |
337 | | /// If the peer doesn't belong to any chain (see [`BasicPeeringStrategy::insert_chain_peer`]), |
338 | | /// then this function has no effect, unless the peer has at least one connected address. This |
339 | | /// is to avoid accidentally collecting addresses for peers that will never be removed and |
340 | | /// create a memory leak. For this reason, you most likely want to call |
341 | | /// [`BasicPeeringStrategy::insert_chain_peer`] before calling this function. |
342 | | /// |
343 | | /// A maximum number of addresses that are maintained for this peer must be passed as |
344 | | /// parameter. If this number is exceeded, an address with zero connections (other than |
345 | | /// the one passed as parameter) is randomly removed. |
346 | 3 | pub fn insert_address( |
347 | 3 | &mut self, |
348 | 3 | peer_id: &PeerId, |
349 | 3 | address: Vec<u8>, |
350 | 3 | max_addresses: usize, |
351 | 3 | ) -> InsertAddressResult { |
352 | 3 | let Some(&peer_id_index2 ) = self.peer_ids_indices.get(peer_id) else { |
353 | 1 | return InsertAddressResult::UnknownPeer; |
354 | | }; |
355 | | |
356 | 2 | match self.insert_address_inner(peer_id_index, address, max_addresses, 0, false) { |
357 | 0 | InsertAddressConnectionsResult::AlreadyKnown => InsertAddressResult::AlreadyKnown, |
358 | 2 | InsertAddressConnectionsResult::Inserted { address_removed } => { |
359 | 2 | InsertAddressResult::Inserted { address_removed } |
360 | | } |
361 | | } |
362 | 3 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE14insert_addressB6_ Line | Count | Source | 346 | 3 | pub fn insert_address( | 347 | 3 | &mut self, | 348 | 3 | peer_id: &PeerId, | 349 | 3 | address: Vec<u8>, | 350 | 3 | max_addresses: usize, | 351 | 3 | ) -> InsertAddressResult { | 352 | 3 | let Some(&peer_id_index2 ) = self.peer_ids_indices.get(peer_id) else { | 353 | 1 | return InsertAddressResult::UnknownPeer; | 354 | | }; | 355 | | | 356 | 2 | match self.insert_address_inner(peer_id_index, address, max_addresses, 0, false) { | 357 | 0 | InsertAddressConnectionsResult::AlreadyKnown => InsertAddressResult::AlreadyKnown, | 358 | 2 | InsertAddressConnectionsResult::Inserted { address_removed } => { | 359 | 2 | InsertAddressResult::Inserted { address_removed } | 360 | | } | 361 | | } | 362 | 3 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE14insert_addressCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE14insert_addressB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE14insert_addressCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE14insert_addressCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE14insert_addressCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE14insert_addressCsibGXYHQB8Ea_25json_rpc_general_requests |
363 | | |
364 | | /// Increases the number of connections of the given address. If the address isn't known, it |
365 | | /// is inserted. |
366 | | /// |
367 | | /// Contrary to [`BasicPeeringStrategy::insert_address`], the address is inserted anyway if |
368 | | /// the `PeerId` isn't known. |
369 | | /// |
370 | | /// > **Note**: Use this function if you establish a connection and accidentally reach a |
371 | | /// > certain [`PeerId`]. |
372 | | /// |
373 | | /// # Panic |
374 | | /// |
375 | | /// Panics if the number of connections is equal to `u32::MAX`. |
376 | | /// |
377 | 2 | pub fn increase_address_connections( |
378 | 2 | &mut self, |
379 | 2 | peer_id: &PeerId, |
380 | 2 | address: Vec<u8>, |
381 | 2 | max_addresses: usize, |
382 | 2 | ) -> InsertAddressConnectionsResult { |
383 | 2 | let peer_id_index = self.get_or_insert_peer_index(peer_id); |
384 | 2 | self.insert_address_inner(peer_id_index, address, max_addresses, 1, true) |
385 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE28increase_address_connectionsB6_ Line | Count | Source | 377 | 2 | pub fn increase_address_connections( | 378 | 2 | &mut self, | 379 | 2 | peer_id: &PeerId, | 380 | 2 | address: Vec<u8>, | 381 | 2 | max_addresses: usize, | 382 | 2 | ) -> InsertAddressConnectionsResult { | 383 | 2 | let peer_id_index = self.get_or_insert_peer_index(peer_id); | 384 | 2 | self.insert_address_inner(peer_id_index, address, max_addresses, 1, true) | 385 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE28increase_address_connectionsCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE28increase_address_connectionsB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE28increase_address_connectionsCsiUjFBJteJ7x_17smoldot_full_node |
386 | | |
387 | 4 | fn insert_address_inner( |
388 | 4 | &mut self, |
389 | 4 | peer_id_index: usize, |
390 | 4 | address: Vec<u8>, |
391 | 4 | max_addresses: usize, |
392 | 4 | initial_num_connections: u32, |
393 | 4 | increase_if_present: bool, |
394 | 4 | ) -> InsertAddressConnectionsResult { |
395 | 4 | match self.addresses.entry((peer_id_index, address.clone())) { |
396 | 4 | btree_map::Entry::Vacant(entry) => { |
397 | 4 | entry.insert(initial_num_connections); |
398 | | |
399 | 4 | let address_removed = { |
400 | 4 | let num_addresses = self |
401 | 4 | .addresses |
402 | 4 | .range((peer_id_index, Vec::new())..=(peer_id_index + 1, Vec::new())) |
403 | 4 | .count(); |
404 | 4 | |
405 | 4 | if num_addresses >= max_addresses { |
406 | | // TODO: is it a good idea to choose the address randomly to remove? maybe there should be a sorting system with best addresses first? |
407 | 0 | self.addresses |
408 | 0 | .range((peer_id_index, Vec::new())..=(peer_id_index + 1, Vec::new())) |
409 | 0 | .filter(|((_, a), n)| **n == 0 && *a != address) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inner0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inner0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE20insert_address_inner0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inner0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inner0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inner0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inner0CsibGXYHQB8Ea_25json_rpc_general_requests |
410 | 0 | .choose(&mut self.randomness) |
411 | 0 | .map(|((_, a), _)| a.clone()) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inners_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inners_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE20insert_address_inners_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners_0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners_0CsibGXYHQB8Ea_25json_rpc_general_requests |
412 | | } else { |
413 | 4 | None |
414 | | } |
415 | | }; |
416 | | |
417 | 4 | if let Some(address_removed0 ) = address_removed.as_ref() { |
418 | 0 | self.addresses |
419 | 0 | .remove(&(peer_id_index, address_removed.clone())); |
420 | 4 | } |
421 | | |
422 | 4 | InsertAddressConnectionsResult::Inserted { address_removed } |
423 | | } |
424 | 0 | btree_map::Entry::Occupied(entry) => { |
425 | 0 | let entry = entry.into_mut(); |
426 | 0 | if increase_if_present { |
427 | 0 | *entry = entry |
428 | 0 | .checked_add(1) |
429 | 0 | .unwrap_or_else(|| panic!("overflow in number of connections")); Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inners0_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_inners0_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE20insert_address_inners0_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners0_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners0_0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners0_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_inners0_0CsibGXYHQB8Ea_25json_rpc_general_requests |
430 | 0 | } |
431 | | |
432 | 0 | InsertAddressConnectionsResult::AlreadyKnown |
433 | | } |
434 | | } |
435 | 4 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_innerB6_ Line | Count | Source | 387 | 4 | fn insert_address_inner( | 388 | 4 | &mut self, | 389 | 4 | peer_id_index: usize, | 390 | 4 | address: Vec<u8>, | 391 | 4 | max_addresses: usize, | 392 | 4 | initial_num_connections: u32, | 393 | 4 | increase_if_present: bool, | 394 | 4 | ) -> InsertAddressConnectionsResult { | 395 | 4 | match self.addresses.entry((peer_id_index, address.clone())) { | 396 | 4 | btree_map::Entry::Vacant(entry) => { | 397 | 4 | entry.insert(initial_num_connections); | 398 | | | 399 | 4 | let address_removed = { | 400 | 4 | let num_addresses = self | 401 | 4 | .addresses | 402 | 4 | .range((peer_id_index, Vec::new())..=(peer_id_index + 1, Vec::new())) | 403 | 4 | .count(); | 404 | 4 | | 405 | 4 | if num_addresses >= max_addresses { | 406 | | // TODO: is it a good idea to choose the address randomly to remove? maybe there should be a sorting system with best addresses first? | 407 | 0 | self.addresses | 408 | 0 | .range((peer_id_index, Vec::new())..=(peer_id_index + 1, Vec::new())) | 409 | 0 | .filter(|((_, a), n)| **n == 0 && *a != address) | 410 | 0 | .choose(&mut self.randomness) | 411 | 0 | .map(|((_, a), _)| a.clone()) | 412 | | } else { | 413 | 4 | None | 414 | | } | 415 | | }; | 416 | | | 417 | 4 | if let Some(address_removed0 ) = address_removed.as_ref() { | 418 | 0 | self.addresses | 419 | 0 | .remove(&(peer_id_index, address_removed.clone())); | 420 | 4 | } | 421 | | | 422 | 4 | InsertAddressConnectionsResult::Inserted { address_removed } | 423 | | } | 424 | 0 | btree_map::Entry::Occupied(entry) => { | 425 | 0 | let entry = entry.into_mut(); | 426 | 0 | if increase_if_present { | 427 | 0 | *entry = entry | 428 | 0 | .checked_add(1) | 429 | 0 | .unwrap_or_else(|| panic!("overflow in number of connections")); | 430 | 0 | } | 431 | | | 432 | 0 | InsertAddressConnectionsResult::AlreadyKnown | 433 | | } | 434 | | } | 435 | 4 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20insert_address_innerCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE20insert_address_innerB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_innerCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_innerCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_innerCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20insert_address_innerCsibGXYHQB8Ea_25json_rpc_general_requests |
436 | | |
437 | | /// Returns the list of all addresses that have been inserted for the given peer. |
438 | 7 | pub fn peer_addresses(&'_ self, peer_id: &PeerId) -> impl Iterator<Item = &'_ [u8]> + '_ { |
439 | 7 | let Some(&peer_id_index4 ) = self.peer_ids_indices.get(peer_id) else { |
440 | | // If the `PeerId` is unknown, it means it doesn't have any address. |
441 | 3 | return either::Right(iter::empty()); |
442 | | }; |
443 | | |
444 | 4 | either::Left( |
445 | 4 | self.addresses |
446 | 4 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) |
447 | 6 | .map(|((_, a), _)| &a[..]), _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE14peer_addresses0B8_ Line | Count | Source | 447 | 6 | .map(|((_, a), _)| &a[..]), |
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE14peer_addresses0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE14peer_addresses0B8_ |
448 | 4 | ) |
449 | 7 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE14peer_addressesB6_ Line | Count | Source | 438 | 7 | pub fn peer_addresses(&'_ self, peer_id: &PeerId) -> impl Iterator<Item = &'_ [u8]> + '_ { | 439 | 7 | let Some(&peer_id_index4 ) = self.peer_ids_indices.get(peer_id) else { | 440 | | // If the `PeerId` is unknown, it means it doesn't have any address. | 441 | 3 | return either::Right(iter::empty()); | 442 | | }; | 443 | | | 444 | 4 | either::Left( | 445 | 4 | self.addresses | 446 | 4 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) | 447 | 4 | .map(|((_, a), _)| &a[..]), | 448 | 4 | ) | 449 | 7 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE14peer_addressesCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE14peer_addressesB6_ |
450 | | |
451 | | /// Chooses a [`PeerId`] that is known to belong to the given chain, that is not banned, and |
452 | | /// that doesn't have a slot assigned to it. |
453 | | /// |
454 | | /// A `TInstant` must be provided in order to determine whether past bans have expired. |
455 | | /// |
456 | | /// If multiple peers can be assigned a slot, the one returned is chosen randomly. Calling |
457 | | /// this function multiple times might return different peers. |
458 | | /// For this reason, this function requires `&mut self`. |
459 | | /// |
460 | | /// Note that this function might return a peer for which no address is present. While this is |
461 | | /// often not desirable, it is preferable to keep the API simple and straight-forward rather |
462 | | /// than try to be smart about function behaviours. |
463 | 147 | pub fn pick_assignable_peer( |
464 | 147 | &'_ mut self, |
465 | 147 | chain: &TChainId, |
466 | 147 | now: &TInstant, |
467 | 147 | ) -> AssignablePeer<'_, TInstant> { |
468 | 147 | let Some(&chain_index0 ) = self.chains_indices.get(chain) else { |
469 | 147 | return AssignablePeer::NoPeer; |
470 | | }; |
471 | | |
472 | 0 | if let Some((_, _, peer_id_index)) = self |
473 | 0 | .peers_chains_by_state |
474 | 0 | .range( |
475 | 0 | (chain_index, PeerChainState::Assignable, usize::MIN) |
476 | 0 | ..=( |
477 | 0 | chain_index, |
478 | 0 | PeerChainState::Banned { |
479 | 0 | expires: now.clone(), |
480 | 0 | }, |
481 | 0 | usize::MAX, |
482 | 0 | ), |
483 | 0 | ) |
484 | 0 | .choose(&mut self.randomness) |
485 | | { |
486 | 0 | return AssignablePeer::Assignable(&self.peer_ids[*peer_id_index]); |
487 | 0 | } |
488 | | |
489 | 0 | if let Some((_, state, _)) = self |
490 | 0 | .peers_chains_by_state |
491 | 0 | .range(( |
492 | 0 | ops::Bound::Excluded(( |
493 | 0 | chain_index, |
494 | 0 | PeerChainState::Banned { |
495 | 0 | expires: now.clone(), |
496 | 0 | }, |
497 | 0 | usize::MAX, |
498 | 0 | )), |
499 | 0 | ops::Bound::Excluded((chain_index, PeerChainState::Slot, usize::MIN)), |
500 | 0 | )) |
501 | 0 | .next() |
502 | | { |
503 | 0 | let PeerChainState::Banned { expires } = state else { |
504 | 0 | unreachable!() |
505 | | }; |
506 | 0 | AssignablePeer::AllPeersBanned { |
507 | 0 | next_unban: expires, |
508 | 0 | } |
509 | | } else { |
510 | 0 | AssignablePeer::NoPeer |
511 | | } |
512 | 147 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE20pick_assignable_peerB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20pick_assignable_peerCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE20pick_assignable_peerB6_ _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20pick_assignable_peerCsiUjFBJteJ7x_17smoldot_full_node Line | Count | Source | 463 | 147 | pub fn pick_assignable_peer( | 464 | 147 | &'_ mut self, | 465 | 147 | chain: &TChainId, | 466 | 147 | now: &TInstant, | 467 | 147 | ) -> AssignablePeer<'_, TInstant> { | 468 | 147 | let Some(&chain_index0 ) = self.chains_indices.get(chain) else { | 469 | 147 | return AssignablePeer::NoPeer; | 470 | | }; | 471 | | | 472 | 0 | if let Some((_, _, peer_id_index)) = self | 473 | 0 | .peers_chains_by_state | 474 | 0 | .range( | 475 | 0 | (chain_index, PeerChainState::Assignable, usize::MIN) | 476 | 0 | ..=( | 477 | 0 | chain_index, | 478 | 0 | PeerChainState::Banned { | 479 | 0 | expires: now.clone(), | 480 | 0 | }, | 481 | 0 | usize::MAX, | 482 | 0 | ), | 483 | 0 | ) | 484 | 0 | .choose(&mut self.randomness) | 485 | | { | 486 | 0 | return AssignablePeer::Assignable(&self.peer_ids[*peer_id_index]); | 487 | 0 | } | 488 | | | 489 | 0 | if let Some((_, state, _)) = self | 490 | 0 | .peers_chains_by_state | 491 | 0 | .range(( | 492 | 0 | ops::Bound::Excluded(( | 493 | 0 | chain_index, | 494 | 0 | PeerChainState::Banned { | 495 | 0 | expires: now.clone(), | 496 | 0 | }, | 497 | 0 | usize::MAX, | 498 | 0 | )), | 499 | 0 | ops::Bound::Excluded((chain_index, PeerChainState::Slot, usize::MIN)), | 500 | 0 | )) | 501 | 0 | .next() | 502 | | { | 503 | 0 | let PeerChainState::Banned { expires } = state else { | 504 | 0 | unreachable!() | 505 | | }; | 506 | 0 | AssignablePeer::AllPeersBanned { | 507 | 0 | next_unban: expires, | 508 | 0 | } | 509 | | } else { | 510 | 0 | AssignablePeer::NoPeer | 511 | | } | 512 | 147 | } |
|
513 | | |
514 | | /// Assigns a slot to the given peer on the given chain. |
515 | | /// |
516 | | /// Acts as an implicit call to [`BasicPeeringStrategy::insert_chain_peer`]. |
517 | | /// |
518 | | /// A slot is assigned even if the peer is banned. API users that call this function are |
519 | | /// expected to be aware of that. |
520 | 0 | pub fn assign_slot(&'_ mut self, chain: &TChainId, peer_id: &PeerId) { |
521 | 0 | let peer_id_index = self.get_or_insert_peer_index(peer_id); |
522 | 0 | let chain_index = self.get_or_insert_chain_index(chain); |
523 | 0 |
|
524 | 0 | match self.peers_chains.entry((peer_id_index, chain_index)) { |
525 | 0 | btree_map::Entry::Occupied(e) => { |
526 | 0 | let _was_removed = self.peers_chains_by_state.remove(&( |
527 | 0 | chain_index, |
528 | 0 | e.get().clone(), |
529 | 0 | peer_id_index, |
530 | 0 | )); |
531 | 0 | debug_assert!(_was_removed); |
532 | 0 | *e.into_mut() = PeerChainState::Slot; |
533 | | } |
534 | 0 | btree_map::Entry::Vacant(e) => { |
535 | 0 | e.insert(PeerChainState::Slot); |
536 | 0 | } |
537 | | } |
538 | | |
539 | 0 | let _was_inserted = |
540 | 0 | self.peers_chains_by_state |
541 | 0 | .insert((chain_index, PeerChainState::Slot, peer_id_index)); |
542 | 0 | debug_assert!(_was_inserted); |
543 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE11assign_slotB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE11assign_slotCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE11assign_slotB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE11assign_slotCsiUjFBJteJ7x_17smoldot_full_node |
544 | | |
545 | | /// Unassign the slot that has been assigned to the given peer and bans the peer, preventing |
546 | | /// it from being assigned a slot on this chain for a certain amount of time. |
547 | | /// |
548 | | /// Has no effect if the peer isn't assigned to the given chain. |
549 | | /// |
550 | | /// If the peer was already banned, the new ban expiration is `max(existing_ban, when_unban)`. |
551 | | /// |
552 | | /// Returns what this function did. |
553 | 0 | pub fn unassign_slot_and_ban( |
554 | 0 | &mut self, |
555 | 0 | chain: &TChainId, |
556 | 0 | peer_id: &PeerId, |
557 | 0 | when_unban: TInstant, |
558 | 0 | ) -> UnassignSlotAndBan<TInstant> { |
559 | 0 | let (Some(&peer_id_index), Some(&chain_index)) = ( |
560 | 0 | self.peer_ids_indices.get(peer_id), |
561 | 0 | self.chains_indices.get(chain), |
562 | | ) else { |
563 | 0 | return UnassignSlotAndBan::NotAssigned; |
564 | | }; |
565 | | |
566 | 0 | if let Some(state) = self.peers_chains.get_mut(&(peer_id_index, chain_index)) { |
567 | 0 | let return_value = match state { |
568 | 0 | PeerChainState::Banned { expires } if *expires >= when_unban => { |
569 | 0 | // Ban is already long enough. Nothing to do. |
570 | 0 | return UnassignSlotAndBan::AlreadyBanned { |
571 | 0 | when_unban: expires.clone(), |
572 | 0 | ban_extended: false, |
573 | 0 | }; |
574 | | } |
575 | 0 | PeerChainState::Banned { .. } => UnassignSlotAndBan::AlreadyBanned { |
576 | 0 | when_unban: when_unban.clone(), |
577 | 0 | ban_extended: true, |
578 | 0 | }, |
579 | 0 | PeerChainState::Assignable => UnassignSlotAndBan::Banned { had_slot: false }, |
580 | 0 | PeerChainState::Slot => UnassignSlotAndBan::Banned { had_slot: true }, |
581 | | }; |
582 | | |
583 | 0 | let _was_in = |
584 | 0 | self.peers_chains_by_state |
585 | 0 | .remove(&(chain_index, state.clone(), peer_id_index)); |
586 | 0 | debug_assert!(_was_in); |
587 | | |
588 | 0 | *state = PeerChainState::Banned { |
589 | 0 | expires: when_unban, |
590 | 0 | }; |
591 | 0 |
|
592 | 0 | let _was_inserted = |
593 | 0 | self.peers_chains_by_state |
594 | 0 | .insert((chain_index, state.clone(), peer_id_index)); |
595 | 0 | debug_assert!(_was_inserted); |
596 | | |
597 | 0 | return_value |
598 | | } else { |
599 | 0 | UnassignSlotAndBan::NotAssigned |
600 | | } |
601 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE21unassign_slot_and_banB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE21unassign_slot_and_banCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE21unassign_slot_and_banB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE21unassign_slot_and_banCsiUjFBJteJ7x_17smoldot_full_node |
602 | | |
603 | | /// Unassigns all the slots that have been assigned to the given peer and bans the peer, |
604 | | /// preventing it from being assigned a slot for all of the chains it had a slot on for a |
605 | | /// certain amount of time. |
606 | | /// |
607 | | /// Has no effect on chains the peer isn't assigned to. |
608 | | /// |
609 | | /// If the peer was already banned, the new ban expiration is `max(existing_ban, when_unban)`. |
610 | | /// |
611 | | /// Returns an iterator to the list of chains where the peer is now banned, and the details |
612 | | /// of what has happened. |
613 | | /// |
614 | | /// > **Note**: This function is a shortcut for calling |
615 | | /// > [`BasicPeeringStrategy::unassign_slot_and_ban`] for all existing chains. |
616 | 0 | pub fn unassign_slots_and_ban( |
617 | 0 | &mut self, |
618 | 0 | peer_id: &PeerId, |
619 | 0 | when_unban: TInstant, |
620 | 0 | ) -> UnassignSlotsAndBanIter<TChainId, TInstant> { |
621 | 0 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { |
622 | 0 | return UnassignSlotsAndBanIter { |
623 | 0 | chains: &self.chains, |
624 | 0 | peers_chains_by_state: &mut self.peers_chains_by_state, |
625 | 0 | inner_iter: None, |
626 | 0 | peer_id_index: 0, |
627 | 0 | when_unban, |
628 | 0 | }; |
629 | | }; |
630 | | |
631 | 0 | UnassignSlotsAndBanIter { |
632 | 0 | chains: &self.chains, |
633 | 0 | peers_chains_by_state: &mut self.peers_chains_by_state, |
634 | 0 | inner_iter: Some( |
635 | 0 | self.peers_chains |
636 | 0 | .range_mut((peer_id_index, usize::MIN)..=(peer_id_index, usize::MAX)) |
637 | 0 | .fuse(), |
638 | 0 | ), |
639 | 0 | peer_id_index, |
640 | 0 | when_unban, |
641 | 0 | } |
642 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE22unassign_slots_and_banB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE22unassign_slots_and_banCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE22unassign_slots_and_banB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE22unassign_slots_and_banCsiUjFBJteJ7x_17smoldot_full_node |
643 | | |
644 | | /// Picks an address from the list with zero connections, and sets the number of connections |
645 | | /// to one. Returns `None` if no such address is available. |
646 | 0 | pub fn pick_address_and_add_connection(&mut self, peer_id: &PeerId) -> Option<&[u8]> { |
647 | 0 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { |
648 | | // If the `PeerId` is unknown, it means it doesn't have any address. |
649 | 0 | return None; |
650 | | }; |
651 | | |
652 | | // TODO: could be optimized further by removing filter() and adjusting the set |
653 | 0 | if let Some(((_, address), num_connections)) = self |
654 | 0 | .addresses |
655 | 0 | .range_mut((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) |
656 | 0 | .filter(|(_, num_connections)| **num_connections == 0) Unexecuted instantiation: _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE31pick_address_and_add_connection0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE31pick_address_and_add_connection0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE31pick_address_and_add_connection0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE31pick_address_and_add_connection0CsiUjFBJteJ7x_17smoldot_full_node |
657 | 0 | .choose(&mut self.randomness) |
658 | | { |
659 | 0 | *num_connections = 1; |
660 | 0 | return Some(address); |
661 | 0 | } |
662 | 0 |
|
663 | 0 | None |
664 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE31pick_address_and_add_connectionB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE31pick_address_and_add_connectionCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE31pick_address_and_add_connectionB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE31pick_address_and_add_connectionCsiUjFBJteJ7x_17smoldot_full_node |
665 | | |
666 | | /// Removes one connection from the given address. |
667 | | /// |
668 | | /// Returns an error if the address isn't known to the data structure, or if there was no |
669 | | /// connection. |
670 | 1 | pub fn decrease_address_connections( |
671 | 1 | &mut self, |
672 | 1 | peer_id: &PeerId, |
673 | 1 | address: &[u8], |
674 | 1 | ) -> Result<(), DecreaseAddressConnectionsError> { |
675 | 1 | self.decrease_address_connections_inner(peer_id, address, false) |
676 | 1 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE28decrease_address_connectionsB6_ Line | Count | Source | 670 | 1 | pub fn decrease_address_connections( | 671 | 1 | &mut self, | 672 | 1 | peer_id: &PeerId, | 673 | 1 | address: &[u8], | 674 | 1 | ) -> Result<(), DecreaseAddressConnectionsError> { | 675 | 1 | self.decrease_address_connections_inner(peer_id, address, false) | 676 | 1 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE28decrease_address_connectionsCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE28decrease_address_connectionsB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE28decrease_address_connectionsCsiUjFBJteJ7x_17smoldot_full_node |
677 | | |
678 | | /// Removes one connection from the given address. If this decreases the number of connections |
679 | | /// from one to zero, the address is removed entirely. |
680 | | /// |
681 | | /// Returns an error if the address isn't known to the data structure, or if there was no |
682 | | /// connection. |
683 | 0 | pub fn decrease_address_connections_and_remove_if_zero( |
684 | 0 | &mut self, |
685 | 0 | peer_id: &PeerId, |
686 | 0 | address: &[u8], |
687 | 0 | ) -> Result<(), DecreaseAddressConnectionsError> { |
688 | 0 | self.decrease_address_connections_inner(peer_id, address, true) |
689 | 0 | } Unexecuted instantiation: _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE47decrease_address_connections_and_remove_if_zeroB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE47decrease_address_connections_and_remove_if_zeroCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE47decrease_address_connections_and_remove_if_zeroB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE47decrease_address_connections_and_remove_if_zeroCsiUjFBJteJ7x_17smoldot_full_node |
690 | | |
691 | 1 | fn decrease_address_connections_inner( |
692 | 1 | &mut self, |
693 | 1 | peer_id: &PeerId, |
694 | 1 | address: &[u8], |
695 | 1 | remove_if_reaches_zero: bool, |
696 | 1 | ) -> Result<(), DecreaseAddressConnectionsError> { |
697 | 1 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { |
698 | | // If the `PeerId` is unknown, it means it doesn't have any address. |
699 | 0 | return Err(DecreaseAddressConnectionsError::UnknownAddress); |
700 | | }; |
701 | | |
702 | 1 | let Some(num_connections) = self.addresses.get_mut(&(peer_id_index, address.to_owned())) |
703 | | else { |
704 | 0 | return Err(DecreaseAddressConnectionsError::UnknownAddress); |
705 | | }; |
706 | | |
707 | 1 | if *num_connections == 0 { |
708 | 0 | return Err(DecreaseAddressConnectionsError::NotConnected); |
709 | 1 | } |
710 | 1 | |
711 | 1 | *num_connections -= 1; |
712 | 1 | |
713 | 1 | if *num_connections != 0 { |
714 | 0 | return Ok(()); |
715 | 1 | } |
716 | 1 | |
717 | 1 | if remove_if_reaches_zero { |
718 | 0 | self.addresses.remove(&(peer_id_index, address.to_owned())); |
719 | 1 | } |
720 | | |
721 | 1 | self.try_clean_up_peer_id(peer_id_index); |
722 | 1 | Ok(()) |
723 | 1 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE34decrease_address_connections_innerB6_ Line | Count | Source | 691 | 1 | fn decrease_address_connections_inner( | 692 | 1 | &mut self, | 693 | 1 | peer_id: &PeerId, | 694 | 1 | address: &[u8], | 695 | 1 | remove_if_reaches_zero: bool, | 696 | 1 | ) -> Result<(), DecreaseAddressConnectionsError> { | 697 | 1 | let Some(&peer_id_index) = self.peer_ids_indices.get(peer_id) else { | 698 | | // If the `PeerId` is unknown, it means it doesn't have any address. | 699 | 0 | return Err(DecreaseAddressConnectionsError::UnknownAddress); | 700 | | }; | 701 | | | 702 | 1 | let Some(num_connections) = self.addresses.get_mut(&(peer_id_index, address.to_owned())) | 703 | | else { | 704 | 0 | return Err(DecreaseAddressConnectionsError::UnknownAddress); | 705 | | }; | 706 | | | 707 | 1 | if *num_connections == 0 { | 708 | 0 | return Err(DecreaseAddressConnectionsError::NotConnected); | 709 | 1 | } | 710 | 1 | | 711 | 1 | *num_connections -= 1; | 712 | 1 | | 713 | 1 | if *num_connections != 0 { | 714 | 0 | return Ok(()); | 715 | 1 | } | 716 | 1 | | 717 | 1 | if remove_if_reaches_zero { | 718 | 0 | self.addresses.remove(&(peer_id_index, address.to_owned())); | 719 | 1 | } | 720 | | | 721 | 1 | self.try_clean_up_peer_id(peer_id_index); | 722 | 1 | Ok(()) | 723 | 1 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE34decrease_address_connections_innerCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE34decrease_address_connections_innerB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE34decrease_address_connections_innerCsiUjFBJteJ7x_17smoldot_full_node |
724 | | |
725 | | /// Finds the index of the given `TChainId` in [`BasicPeeringStrategy::chains`], or inserts |
726 | | /// one if there is none. |
727 | 2 | fn get_or_insert_chain_index(&mut self, chain: &TChainId) -> usize { |
728 | 2 | debug_assert_eq!(self.chains.len(), self.chains_indices.len()); |
729 | | |
730 | 2 | match self.chains_indices.raw_entry_mut().from_key(chain) { |
731 | 0 | hashbrown::hash_map::RawEntryMut::Occupied(occupied_entry) => *occupied_entry.get(), |
732 | 2 | hashbrown::hash_map::RawEntryMut::Vacant(vacant_entry) => { |
733 | 2 | let idx = self.chains.insert(chain.clone()); |
734 | 2 | vacant_entry.insert(chain.clone(), idx); |
735 | 2 | idx |
736 | | } |
737 | | } |
738 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE25get_or_insert_chain_indexB6_ Line | Count | Source | 727 | 2 | fn get_or_insert_chain_index(&mut self, chain: &TChainId) -> usize { | 728 | 2 | debug_assert_eq!(self.chains.len(), self.chains_indices.len()); | 729 | | | 730 | 2 | match self.chains_indices.raw_entry_mut().from_key(chain) { | 731 | 0 | hashbrown::hash_map::RawEntryMut::Occupied(occupied_entry) => *occupied_entry.get(), | 732 | 2 | hashbrown::hash_map::RawEntryMut::Vacant(vacant_entry) => { | 733 | 2 | let idx = self.chains.insert(chain.clone()); | 734 | 2 | vacant_entry.insert(chain.clone(), idx); | 735 | 2 | idx | 736 | | } | 737 | | } | 738 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE25get_or_insert_chain_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE25get_or_insert_chain_indexB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE25get_or_insert_chain_indexCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE25get_or_insert_chain_indexCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE25get_or_insert_chain_indexCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE25get_or_insert_chain_indexCsibGXYHQB8Ea_25json_rpc_general_requests |
739 | | |
740 | | /// Check if the given `TChainId` is still used within the collection. If no, removes it from |
741 | | /// [`BasicPeeringStrategy::chains`]. |
742 | 2 | fn try_clean_up_chain(&mut self, chain_index: usize) { |
743 | 2 | if self |
744 | 2 | .peers_chains_by_state |
745 | 2 | .range( |
746 | 2 | (chain_index, PeerChainState::Assignable, usize::MIN) |
747 | 2 | ..=(chain_index, PeerChainState::Slot, usize::MAX), |
748 | 2 | ) |
749 | 2 | .next() |
750 | 2 | .is_some() |
751 | | { |
752 | 0 | return; |
753 | 2 | } |
754 | 2 | |
755 | 2 | // Chain is unused. We can remove it. |
756 | 2 | let chain_id = self.chains.remove(chain_index); |
757 | 2 | let _was_in = self.chains_indices.remove(&chain_id); |
758 | 2 | debug_assert_eq!(_was_in, Some(chain_index)); |
759 | 2 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE18try_clean_up_chainB6_ Line | Count | Source | 742 | 2 | fn try_clean_up_chain(&mut self, chain_index: usize) { | 743 | 2 | if self | 744 | 2 | .peers_chains_by_state | 745 | 2 | .range( | 746 | 2 | (chain_index, PeerChainState::Assignable, usize::MIN) | 747 | 2 | ..=(chain_index, PeerChainState::Slot, usize::MAX), | 748 | 2 | ) | 749 | 2 | .next() | 750 | 2 | .is_some() | 751 | | { | 752 | 0 | return; | 753 | 2 | } | 754 | 2 | | 755 | 2 | // Chain is unused. We can remove it. | 756 | 2 | let chain_id = self.chains.remove(chain_index); | 757 | 2 | let _was_in = self.chains_indices.remove(&chain_id); | 758 | 2 | debug_assert_eq!(_was_in, Some(chain_index)); | 759 | 2 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE18try_clean_up_chainCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE18try_clean_up_chainB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE18try_clean_up_chainCsiUjFBJteJ7x_17smoldot_full_node |
760 | | |
761 | | /// Finds the index of the given [`PeerId`] in [`BasicPeeringStrategy::peer_ids`], or inserts |
762 | | /// one if there is none. |
763 | 4 | fn get_or_insert_peer_index(&mut self, peer_id: &PeerId) -> usize { |
764 | 4 | debug_assert_eq!(self.peer_ids.len(), self.peer_ids_indices.len()); |
765 | | |
766 | 4 | match self.peer_ids_indices.raw_entry_mut().from_key(peer_id) { |
767 | 1 | hashbrown::hash_map::RawEntryMut::Occupied(occupied_entry) => *occupied_entry.get(), |
768 | 3 | hashbrown::hash_map::RawEntryMut::Vacant(vacant_entry) => { |
769 | 3 | let idx = self.peer_ids.insert(peer_id.clone()); |
770 | 3 | vacant_entry.insert(peer_id.clone(), idx); |
771 | 3 | idx |
772 | | } |
773 | | } |
774 | 4 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE24get_or_insert_peer_indexB6_ Line | Count | Source | 763 | 4 | fn get_or_insert_peer_index(&mut self, peer_id: &PeerId) -> usize { | 764 | 4 | debug_assert_eq!(self.peer_ids.len(), self.peer_ids_indices.len()); | 765 | | | 766 | 4 | match self.peer_ids_indices.raw_entry_mut().from_key(peer_id) { | 767 | 1 | hashbrown::hash_map::RawEntryMut::Occupied(occupied_entry) => *occupied_entry.get(), | 768 | 3 | hashbrown::hash_map::RawEntryMut::Vacant(vacant_entry) => { | 769 | 3 | let idx = self.peer_ids.insert(peer_id.clone()); | 770 | 3 | vacant_entry.insert(peer_id.clone(), idx); | 771 | 3 | idx | 772 | | } | 773 | | } | 774 | 4 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE24get_or_insert_peer_indexCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE24get_or_insert_peer_indexB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE24get_or_insert_peer_indexCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE24get_or_insert_peer_indexCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE24get_or_insert_peer_indexCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE24get_or_insert_peer_indexCsibGXYHQB8Ea_25json_rpc_general_requests |
775 | | |
776 | | /// Check if the given [`PeerId`] is still used within the collection. If no, removes it from |
777 | | /// [`BasicPeeringStrategy::peer_ids`]. |
778 | 3 | fn try_clean_up_peer_id(&mut self, peer_id_index: usize) { |
779 | 3 | if self |
780 | 3 | .peers_chains |
781 | 3 | .range((peer_id_index, usize::MIN)..=(peer_id_index, usize::MAX)) |
782 | 3 | .next() |
783 | 3 | .is_some() |
784 | | { |
785 | 0 | return; |
786 | 3 | } |
787 | 3 | |
788 | 3 | if self |
789 | 3 | .addresses |
790 | 3 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) |
791 | 4 | .any(|(_, num_connections)| *num_connections >= 1)3 _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_id0B8_ Line | Count | Source | 791 | 4 | .any(|(_, num_connections)| *num_connections >= 1) |
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_id0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE20try_clean_up_peer_id0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_id0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_id0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_id0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_id0CsibGXYHQB8Ea_25json_rpc_general_requests |
792 | | { |
793 | 1 | return; |
794 | 2 | } |
795 | 2 | |
796 | 2 | // PeerId is unused. We can remove it. |
797 | 2 | let peer_id = self.peer_ids.remove(peer_id_index); |
798 | 2 | let _was_in = self.peer_ids_indices.remove(&peer_id); |
799 | 2 | debug_assert_eq!(_was_in, Some(peer_id_index)); |
800 | 3 | for address in self |
801 | 2 | .addresses |
802 | 2 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) |
803 | 3 | .map(|((_, a), _)| a.clone()) _RNCNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_ids_0B8_ Line | Count | Source | 803 | 3 | .map(|((_, a), _)| a.clone()) |
Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_ids_0CsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyppE20try_clean_up_peer_ids_0B8_ Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_ids_0CsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_ids_0CsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_ids_0CscDgN54JpMGG_6author Unexecuted instantiation: _RNCNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_20BasicPeeringStrategyNtNtB6_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_ids_0CsibGXYHQB8Ea_25json_rpc_general_requests |
804 | 2 | .collect::<Vec<_>>() |
805 | | { |
806 | 3 | let _was_removed = self.addresses.remove(&(peer_id_index, address)); |
807 | 3 | debug_assert!(_was_removed.is_some()); |
808 | | } |
809 | 3 | } _RNvMNtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategymNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_idB6_ Line | Count | Source | 778 | 3 | fn try_clean_up_peer_id(&mut self, peer_id_index: usize) { | 779 | 3 | if self | 780 | 3 | .peers_chains | 781 | 3 | .range((peer_id_index, usize::MIN)..=(peer_id_index, usize::MAX)) | 782 | 3 | .next() | 783 | 3 | .is_some() | 784 | | { | 785 | 0 | return; | 786 | 3 | } | 787 | 3 | | 788 | 3 | if self | 789 | 3 | .addresses | 790 | 3 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) | 791 | 3 | .any(|(_, num_connections)| *num_connections >= 1) | 792 | | { | 793 | 1 | return; | 794 | 2 | } | 795 | 2 | | 796 | 2 | // PeerId is unused. We can remove it. | 797 | 2 | let peer_id = self.peer_ids.remove(peer_id_index); | 798 | 2 | let _was_in = self.peer_ids_indices.remove(&peer_id); | 799 | 2 | debug_assert_eq!(_was_in, Some(peer_id_index)); | 800 | 3 | for address in self | 801 | 2 | .addresses | 802 | 2 | .range((peer_id_index, Vec::new())..(peer_id_index + 1, Vec::new())) | 803 | 2 | .map(|((_, a), _)| a.clone()) | 804 | 2 | .collect::<Vec<_>>() | 805 | | { | 806 | 3 | let _was_removed = self.addresses.remove(&(peer_id_index, address)); | 807 | 3 | debug_assert!(_was_removed.is_some()); | 808 | | } | 809 | 3 | } |
Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationE20try_clean_up_peer_idCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyppE20try_clean_up_peer_idB6_ Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_idCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_idCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_idCscDgN54JpMGG_6author Unexecuted instantiation: _RNvMNtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB2_20BasicPeeringStrategyNtNtB4_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantE20try_clean_up_peer_idCsibGXYHQB8Ea_25json_rpc_general_requests |
810 | | } |
811 | | |
812 | | /// See [`BasicPeeringStrategy::decrease_address_connections`]. |
813 | 0 | #[derive(Debug, derive_more::Display)] Unexecuted instantiation: _RNvXsc_NtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyNtB5_31DecreaseAddressConnectionsErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXsc_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyNtB5_31DecreaseAddressConnectionsErrorNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
814 | | pub enum DecreaseAddressConnectionsError { |
815 | | /// Address isn't known to the collection. |
816 | | UnknownAddress, |
817 | | /// The address didn't have any connection. |
818 | | NotConnected, |
819 | | } |
820 | | |
821 | | /// See [`BasicPeeringStrategy::pick_assignable_peer`]. |
822 | | pub enum AssignablePeer<'a, TInstant> { |
823 | | /// An assignal peer was found. Note that the peer wasn't assigned yet. |
824 | | Assignable(&'a PeerId), |
825 | | /// No peer was found as all known un-assigned peers are currently in the "banned" state. |
826 | | AllPeersBanned { |
827 | | /// Instant when the first peer will be unbanned. |
828 | | next_unban: &'a TInstant, |
829 | | }, |
830 | | /// No un-assigned peer was found. |
831 | | NoPeer, |
832 | | } |
833 | | |
834 | | /// See [`BasicPeeringStrategy::insert_chain_peer`]. |
835 | | pub enum InsertChainPeerResult { |
836 | | /// Peer-chain association has been successfully inserted. |
837 | | Inserted { |
838 | | /// If the maximum number of peers is reached, an old peer might have been removed. If so, |
839 | | /// this contains the peer. |
840 | | peer_removed: Option<PeerId>, |
841 | | }, |
842 | | /// Peer-chain association was already inserted. |
843 | | Duplicate, |
844 | | } |
845 | | |
846 | | /// See [`BasicPeeringStrategy::insert_address`]. |
847 | | pub enum InsertAddressResult { |
848 | | /// Address has been successfully inserted. |
849 | | Inserted { |
850 | | /// If the maximum number of addresses is reached, an old address might have been |
851 | | /// removed. If so, this contains the address. |
852 | | address_removed: Option<Vec<u8>>, |
853 | | }, |
854 | | /// Address was already known. |
855 | | AlreadyKnown, |
856 | | /// The peer isn't associated to any chain, and as such the address was not inserted. |
857 | | UnknownPeer, |
858 | | } |
859 | | |
860 | | /// See [`BasicPeeringStrategy::increase_address_connections`]. |
861 | | pub enum InsertAddressConnectionsResult { |
862 | | /// Address has been inserted. |
863 | | Inserted { |
864 | | /// If the maximum number of addresses is reached, an old address might have been |
865 | | /// removed. If so, this contains the address. |
866 | | address_removed: Option<Vec<u8>>, |
867 | | }, |
868 | | /// Address was already known. |
869 | | AlreadyKnown, |
870 | | } |
871 | | |
872 | | /// See [`BasicPeeringStrategy::unassign_slot_and_ban`]. |
873 | | pub enum UnassignSlotAndBan<TInstant> { |
874 | | /// Peer wasn't assigned to the given chain. |
875 | | NotAssigned, |
876 | | /// Peer was already banned. |
877 | | AlreadyBanned { |
878 | | /// When the peer is unbanned. |
879 | | when_unban: TInstant, |
880 | | /// `true` if the ban has been extended, in other words if the value of `when_unban` was |
881 | | /// superior to the existing ban. |
882 | | ban_extended: bool, |
883 | | }, |
884 | | /// Peer wasn't banned and is now banned. |
885 | | Banned { |
886 | | /// `true` if the peer had a slot on the chain. |
887 | | had_slot: bool, |
888 | | }, |
889 | | } |
890 | | |
891 | | impl<TInstant> UnassignSlotAndBan<TInstant> { |
892 | | /// Returns `true` for [`UnassignSlotAndBan::Banned`] where `had_slot` is `true`. |
893 | 0 | pub fn had_slot(&self) -> bool { |
894 | 0 | matches!(self, UnassignSlotAndBan::Banned { had_slot: true }) |
895 | 0 | } Unexecuted instantiation: _RNvMs_NtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategyINtB4_18UnassignSlotAndBanpE8had_slotB8_ Unexecuted instantiation: _RNvMs_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB4_18UnassignSlotAndBanpE8had_slotB8_ |
896 | | } |
897 | | |
898 | | /// See [`BasicPeeringStrategy::unassign_slot_and_remove_chain_peer`]. |
899 | | pub enum UnassignSlotAndRemoveChainPeer<TInstant> { |
900 | | /// Peer wasn't assigned to the given chain. |
901 | | NotAssigned, |
902 | | /// Peer was assigned to the given chain but didn't have a slot or was banned. |
903 | | Assigned { |
904 | | /// `Some` if the peer was banned. Contains the ban expiration. |
905 | | ban_expiration: Option<TInstant>, |
906 | | }, |
907 | | /// Peer was assigned to the given chain and had a slot. |
908 | | HadSlot, |
909 | | } |
910 | | |
911 | | /// See [`BasicPeeringStrategy::unassign_slots_and_ban`]. |
912 | | pub struct UnassignSlotsAndBanIter<'a, TChainId, TInstant> |
913 | | where |
914 | | TInstant: PartialOrd + Ord + Eq + Clone, |
915 | | { |
916 | | /// Same field as in [`BasicPeeringStrategy`]. |
917 | | chains: &'a slab::Slab<TChainId>, |
918 | | /// Same field as in [`BasicPeeringStrategy`]. |
919 | | peers_chains_by_state: &'a mut BTreeSet<(usize, PeerChainState<TInstant>, usize)>, |
920 | | /// Iterator within [`BasicPeeringStrategy::peers_chains`]. |
921 | | inner_iter: |
922 | | Option<iter::Fuse<btree_map::RangeMut<'a, (usize, usize), PeerChainState<TInstant>>>>, |
923 | | /// Parameter passed to [`BasicPeeringStrategy::unassign_slots_and_ban`]. Dummy value when |
924 | | /// [`UnassignSlotsAndBanIter::inner_iter`] is `None`. |
925 | | peer_id_index: usize, |
926 | | /// Parameter passed to [`BasicPeeringStrategy::unassign_slots_and_ban`]. |
927 | | when_unban: TInstant, |
928 | | } |
929 | | |
930 | | /// See [`BasicPeeringStrategy::unassign_slots_and_ban`]. |
931 | | pub enum UnassignSlotsAndBan<TInstant> { |
932 | | /// Peer was already banned. |
933 | | AlreadyBanned { |
934 | | /// When the peer is unbanned. |
935 | | when_unban: TInstant, |
936 | | /// `true` if the ban has been extended, in other words if the value of `when_unban` was |
937 | | /// superior to the existing ban. |
938 | | ban_extended: bool, |
939 | | }, |
940 | | /// Peer wasn't banned and is now banned. |
941 | | Banned { |
942 | | /// `true` if the peer had a slot on the chain. |
943 | | had_slot: bool, |
944 | | }, |
945 | | } |
946 | | |
947 | | impl<'a, TChainId, TInstant> Iterator for UnassignSlotsAndBanIter<'a, TChainId, TInstant> |
948 | | where |
949 | | TInstant: PartialOrd + Ord + Eq + Clone, |
950 | | { |
951 | | type Item = (&'a TChainId, UnassignSlotsAndBan<TInstant>); |
952 | | |
953 | 0 | fn next(&mut self) -> Option<Self::Item> { |
954 | 0 | let Some(inner_iter) = self.inner_iter.as_mut() else { |
955 | 0 | return None; |
956 | | }; |
957 | | |
958 | | loop { |
959 | 0 | let Some((&(_, chain_index), state)) = inner_iter.next() else { |
960 | 0 | return None; |
961 | | }; |
962 | | |
963 | 0 | let return_value = match state { |
964 | 0 | PeerChainState::Banned { expires } if *expires >= self.when_unban => { |
965 | 0 | // Ban is already long enough. Nothing to do. |
966 | 0 | return Some(( |
967 | 0 | &self.chains[chain_index], |
968 | 0 | UnassignSlotsAndBan::AlreadyBanned { |
969 | 0 | when_unban: expires.clone(), |
970 | 0 | ban_extended: false, |
971 | 0 | }, |
972 | 0 | )); |
973 | | } |
974 | 0 | PeerChainState::Banned { .. } => UnassignSlotsAndBan::AlreadyBanned { |
975 | 0 | when_unban: self.when_unban.clone(), |
976 | 0 | ban_extended: true, |
977 | 0 | }, |
978 | 0 | PeerChainState::Assignable => UnassignSlotsAndBan::Banned { had_slot: false }, |
979 | 0 | PeerChainState::Slot => UnassignSlotsAndBan::Banned { had_slot: true }, |
980 | | }; |
981 | | |
982 | 0 | let _was_in = self.peers_chains_by_state.remove(&( |
983 | 0 | chain_index, |
984 | 0 | state.clone(), |
985 | 0 | self.peer_id_index, |
986 | 0 | )); |
987 | 0 | debug_assert!(_was_in); |
988 | | |
989 | 0 | *state = PeerChainState::Banned { |
990 | 0 | expires: self.when_unban.clone(), |
991 | 0 | }; |
992 | 0 |
|
993 | 0 | let _was_inserted = |
994 | 0 | self.peers_chains_by_state |
995 | 0 | .insert((chain_index, state.clone(), self.peer_id_index)); |
996 | 0 | debug_assert!(_was_inserted); |
997 | | |
998 | 0 | break Some((&self.chains[chain_index], return_value)); |
999 | | } |
1000 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategys0_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator4nextB9_ Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB5_23UnassignSlotsAndBanIterNtNtB7_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationENtNtNtNtB1X_4iter6traits8iterator8Iterator4nextCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategys0_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator4nextB9_ Unexecuted instantiation: _RNvXs0_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB5_23UnassignSlotsAndBanIterNtNtB7_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator4nextCsiUjFBJteJ7x_17smoldot_full_node |
1001 | | |
1002 | 0 | fn size_hint(&self) -> (usize, Option<usize>) { |
1003 | 0 | self.inner_iter |
1004 | 0 | .as_ref() |
1005 | 0 | .map_or((0, Some(0)), |inner| inner.size_hint()) Unexecuted instantiation: _RNCNvXININtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategys0_0ppEINtB7_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator9size_hint0Bb_ Unexecuted instantiation: _RNCNvXININtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategys0_0ppEINtB7_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator9size_hint0Bb_ |
1006 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategys0_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator9size_hintB9_ Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategys0_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtNtCsaYZPK01V26L_4core4iter6traits8iterator8Iterator9size_hintB9_ |
1007 | | } |
1008 | | |
1009 | | impl<'a, TChainId, TInstant> iter::FusedIterator for UnassignSlotsAndBanIter<'a, TChainId, TInstant> where |
1010 | | TInstant: PartialOrd + Ord + Eq + Clone |
1011 | | { |
1012 | | } |
1013 | | |
1014 | | impl<'a, TChainId, TInstant> Drop for UnassignSlotsAndBanIter<'a, TChainId, TInstant> |
1015 | | where |
1016 | | TInstant: PartialOrd + Ord + Eq + Clone, |
1017 | | { |
1018 | 0 | fn drop(&mut self) { |
1019 | | // Note that this is safe because `UnassignSlotsAndBanIter` is a `FusedIterator`. |
1020 | 0 | while let Some(_) = self.next() {} |
1021 | 0 | } Unexecuted instantiation: _RNvXININtNtCsN16ciHI6Qf_7smoldot7network22basic_peering_strategys2_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4dropB9_ Unexecuted instantiation: _RNvXs2_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB5_23UnassignSlotsAndBanIterNtNtB7_7service7ChainIdNtNtCsaYZPK01V26L_4core4time8DurationENtNtNtB1X_3ops4drop4Drop4dropCsDDUKWWCHAU_18smoldot_light_wasm Unexecuted instantiation: _RNvXININtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategys2_0ppEINtB5_23UnassignSlotsAndBanIterppENtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4dropB9_ Unexecuted instantiation: _RNvXs2_NtNtCseuYC0Zibziv_7smoldot7network22basic_peering_strategyINtB5_23UnassignSlotsAndBanIterNtNtB7_7service7ChainIdNtNtCsbpXXxgr6u8g_3std4time7InstantENtNtNtCsaYZPK01V26L_4core3ops4drop4Drop4dropCsiUjFBJteJ7x_17smoldot_full_node |
1022 | | } |
1023 | | |
1024 | | #[cfg(test)] |
1025 | | mod tests { |
1026 | | use super::{ |
1027 | | BasicPeeringStrategy, Config, InsertAddressConnectionsResult, InsertAddressResult, |
1028 | | InsertChainPeerResult, |
1029 | | }; |
1030 | | use crate::network::service::{peer_id::PublicKey, PeerId}; |
1031 | | use core::time::Duration; |
1032 | | |
1033 | | #[test] |
1034 | 1 | fn peer_state_ordering() { |
1035 | 1 | // The implementation above relies on the properties tested here. |
1036 | 1 | use super::PeerChainState; |
1037 | 1 | assert!(PeerChainState::Assignable < PeerChainState::Banned { expires: 0 }); |
1038 | 1 | assert!(PeerChainState::Banned { expires: 5 } < PeerChainState::Banned { expires: 7 }); |
1039 | 1 | assert!(PeerChainState::Banned { expires: u32::MAX } < PeerChainState::Slot); |
1040 | 1 | } |
1041 | | |
1042 | | #[test] |
1043 | 1 | fn addresses_removed_when_peer_has_no_chain_association() { |
1044 | 1 | let mut bps = BasicPeeringStrategy::<u32, Duration>::new(Config { |
1045 | 1 | randomness_seed: [0; 32], |
1046 | 1 | peers_capacity: 0, |
1047 | 1 | chains_capacity: 0, |
1048 | 1 | }); |
1049 | 1 | |
1050 | 1 | let peer_id = PeerId::from_public_key(&PublicKey::Ed25519([0; 32])); |
1051 | 1 | |
1052 | 1 | assert!(matches!0 ( |
1053 | 1 | bps.insert_chain_peer(0, peer_id.clone(), usize::MAX), |
1054 | | InsertChainPeerResult::Inserted { peer_removed: None } |
1055 | | )); |
1056 | | |
1057 | 1 | assert!(matches!0 ( |
1058 | 1 | bps.insert_address(&peer_id, Vec::new(), usize::MAX), |
1059 | | InsertAddressResult::Inserted { |
1060 | | address_removed: None |
1061 | | } |
1062 | | )); |
1063 | | |
1064 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 1); |
1065 | 1 | bps.unassign_slot_and_remove_chain_peer(&0, &peer_id); |
1066 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 0); |
1067 | 1 | } |
1068 | | |
1069 | | #[test] |
1070 | 1 | fn addresses_not_removed_if_connected_when_peer_has_no_chain_association() { |
1071 | 1 | let mut bps = BasicPeeringStrategy::<u32, Duration>::new(Config { |
1072 | 1 | randomness_seed: [0; 32], |
1073 | 1 | peers_capacity: 0, |
1074 | 1 | chains_capacity: 0, |
1075 | 1 | }); |
1076 | 1 | |
1077 | 1 | let peer_id = PeerId::from_public_key(&PublicKey::Ed25519([0; 32])); |
1078 | 1 | |
1079 | 1 | assert!(matches!0 ( |
1080 | 1 | bps.insert_chain_peer(0, peer_id.clone(), usize::MAX), |
1081 | | InsertChainPeerResult::Inserted { peer_removed: None } |
1082 | | )); |
1083 | | |
1084 | 1 | assert!(matches!0 ( |
1085 | 1 | bps.increase_address_connections(&peer_id, Vec::new(), usize::MAX), |
1086 | | InsertAddressConnectionsResult::Inserted { |
1087 | | address_removed: None |
1088 | | } |
1089 | | )); |
1090 | | |
1091 | 1 | assert!(matches!0 ( |
1092 | 1 | bps.insert_address(&peer_id, vec![1], usize::MAX), |
1093 | | InsertAddressResult::Inserted { |
1094 | | address_removed: None |
1095 | | } |
1096 | | )); |
1097 | | |
1098 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 2); |
1099 | 1 | bps.unassign_slot_and_remove_chain_peer(&0, &peer_id); |
1100 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 2); |
1101 | | |
1102 | 1 | bps.decrease_address_connections(&peer_id, &[]).unwrap(); |
1103 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 0); |
1104 | 1 | } |
1105 | | |
1106 | | #[test] |
1107 | 1 | fn address_not_inserted_when_peer_has_no_chain_association() { |
1108 | 1 | let mut bps = BasicPeeringStrategy::<u32, Duration>::new(Config { |
1109 | 1 | randomness_seed: [0; 32], |
1110 | 1 | peers_capacity: 0, |
1111 | 1 | chains_capacity: 0, |
1112 | 1 | }); |
1113 | 1 | |
1114 | 1 | let peer_id = PeerId::from_public_key(&PublicKey::Ed25519([0; 32])); |
1115 | 1 | |
1116 | 1 | assert!(matches!0 ( |
1117 | 1 | bps.insert_address(&peer_id, Vec::new(), usize::MAX), |
1118 | | InsertAddressResult::UnknownPeer |
1119 | | )); |
1120 | | |
1121 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 0); |
1122 | 1 | } |
1123 | | |
1124 | | #[test] |
1125 | 1 | fn address_connections_inserted_when_peer_has_no_chain_association() { |
1126 | 1 | let mut bps = BasicPeeringStrategy::<u32, Duration>::new(Config { |
1127 | 1 | randomness_seed: [0; 32], |
1128 | 1 | peers_capacity: 0, |
1129 | 1 | chains_capacity: 0, |
1130 | 1 | }); |
1131 | 1 | |
1132 | 1 | let peer_id = PeerId::from_public_key(&PublicKey::Ed25519([0; 32])); |
1133 | 1 | |
1134 | 1 | assert!(matches!0 ( |
1135 | 1 | bps.increase_address_connections(&peer_id, Vec::new(), usize::MAX), |
1136 | | InsertAddressConnectionsResult::Inserted { .. } |
1137 | | )); |
1138 | | |
1139 | 1 | assert_eq!(bps.peer_addresses(&peer_id).count(), 1); |
1140 | 1 | } |
1141 | | |
1142 | | // TODO: more tests |
1143 | | } |