From 5fe7653a2e86bfbee0bcbe536bb74287ab47498f Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 13:54:07 +0000 Subject: rules: a carried remake record taken from the coordinator its snapshot names Review finding 7, second part: a record carried into a new epoch whole (proposal and decision in one change) was taken from any member, for any remake ID. A member could write a forged record, decision included, for a fresh ID in a single change. The snapshot's epoch metadata now names the remake's coordinator, as the quorum built it. The carried-record exception holds only in a later epoch, only for the remake that made it, and only from the coordinator its snapshot names, where there is no record yet. Wire version 43: the snapshot, and so the epoch ID, changes. The review suggested carrying the record inside the snapshot instead. The snapshot can't hold the decision, which names the snapshot's own hash. So the snapshot vouches for who may carry the record instead. --- src/remake/snapshot.rs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/remake/snapshot.rs') diff --git a/src/remake/snapshot.rs b/src/remake/snapshot.rs index 220989e..7938b53 100644 --- a/src/remake/snapshot.rs +++ b/src/remake/snapshot.rs @@ -36,6 +36,8 @@ use crate::document::store::{self, StoreError}; pub(crate) struct SnapshotParams<'a> { /// ID of the committed remake; seeds the snapshot actor. pub(crate) remake_id: &'a str, + /// The node coordinating it: the one that carries its record into the new epoch. + pub(crate) coordinator: &'a str, /// The epoch being compacted. The snapshot starts generation `previous + 1`. pub(crate) previous: Epoch, /// Heads of the base. Every node must hold all of these changes. @@ -84,6 +86,7 @@ pub(crate) enum SnapshotError { #[derive(Clone, Debug)] pub(crate) struct SnapshotRequest { pub(crate) remake_id: String, + pub(crate) coordinator: String, pub(crate) previous: Epoch, pub(crate) base_heads: Vec, pub(crate) policy: JsonValue, @@ -97,6 +100,7 @@ impl SnapshotRequest { pub(crate) fn params(&self) -> SnapshotParams<'_> { SnapshotParams { remake_id: &self.remake_id, + coordinator: &self.coordinator, previous: self.previous, base_heads: &self.base_heads, policy: &self.policy, @@ -311,6 +315,7 @@ pub(crate) fn build( let metadata = canonical(json!({ "generation": generation, "remakeId": params.remake_id, + "coordinator": params.coordinator, "previous": { "generation": params.previous.generation, "id": params.previous.id_hex(), @@ -391,6 +396,7 @@ mod tests { fn params<'a>(heads: &'a [ChangeHash], policy: &'a JsonValue) -> SnapshotParams<'a> { SnapshotParams { remake_id: "c-1", + coordinator: "a", previous: Epoch::GENESIS, base_heads: heads, policy, -- cgit v1.3.1