diff options
| author | tv <tv@krebsco.de> | 2026-10-28 17:35:35 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-10-28 17:35:35 +0100 |
| commit | beaed2e572cf2477714bd4c1ea2b1901fb0cc11e (patch) | |
| tree | 2dac07650feb47e7b76a06dff6fae1926fbed38e /src/swarm | |
| parent | c0f53c8d163339c675fa0336e3588b7cfa4ac87e (diff) | |
track unlisted members
Diffstat (limited to 'src/swarm')
| -rw-r--r-- | src/swarm/peer/handshake.rs | 2 | ||||
| -rw-r--r-- | src/swarm/topology.rs | 30 |
2 files changed, 30 insertions, 2 deletions
diff --git a/src/swarm/peer/handshake.rs b/src/swarm/peer/handshake.rs index fbebfc6..3e8fbf4 100644 --- a/src/swarm/peer/handshake.rs +++ b/src/swarm/peer/handshake.rs @@ -375,6 +375,8 @@ pub(super) async fn establish_peer( peer_state.standing = Standing::Member { swarm_id: swarm_id.clone(), }; + // A member our list may lack yet: a neighbour then (`topology::refresh`). + state.topology_changed.notify_one(); } // Stop our retries and sync from a clean slate. A new handshake from the peer always diff --git a/src/swarm/topology.rs b/src/swarm/topology.rs index 2ba07b7..1e4f5b9 100644 --- a/src/swarm/topology.rs +++ b/src/swarm/topology.rs @@ -44,6 +44,9 @@ pub(crate) struct NeighbourView { /// The transports (address schemes) of each member, and ours. transports: BTreeMap<String, BTreeSet<String>>, local_transports: BTreeSet<String>, + /// Peers that proved they are of our swarm but aren't in our member list (yet): their + /// registration hasn't reached us. They are neighbours too (`refresh`). + unlisted: BTreeSet<String>, neighbours: BTreeSet<String>, /// Every reachable member is a neighbour. full_mesh: bool, @@ -205,10 +208,29 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { unreachable.insert(member.clone()); } } + // A node that joined while the genesis node hadn't registered yet has the genesis + // document without the genesis node in it, and registers itself there: then neither + // lists the other, and with each the other's neighbour only by the member list, + // neither would ever sync with the other, and their registrations never pass. So a + // peer that proved itself a member of our swarm counts until the list says otherwise: + // syncing brings each the other's registration. + let mut unlisted = BTreeSet::new(); + for (peer, peer_state) in state.peers_snapshot().await { + if current.contains(&peer) || peer == state.local_id() { + continue; + } + let peer_state = peer_state.lock().await; + if matches!(peer_state.standing, crate::state::Standing::Member { .. }) + && !peer_state.is_unreachable() + { + unlisted.insert(peer); + } + } let previous = { let view = state.neighbours.read_or_recover(); if view.as_ref().is_some_and(|view| { view.members == current + && view.unlisted == unlisted && view.k == k && view.unreachable == unreachable && view.stable == stable @@ -225,7 +247,7 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { Some(previous) => previous, None => state.peer_states.read().await.keys().cloned().collect(), }; - let computed = neighbours_across( + let mut computed = neighbours_across( &transports, state.local_id(), &local_transports, @@ -233,6 +255,8 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { &|m| unreachable.contains(m), &|m| stable.contains(m), ); + let listed_neighbours = computed.len(); + computed.extend(unlisted.iter().cloned()); let change = NeighbourChange { added: computed .iter() @@ -251,6 +275,7 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { stable = stable.len(), k, neighbours = computed.len(), + unlisted = unlisted.len(), added = change.added.len(), removed = change.removed.len(), "Neighbours computed from the member list" @@ -260,13 +285,14 @@ pub(crate) async fn refresh(state: &AppState) -> Option<NeighbourChange> { .filter(|m| m.as_str() != state.local_id() && !unreachable.contains(*m)) .count(); *state.neighbours.write_or_recover() = Some(NeighbourView { - full_mesh: computed.len() >= reachable_others, + full_mesh: listed_neighbours >= reachable_others, members: current, k, unreachable, stable, transports, local_transports, + unlisted, neighbours: computed, }); Some(change) |
