summaryrefslogtreecommitdiffstats
path: root/src/swarm/peer/handshake.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-26 05:45:20 +0100
committertv <tv@krebsco.de>2026-10-26 05:45:20 +0100
commit51e8c8e38c05d98487784e21f9df54cc18875b8b (patch)
tree5b3a6f85ed79549bea8c104d39b9069b40a8d2ef /src/swarm/peer/handshake.rs
parentf12a839d6e6bdd29a86ac52d5de836519a41aaf0 (diff)
send bounded peer lists
Diffstat (limited to 'src/swarm/peer/handshake.rs')
-rw-r--r--src/swarm/peer/handshake.rs37
1 files changed, 31 insertions, 6 deletions
diff --git a/src/swarm/peer/handshake.rs b/src/swarm/peer/handshake.rs
index c46df9c..038dac6 100644
--- a/src/swarm/peer/handshake.rs
+++ b/src/swarm/peer/handshake.rs
@@ -13,6 +13,12 @@ use crate::swarm::sync::SyncEvent;
use crate::swarm::topology;
use crate::transport::{self, ParsedMessage};
+/// Most peers a HELLO_REPLY lists, and most we take from one: each listed peer may get
+/// a HELLO, so a long list (a hub's hundreds of neighbours, or a peer making up keys)
+/// costs the recipient as much as it is long. A joining node needs only a few to find
+/// the swarm; the member list gives it the rest once it is ready.
+const MAX_LISTED_PEERS: usize = 64;
+
pub(crate) async fn remember_peer(state: &AppState, peer: &str) {
if peer.is_empty() {
warn!("Ignoring empty peer public key");
@@ -183,6 +189,12 @@ pub(super) async fn send_hello_reply(
peers.push(known);
}
}
+ // Those the recipient would most likely pick as neighbours itself (lowest pair
+ // score with it, as `topology` ranks them), if there are too many.
+ if peers.len() > MAX_LISTED_PEERS {
+ peers.sort_by_cached_key(|known| topology::pair_score(peer, known));
+ peers.truncate(MAX_LISTED_PEERS);
+ }
let auth = state
.swarm_key
@@ -215,18 +227,31 @@ pub(super) async fn send_hello_reply(
Ok(())
}
+/// Greets the peers a HELLO_REPLY listed: at most `MAX_LISTED_PEERS`, only valid
+/// identities, and, once the member list is known, only those that are our neighbours
+/// (it says whom we greet; a listed peer that isn't one would get nothing from us, so
+/// it isn't remembered either).
pub(super) async fn discover_peers(state: &AppState, from_peer: &str, advertised_peers: &[String]) {
- // TODO here we could add a trace t oshwo advertised_peers
+ let view_known = topology::view_known(state);
+ let mut taken = 0;
for discovered_peer in advertised_peers {
- if discovered_peer == from_peer {
+ if discovered_peer == from_peer || !state.transport.is_peer_id(discovered_peer) {
continue;
}
-
- remember_peer(state, discovered_peer).await;
-
- if !topology::is_neighbour(state, discovered_peer) {
+ if view_known && !topology::is_neighbour(state, discovered_peer) {
continue;
}
+ if taken == MAX_LISTED_PEERS {
+ debug!(
+ from = %from_peer,
+ listed = advertised_peers.len(),
+ "HELLO_REPLY listed more peers than we take; ignoring the rest"
+ );
+ break;
+ }
+ taken += 1;
+
+ remember_peer(state, discovered_peer).await;
if let Err(error) = send_hello_once(state, discovered_peer).await {
warn!(
peer = %discovered_peer,