diff options
Diffstat (limited to 'src/remake')
| -rw-r--r-- | src/remake/coordinator.rs | 43 | ||||
| -rw-r--r-- | src/remake/mod.rs | 4 | ||||
| -rw-r--r-- | src/remake/vote.rs | 9 |
3 files changed, 44 insertions, 12 deletions
diff --git a/src/remake/coordinator.rs b/src/remake/coordinator.rs index 314cd87..0d7a434 100644 --- a/src/remake/coordinator.rs +++ b/src/remake/coordinator.rs @@ -138,7 +138,10 @@ async fn step<H: Host>(host: &H, id: &str) -> Result<bool, StoreError> { decide_abort( host, id, - format!("no majority in the voting period: {tally}"), + format!( + "no majority in the voting period: {tally}{}", + strict_hint(id, &record, ®ister) + ), ) .await?; return Ok(true); @@ -149,12 +152,48 @@ async fn step<H: Host>(host: &H, id: &str) -> Result<bool, StoreError> { return Ok(true); } if tally.out_of_reach() { - decide_abort(host, id, format!("a majority is out of reach: {tally}")).await?; + decide_abort( + host, + id, + format!( + "a majority is out of reach: {tally}{}", + strict_hint(id, &record, ®ister) + ), + ) + .await?; return Ok(true); } Ok(false) } +/// For a strict remake `id` without a majority: who didn't vote, and why they may not +/// have (`vote::strict_taken`), for its operator to tell from the reason. Nothing for +/// another kind, or if all voted. +fn strict_hint(id: &str, record: &Record, register: &records::Register) -> String { + if record.proposal.kind != "strict" { + return String::new(); + } + let silent: Vec<&str> = record + .proposal + .electorate + .iter() + .filter(|member| { + register + .get(member.as_str()) + .is_none_or(|votes| !votes.iter().any(|vote| vote.remake == id)) + }) + .map(String::as_str) + .collect(); + if silent.is_empty() { + return String::new(); + } + format!( + "; a strict remake, not voted for by {}: a member votes for one only with its \ + manifest signed by a key of its --strict-keys (or it was away)", + silent.join(", ") + ) +} + /// Why remake `id` must be aborted whatever its votes, if it must. fn obstacle(id: &str, record: &Record, all: &[(String, Record)]) -> Option<String> { if let Some(request) = &record.abort_requested { diff --git a/src/remake/mod.rs b/src/remake/mod.rs index a075c69..33ac748 100644 --- a/src/remake/mod.rs +++ b/src/remake/mod.rs @@ -330,10 +330,8 @@ pub(crate) trait Host: Clone + Send + Sync + 'static { /// What a replay does with writes a newer one superseded (`--superseded-writes`). fn superseded(&self) -> Superseded; - /// Whose signature on a strict remake's manifest this node takes (`--strict-keys`), - /// and whether it votes for one without any (`--follow-strict-remakes`). + /// Whose signature on a strict remake's manifest this node takes (`--strict-keys`). fn strict_keys(&self) -> &[crate::access::sshsig::PublicKey]; - fn follows_strict_remakes(&self) -> bool; /// Applies a change downloaded from peers (`fetch_change`), then publishes it like /// a change received by sync. diff --git a/src/remake/vote.rs b/src/remake/vote.rs index c231afa..073fcda 100644 --- a/src/remake/vote.rs +++ b/src/remake/vote.rs @@ -375,8 +375,7 @@ pub(super) async fn cast<H: Host>(host: &H) { } /// Whether this node takes a strict remake's manifest (`content`, for `swarm`): signed -/// by one of its `--strict-keys`; without any, if it follows strict remakes all the same -/// (`--follow-strict-remakes`). Why not, if not. +/// by one of its `--strict-keys`. Why not, if not. pub(super) fn strict_taken<H: Host>( host: &H, content: Option<&[u8]>, @@ -386,11 +385,7 @@ pub(super) fn strict_taken<H: Host>( .and_then(|bytes| std::str::from_utf8(bytes).ok()) .ok_or("no manifest")?; if host.strict_keys().is_empty() { - return if host.follows_strict_remakes() { - crate::access::strict::read(text).map(|_| ()) - } else { - Err("this node has no --strict-keys (nor --follow-strict-remakes)".to_owned()) - }; + return Err("this node has no --strict-keys".to_owned()); } crate::access::strict::verify(text, host.strict_keys(), swarm).map(|_| ()) } |
