diff options
Diffstat (limited to 'src/access')
| -rw-r--r-- | src/access/screen.rs | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/src/access/screen.rs b/src/access/screen.rs index 3ea03e0..010ef49 100644 --- a/src/access/screen.rs +++ b/src/access/screen.rs @@ -684,6 +684,9 @@ pub(crate) struct Outcome { pub(crate) roots: Vec<ChangeHash>, /// Changes the bytes carried forged under another node's actor: their sender's. pub(crate) forged: usize, + /// The fresh actor the node writes as from now on, where the bytes carried a change + /// of its own actor that it doesn't hold: for its own actors (`add_own_actor`). + pub(crate) fresh_actor: Option<crate::document::ActorId>, } /// [`apply`] of the changes in `bytes`, as sync messages and downloads carry them, with @@ -710,6 +713,27 @@ pub(crate) fn apply_bytes( } let mut changes = crate::document::changes::changes_in(bytes) .ok_or_else(|| anyhow::anyhow!("Refused changes that don't load"))?; + // A change of the actor this node writes as, and not one it made: another node writes + // as it too (two started from one document file with `--keep-actor`, a copied data + // directory). Each would make changes the other's peers refuse as forged; the node + // writes on as a fresh actor at once. The change is judged as any other. + let fresh_actor = changes + .iter() + .find(|change| { + change.actor_id() == doc.get_actor() + && !crate::document::changes::holds(&*doc, &change.hash()) + }) + .map(|change| { + let actor = crate::document::ActorId::random(); + tracing::warn!( + actor = %doc.get_actor(), + seq = change.seq(), + fresh = %actor, + "A change of this node's actor that it didn't make: another node writes as it (its files copied?); writing as a fresh actor" + ); + doc.set_actor(actor.clone()); + actor + }); let mut screening = screening.lock_or_recover(); let screening = screening.of(epoch_seq); // Into an empty document of the first epoch, a root only as pinned: one given or @@ -752,7 +776,10 @@ pub(crate) fn apply_bytes( } screening.record(refused_roots); if changes.is_empty() && screening.waiting.len() == 0 { - return Ok(Outcome::default()); + return Ok(Outcome { + fresh_actor, + ..Outcome::default() + }); } let received = changes.len(); let policed = screening.policed(doc); @@ -770,6 +797,7 @@ pub(crate) fn apply_bytes( refused_again: received > 0 && screened.refused_again == received, roots: screened.roots.iter().copied().collect(), forged: screened.forged, + fresh_actor, }; screening.judge_members(&screened); screening.record(screened.refused); @@ -1100,6 +1128,48 @@ mod tests { assert!(building.refused[0].why.contains("builds on refused change")); } + /// A change of the node's own actor that it didn't make: it writes on as a fresh + /// actor. Its own changes coming back change nothing. + #[test] + fn another_writing_as_this_node() { + let mut theirs = genesis(); + let mut ours = theirs.fork().with_actor(theirs.get_actor().clone()); + let screening = std::sync::Mutex::new(Screening::default()); + let take = |doc: &mut Document, from: &Document, since: &[ChangeHash]| { + let bytes: Vec<u8> = received(from, since) + .iter() + .flat_map(|change| change.raw_bytes().to_vec()) + .collect(); + apply_bytes( + doc, + Epoch::GENESIS, + 0, + &bytes, + &screening, + None, + &mut crate::document::PatchLog::inactive(), + ) + .unwrap() + }; + let heads = ours.get_heads(); + write(&mut ours, "a", None, "_continuum/members/a/alive", json!(1)); + let echo = ours.clone(); + assert!(take(&mut ours, &echo, &heads).fresh_actor.is_none()); + + let actor = ours.get_actor().clone(); + let before = theirs.get_heads(); + write( + &mut theirs, + "a", + None, + "_continuum/members/a/alive", + json!(2), + ); + let outcome = take(&mut ours, &theirs, &before); + assert_eq!(outcome.fresh_actor.as_ref(), Some(ours.get_actor())); + assert_ne!(ours.get_actor(), &actor); + } + /// Judged as its writer saw the registry: a grant earlier in the same batch counts. #[test] fn a_grant_in_the_same_batch_counts() { |
