summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/remake/catchup.rs4
-rw-r--r--src/remake/mod.rs20
-rw-r--r--src/state.rs8
3 files changed, 29 insertions, 3 deletions
diff --git a/src/remake/catchup.rs b/src/remake/catchup.rs
index 39b9550..56aeee1 100644
--- a/src/remake/catchup.rs
+++ b/src/remake/catchup.rs
@@ -71,11 +71,13 @@ pub(super) async fn check<H: Host>(host: &H) {
}
let local = host.current_epoch();
+ // Only ready members count: a rejoining peer advertises an epoch it doesn't hold
+ // yet, and a node of another swarm (or a stranger) advertises one that isn't ours.
let mut ahead: Vec<(String, Epoch)> = host
.peer_summaries()
.await
.into_iter()
- .filter(|peer| peer.active)
+ .filter(|peer| peer.serves())
.filter_map(|peer| peer.epoch.map(|epoch| (peer.id, epoch)))
.filter(|(_, epoch)| epoch.generation > local.generation)
.collect();
diff --git a/src/remake/mod.rs b/src/remake/mod.rs
index dacd1db..ca17956 100644
--- a/src/remake/mod.rs
+++ b/src/remake/mod.rs
@@ -141,10 +141,30 @@ pub(crate) struct PeerSummary {
pub(crate) id: String,
/// Not dormant.
pub(crate) active: bool,
+ /// Completed the handshake and belongs to our swarm. A peer that merely sent us
+ /// something (a node of another swarm on the same network, a stranger before
+ /// admission) is not one, and nothing it advertises is followed.
+ pub(crate) member: bool,
+ /// What it last said about being ready; None before it said anything.
+ pub(crate) ready: Option<bool>,
/// The epoch the peer last advertised.
pub(crate) epoch: Option<Epoch>,
}
+impl PeerSummary {
+ /// A peer whose epoch can be followed and downloaded from: an active member that
+ /// holds the document it advertises. A rejoining peer advertises its target epoch
+ /// with an empty document and `ready: false`.
+ pub(crate) fn serves_epoch(&self, epoch: Epoch) -> bool {
+ self.serves() && self.epoch == Some(epoch)
+ }
+
+ /// An active, ready member.
+ pub(crate) fn serves(&self) -> bool {
+ self.active && self.member && self.ready == Some(true)
+ }
+}
+
/// Admin routes. Merged into the authenticated part of the node's router.
/// Largest remake request (bytes). The proposal carries the new document to every
/// node in one sync message, which Mycelium must deliver within its deadline, so
diff --git a/src/state.rs b/src/state.rs
index c51446f..9383c89 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -643,13 +643,14 @@ impl AppState {
self.transport.local_id()
}
- /// Peers that are active and last said they are on our epoch.
+ /// Peers that can serve our epoch's data: active, ready members on our epoch
+ /// (`PeerSummary::serves_epoch`).
pub(crate) async fn active_peers_on_local_epoch(&self) -> Vec<String> {
let epoch = self.local_epoch();
self.peer_summaries()
.await
.into_iter()
- .filter(|peer| peer.active && peer.epoch == Some(epoch))
+ .filter(|peer| peer.serves_epoch(epoch))
.map(|peer| peer.id)
.collect()
}
@@ -1090,6 +1091,9 @@ impl Host for AppState {
summaries.push(PeerSummary {
id,
active: peer.liveness == Liveness::Active,
+ member: matches!(peer.standing, Standing::Member { .. })
+ && peer.hello_state == HelloState::Established,
+ ready: peer.reports_ready,
epoch: peer.epoch,
});
}