aboutsummaryrefslogtreecommitdiffstats
path: root/src/remake
diff options
context:
space:
mode:
Diffstat (limited to 'src/remake')
-rw-r--r--src/remake/coordinator.rs43
-rw-r--r--src/remake/mod.rs4
-rw-r--r--src/remake/vote.rs9
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, &register)
+ ),
)
.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, &register)
+ ),
+ )
+ .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(|_| ())
}