aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/access.md9
-rw-r--r--src/swarm/bootstrap.rs1
-rw-r--r--src/swarm/roots.rs24
3 files changed, 28 insertions, 6 deletions
diff --git a/docs/access.md b/docs/access.md
index 3877dff..6422b51 100644
--- a/docs/access.md
+++ b/docs/access.md
@@ -357,9 +357,12 @@ ID: a forged root, or a genesis started again).
A node joining with an empty document takes as its root only the one it was given
(`--genesis-root`), or else the one its peers name, and none while they name different
ones; and none before each of its seeds named one, or ten seconds passed since the
-first did. So without `--genesis-root`, the root is the one the seeds that answer within
-that wait agree on: one peer hands a joiner another root only if it is all the joiner
-hears by then; with `--genesis-root`, never.
+first did. Its seeds are the nodes proven at the seeds' addresses: another peer naming
+a root (one of a member's own identities, say) disputes it, but neither ends the wait
+nor starts it. So without `--genesis-root`, the root is the one the seeds that answer
+within that wait agree on, none while any peer names another: one seed hands a joiner
+another root only if it is all the joiner hears of its seeds by then; with
+`--genesis-root`, never.
What it doesn't do yet:
diff --git a/src/swarm/bootstrap.rs b/src/swarm/bootstrap.rs
index 6d3a4ad..d2a593b 100644
--- a/src/swarm/bootstrap.rs
+++ b/src/swarm/bootstrap.rs
@@ -409,6 +409,7 @@ async fn resolve_seeds(
debug!(seed = %seed, peer = %peer, "Resolved seed");
}
remember_peer(state, &peer).await;
+ crate::swarm::roots::seed_found(state, &peer);
if let Err(error) = send_hello_once(state, &peer).await {
warn!(peer = %peer, error = %format!("{error:#}"), "Initial HELLO failed; will retry");
}
diff --git a/src/swarm/roots.rs b/src/swarm/roots.rs
index d12f089..930c190 100644
--- a/src/swarm/roots.rs
+++ b/src/swarm/roots.rs
@@ -11,8 +11,10 @@
//! * a joining node takes as its root only the one given (`--genesis-root`), or else the
//! one its peers name, and none while they name different ones (`RootPin`); and none
//! before each of its seeds named one, or `ROOT_WAIT` passed since the first did, so
-//! the seed that answers first doesn't decide alone. One peer hands a joiner another
-//! root only if it is all the joiner hears within the wait.
+//! the seed that answers first doesn't decide alone. Seeds are the nodes proven at
+//! the seeds' addresses (`seed_found`): a peer answering under identities of its own
+//! neither ends the wait nor starts its clock, only disputes. One seed hands a joiner
+//! another root only if it is all the joiner hears of its seeds within the wait.
use std::collections::{HashMap, HashSet};
use std::time::Duration;
@@ -35,6 +37,9 @@ pub(crate) const ROOT_WAIT: Duration = Duration::from_secs(10);
pub(crate) struct Roots {
/// Of the first epoch, as each peer named it.
named: HashMap<String, ChangeHash>,
+ /// The nodes proven at the seeds' addresses (`seed_found`): only theirs count
+ /// toward the wait (`repin`).
+ seeds: HashSet<String>,
/// Joining with an empty document: how many seeds it waits for, and until when once
/// the first named a root.
awaiting: Option<(usize, Option<tokio::time::Instant>)>,
@@ -156,6 +161,14 @@ pub(crate) fn await_seeds(state: &AppState, seeds: usize) {
repin(state);
}
+/// `node` is the one at a seed's address (`bootstrap::resolve_seeds`): its root counts
+/// toward the wait for the seeds (`repin`).
+pub(crate) fn seed_found(state: &AppState, node: &str) {
+ if state.roots.lock_or_recover().seeds.insert(node.to_owned()) {
+ repin(state);
+ }
+}
+
/// Until when a joining node still waits for its seeds to name the swarm's root, if it
/// waits on a clock (`await_seeds`): then `repin`.
pub(crate) fn waiting_until(state: &AppState) -> Option<tokio::time::Instant> {
@@ -172,7 +185,12 @@ pub(crate) fn repin(state: &AppState) {
let now = tokio::time::Instant::now();
let pin = {
let mut roots = state.roots.lock_or_recover();
- let named = roots.named.len();
+ // Seeds only: others' roots dispute, but neither end the wait nor start it.
+ let named = roots
+ .named
+ .keys()
+ .filter(|peer| roots.seeds.contains(*peer))
+ .count();
let awaiting = match &mut roots.awaiting {
Some((seeds, until)) => {
if until.is_none() && named > 0 {