diff options
| -rw-r--r-- | docs/access.md | 3 | ||||
| -rw-r--r-- | src/remake/catchup.rs | 16 | ||||
| -rw-r--r-- | src/remake/switch.rs | 12 |
3 files changed, 30 insertions, 1 deletions
diff --git a/docs/access.md b/docs/access.md index 46758b0..be91185 100644 --- a/docs/access.md +++ b/docs/access.md @@ -428,7 +428,8 @@ registry, the policy and the bans change only as a user who may change them sign A running swarm turns strict through a remake of its own kind, `strict`, once (a swarm strict already takes none: its registry, policy and bans change by their users' -signatures, not by a majority of members): compaction +signatures, not by a majority of members; its nodes neither vote for one nor follow one +a majority commits anyway, switching or rejoining): compaction that keeps, at the places values are signed (the registry, `_continuum/access`, the bans, the paths listed in `userSigned`), only the values an operator looked over and signed, and sets the strict policy. What was written after its base reaches the new diff --git a/src/remake/catchup.rs b/src/remake/catchup.rs index 4df5c90..6ef8121 100644 --- a/src/remake/catchup.rs +++ b/src/remake/catchup.rs @@ -528,6 +528,22 @@ fn prepare( .filter(|next| next.previous == previous); let gap = target.generation - previous.generation; + // A strict remake of a swarm strict already isn't followed: there its registry, + // policy and bans change by its users' signatures, not by a majority of members + // (`vote::strict_taken`). Strict as our document is, or once a remake since made it so. + let mut strict = crate::access::policy::of(old).strict(); + for generation in previous.generation + 1..=target.generation { + if let Ok(epoch) = snapshot::read_epoch_metadata(copy, generation) + && epoch.kind == "strict" + { + if strict { + return Prepared::Failed(format!( + "epoch generation {generation} was made by a strict remake of a swarm strict already: not followed" + )); + } + strict = true; + } + } // Writes made in our epoch go through every remake since, in order. let translator = (previous.generation + 1..=target.generation).try_fold( Translator::default(), diff --git a/src/remake/switch.rs b/src/remake/switch.rs index bd40d72..df3fcc8 100644 --- a/src/remake/switch.rs +++ b/src/remake/switch.rs @@ -192,6 +192,18 @@ async fn switch<H: Host>( let translator = request .translator() .ok_or_else(|| format!("unknown remake kind {:?}", request.kind))?; + // A strict remake of a swarm strict already, committed by a majority of members + // anyway: not followed (`vote::strict_taken`, `catchup`). + if request.kind == "strict" + && host + .read_doc(|doc| crate::access::policy::of(doc).strict()) + .await + { + return Err( + "a strict remake of a swarm strict already: its registry changes by its users' signatures; not followed" + .to_owned(), + ); + } let late_translator = translator.clone(); let superseded = host.superseded(); let previous = request.previous; |
