diff options
| author | tv <tv@krebsco.de> | 2026-11-07 22:35:21 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-07 22:35:21 +0100 |
| commit | c9b05d33f57b7efd69301b56725614a0d9938599 (patch) | |
| tree | 1b1fc8dd4d2254174303f2938fb0ec773081af2e /src/state | |
| parent | 8523e9c67e375747147a0b05ec191ad81ce2e318 (diff) | |
signatures: --sign-every
Changes left unsigned are vouched for by the node's next signature:
--sign-every 1s (default) signs the latest within a second, all signs
every change, none only those that must be.
Auth plan M5.
Diffstat (limited to 'src/state')
| -rw-r--r-- | src/state/mod.rs | 33 |
1 files changed, 30 insertions, 3 deletions
diff --git a/src/state/mod.rs b/src/state/mod.rs index ef1559d..1fc8ea8 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -38,7 +38,7 @@ use tracing::{debug, error, warn}; use crate::document::lock::DocumentLock; use crate::document::replica::{Epoch, Stamp}; -use crate::document::signatures::Sign; +use crate::document::signatures::{Sign, SignEvery}; use crate::document::store::{ChangeSet, StoreError}; use crate::document::{Document, Transaction}; use crate::locks::{MutexExt, RwLockExt}; @@ -147,6 +147,9 @@ pub(crate) struct AppState { /// Signs the tokens this node issues and the changes it commits /// (`NodeConfig::node_key`). pub(crate) node_key: Option<Arc<crate::identity::NodeKey>>, + /// Which of its changes this node signs besides those a write's `Sign` says + /// (`--sign-every`). + pub(crate) sign_every: SignEvery, pub(crate) token_lifetime: Duration, pub(crate) session_lifetime: Duration, /// Origins whose pages may call this node's open endpoints (`api::cors`). @@ -527,9 +530,12 @@ impl AppState { let after = replica.doc.get_heads(); if after != before && let [hash] = after[..] - && sign.wanted(&replica.doc) { - replica.signatures.sign(hash, key); + if state.sign_every == SignEvery::Change || sign.wanted(&replica.doc) { + replica.signatures.sign(hash, key); + } else { + replica.signatures.left_unsigned(hash); + } } } replica.refresh_heads(); @@ -545,6 +551,27 @@ impl AppState { .expect("document write task panicked") } + /// 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 { + 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() + && state.doc.blocking_write().signatures.sign_latest(&key) + }) + .await; + } + } + pub(crate) fn publish_change(&self) { self.notify_store_changed(); if let Err(error) = self.sync_events.send(SyncEvent::DocumentChanged) { |
