aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/access')
-rw-r--r--src/access/screen.rs72
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() {