aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-08 22:44:23 +0000
committertv <tv@krebsco.de>2026-11-08 23:53:02 +0100
commiteae437ce2734b8d65bf40aa207c134a3c641138f (patch)
tree44743e69511d0f56a987497bcbbc03e53cd4dc74
parent24527adf52ca2d8d3b927feb1b811e10fc55fc5c (diff)
sync: signatures go with changes only
A sync message took the signatures its peer wasn't sent yet whenever it had a body, an Automerge message saying only what we have included. A signature belongs with the changes it vouches for: they go along the trees, and a peer that got them elsewhere got the signatures with them. Signatures now go in a message that carries changes (pushed, offered as a delta, or in an Automerge message carrying some: SyncSession:: carrying), and in no other.
-rw-r--r--src/document/sync.rs7
-rw-r--r--src/swarm/sync.rs14
2 files changed, 19 insertions, 2 deletions
diff --git a/src/document/sync.rs b/src/document/sync.rs
index 394b10a..440718c 100644
--- a/src/document/sync.rs
+++ b/src/document/sync.rs
@@ -983,6 +983,13 @@ impl SyncSession {
self.state.their_heads.is_none() && we_ready && peer_ready == Some(false)
}
+ /// Whether the message just generated (`generate`) carries changes.
+ pub(crate) fn carrying(&self) -> bool {
+ self.sending
+ .as_ref()
+ .is_some_and(|sending| !sending.sent.is_empty())
+ }
+
/// Which session this is: a message generated from it reports its send's outcome
/// with this (`send_succeeded`, `send_failed`).
pub(crate) fn id(&self) -> u64 {
diff --git a/src/swarm/sync.rs b/src/swarm/sync.rs
index 0c49fa3..b7bf8ed 100644
--- a/src/swarm/sync.rs
+++ b/src/swarm/sync.rs
@@ -287,8 +287,18 @@ async fn deliver_sync_to_peer(state: &AppState, peer: &str) -> Result<()> {
_ => {}
}
}
- // With what it carries, the signatures the peer wasn't sent yet.
- let signatures = if body.is_some() {
+ // With changes, the signatures the peer wasn't sent yet: they go where
+ // changes go, along the trees, so a peer that got these changes
+ // elsewhere got the signatures with them, and a message carrying
+ // none takes none.
+ let carries = match &body {
+ Some(
+ transport::SyncBody::Changes { .. } | transport::SyncBody::Delta(_),
+ ) => true,
+ Some(_) => peer_state.sync.carrying(),
+ None => false,
+ };
+ let signatures = if carries {
let (signatures, sent) =
replica.signatures.newer_than(peer_state.signatures_sent);
peer_state.signatures_sent = sent;