diff options
Diffstat (limited to 'src/state')
| -rw-r--r-- | src/state/host.rs | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/src/state/host.rs b/src/state/host.rs index ac36171..e7fc61a 100644 --- a/src/state/host.rs +++ b/src/state/host.rs @@ -99,14 +99,20 @@ impl AppState { /// so). Every peer syncs anew. Nothing while a rejoin runs, or if the document doesn't /// hold `root`; nor if `root` is an epoch's root, or nothing would be kept, which no /// rule can mean (logged as an error). A drop taking much (`BIG_DROP`) waits for a - /// second member to say so (`peer` the first, `why` its rules' reason): its rules and - /// one peer's word might both be off, the swarm's not. + /// second member to say so (`peer` the first, `why` its rules' reason), where it has + /// another neighbour: its rules and one peer's word might both be off, the swarm's + /// not. Two members colluding pass it; it guards against one. pub(crate) async fn drop_taken(&self, root: ChangeHash, peer: &str, why: &str) { /// Changes a drop takes, at most, on one peer's word: more, or more than a tenth /// of the document (past `SMALL_DROP`), wait for another's. const BIG_DROP: usize = 100; const SMALL_DROP: usize = 10; let own = self.remake.own_actors(); + // Another member to hear it from: a node with one neighbour, the one telling, has + // only its word (a swarm of two, a leaf), and waiting would hold the drop for good. + let another = crate::swarm::topology::our_neighbours(self) + .iter() + .any(|other| other != peer); let state = self.clone(); let peer = peer.to_owned(); let why = why.to_owned(); @@ -136,8 +142,9 @@ impl AppState { error!(change = %root, "Dropping a change would leave nothing; kept it"); return None; } - if tainted.len() > BIG_DROP - || (tainted.len() > SMALL_DROP && tainted.len() * 10 > changes.len()) + if another + && (tainted.len() > BIG_DROP + || (tainted.len() > SMALL_DROP && tainted.len() * 10 > changes.len())) { use crate::locks::MutexExt; let mut screening = state.screening.lock_or_recover(); |
