diff options
| author | tv <tv@krebsco.de> | 2026-11-08 22:43:19 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-08 23:52:59 +0100 |
| commit | 24527adf52ca2d8d3b927feb1b811e10fc55fc5c (patch) | |
| tree | 599616858c8ec8bca78163810e65585f5e0daba4 /src/state | |
| parent | 1f50adb6ab723425ce031b45ed0db80d404805f0 (diff) | |
signatures: sign what is sent
A node signed its changes no rule signs a while after them (--sign-every
1s): the change left at once, unsigned, and its signature followed on
its own a second later, to every neighbour, over every link. A few
writes made a cascade of SIGNATURES. Under a policy requiring
signatures it signed every change as it was made instead.
A node now signs its latest change, if no signature vouches for it, as
a sync message takes it (--sign-every sent, the default): the
signature leaves in the same message, and goes where the change goes.
One signature per message, however many changes it carries, each
vouching for those before it: a slow writer's every change is signed,
a fast writer's batches are, at no threshold to pick. A policy
requiring signatures signs what is sent too, even with `none`. `all`
still signs every change as it is made; changes to protocol data,
listed paths and ?signed=true writes are signed as they are made, as
before. The interval, and the task signing on it, go.
Diffstat (limited to 'src/state')
| -rw-r--r-- | src/state/mod.rs | 47 |
1 files changed, 22 insertions, 25 deletions
diff --git a/src/state/mod.rs b/src/state/mod.rs index e079340..26910b6 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -692,8 +692,8 @@ impl AppState { } /// Signs the change just made in `replica`, if any (the one head after `before`, as - /// it builds on every head before), as `sign` says, or as `--sign-every` or the - /// policy has it; or keeps it as left unsigned. + /// it builds on every head before), as `sign` says, or as `--sign-every` has it; or + /// keeps it as left unsigned, for the sync message that takes it (`sign_sent`). fn sign_made( &self, replica: &mut crate::document::replica::Replica, @@ -707,10 +707,7 @@ impl AppState { if after != before && let [hash] = after[..] { - if self.sign_every == SignEvery::Change - || sign.wanted(&replica.doc) - || crate::access::policy::of(&replica.doc).required() - { + if self.sign_every == SignEvery::Change || sign.wanted(&replica.doc) { replica.signatures.sign(&replica.doc, hash, key); } else { replica.signatures.left_unsigned(hash); @@ -718,27 +715,27 @@ impl AppState { } } - /// This node's latest change signed, if no signature vouches for it yet, every - /// `every` (`--sign-every`): every change it makes is vouched for within that. - pub(crate) async fn sign_latest_every(self, every: Duration) { - let Some(key) = self.node_key.clone() else { + /// Before a sync message is made from `doc`: this node's latest change signed, if + /// no signature vouches for it yet and it signs what it sends (`--sign-every sent`, + /// or `none` under a policy requiring signatures), so it leaves with its signature. + /// Looked at first under the read lock: mostly there is nothing to sign. Blocking. + pub(crate) fn sign_sent(&self, doc: &crate::document::lock::DocumentLock) { + let Some(key) = &self.node_key else { return; }; - let mut ticks = tokio::time::interval(every); - ticks.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Delay); - loop { - ticks.tick().await; - let state = self.clone(); - let key = Arc::clone(&key); - let _ = tokio::task::spawn_blocking(move || { - // Looked at first under the read lock: mostly there is nothing to sign. - state.doc.blocking_read().signatures.pending() && { - let mut replica = state.doc.blocking_write(); - let replica = &mut *replica; - replica.signatures.sign_latest(&replica.doc, &key) - } - }) - .await; + if self.sign_every == SignEvery::Change { + return; + } + let due = { + let replica = doc.blocking_read(); + replica.signatures.pending() + && (self.sign_every == SignEvery::Sent + || crate::access::policy::of(&replica.doc).required()) + }; + if due { + let mut replica = doc.blocking_write(); + let replica = &mut *replica; + replica.signatures.sign_latest(&replica.doc, key); } } |
