From 81dc0ca6012372ff293e19549053fda84bca1eb0 Mon Sep 17 00:00:00 2001 From: tv Date: Thu, 12 Nov 2026 01:13:54 +0000 Subject: screen: refuse a change at a seq this node made under its own actor A node receiving a change of the actor it writes as, one it doesn't hold, writes on as a fresh actor (another node writes as it, from a copy of its files). Where the other node made it at a seq this node made a change at too, the change was taken to Automerge, which refuses the whole batch (duplicate seq): the message failed, and with it everything else it carried. Signatures::forks found it forged only where a signature verified a change of the actor at that seq, and this node signs its own latest change only as it sends it. forks now also finds a change forged where its actor is the one the document writes as and the document's latest change of it (get_last_local_change) is at its seq or later. apply_bytes switches to the fresh actor after judging the batch, not before, so the check still sees the actor; also where judging fails. --- src/document/signatures.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/document/signatures.rs') diff --git a/src/document/signatures.rs b/src/document/signatures.rs index 4f34ecb..79c8569 100644 --- a/src/document/signatures.rs +++ b/src/document/signatures.rs @@ -603,11 +603,15 @@ impl Signatures { /// Whether `change`, not in `doc`, forks its actor's changes: `doc` holds a change /// a signature verified of that actor at a seq as late, so its real change at /// `change`'s seq too. Anyone can make a change under any actor; only its node can - /// sign one. + /// sign one. Or the actor is the one `doc` writes as, and it made a change at a seq + /// as late: another node writing as it too made this one. pub(crate) fn forks(&self, doc: &Document, change: &super::Change) -> bool { self.latest.get(change.actor_id()).is_some_and(|latest| { latest.seq >= change.seq() && super::changes::holds(doc, &latest.hash) - }) + }) || (change.actor_id() == doc.get_actor() + && doc + .get_last_local_change() + .is_some_and(|own| own.seq() >= change.seq())) } /// Whether a signature vouches for `actor`'s change `seq`. -- cgit v1.3.1