aboutsummaryrefslogtreecommitdiffstats
path: root/src/state
diff options
context:
space:
mode:
Diffstat (limited to 'src/state')
-rw-r--r--src/state/host.rs15
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();