From 075ee0be09be7ebce846043e5230ffb67a7f9a5c Mon Sep 17 00:00:00 2001 From: tv Date: Sun, 8 Nov 2026 14:14:27 +0000 Subject: screen, signatures: the oldest waiting go, not the newest Review finding 9: once 4096 signatures waited for their changes, new ones were dropped, and the waiting changes were cut at 10 000 keeping the oldest. A member could send junk once (signatures of changes that never come, changes no signature will vouch for) and fill both for good. Every honest signature arriving before its change was then lost, so under signatures required its changes waited for the actor's next signature: a stall for quiet actors. Both now keep the newest: the oldest go. A share per sender, so a member sending junk without pause can't push out what others sent either, is in future-work.md. --- src/access/screen.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/access') diff --git a/src/access/screen.rs b/src/access/screen.rs index a9450a6..4c640b6 100644 --- a/src/access/screen.rs +++ b/src/access/screen.rs @@ -39,7 +39,7 @@ use crate::document::replica::{Epoch, user_of}; use crate::document::signatures::Signatures; use crate::document::{Change, ChangeHash, Document, ReadDoc}; -/// Changes waiting for their dependencies, kept at most. +/// Changes waiting for their dependencies, kept at most: the oldest go. const MAX_WAITING: usize = 10_000; /// Refused changes kept for operators, at most: the oldest go. pub(crate) const MAX_REFUSED: usize = 1_000; @@ -187,6 +187,13 @@ impl Waiting { pub(crate) fn len(&self) -> usize { self.0.len() } + + /// The newest `MAX_WAITING`: the oldest go, so changes a peer sent that will never + /// be taken (whose dependencies or signatures never come) make way for others. + fn keep_newest(&mut self) { + let excess = self.0.len().saturating_sub(MAX_WAITING); + self.0.drain(..excess); + } } /// What `apply` did: how many changes it applied, and those it refused. @@ -269,7 +276,7 @@ pub(crate) fn apply( let (ready, unready) = in_order(doc, candidates); waiting.0 = unready; if ready.is_empty() { - waiting.0.truncate(MAX_WAITING); + waiting.keep_newest(); return Ok(screened); } @@ -462,7 +469,7 @@ pub(crate) fn apply( screened.roots.insert(root); } } - waiting.0.truncate(MAX_WAITING); + waiting.keep_newest(); Ok(screened) } -- cgit v1.3.1