diff options
| -rw-r--r-- | docs/access.md | 9 | ||||
| -rw-r--r-- | src/swarm/bootstrap.rs | 1 | ||||
| -rw-r--r-- | src/swarm/roots.rs | 24 |
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 { |
