aboutsummaryrefslogtreecommitdiffstats
path: root/src/state/mod.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-08 22:43:19 +0000
committertv <tv@krebsco.de>2026-11-08 23:52:59 +0100
commit24527adf52ca2d8d3b927feb1b811e10fc55fc5c (patch)
tree599616858c8ec8bca78163810e65585f5e0daba4 /src/state/mod.rs
parent1f50adb6ab723425ce031b45ed0db80d404805f0 (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/mod.rs')
-rw-r--r--src/state/mod.rs47
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);
}
}