aboutsummaryrefslogtreecommitdiffstats
path: root/src/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/access')
-rw-r--r--src/access/screen.rs38
1 files changed, 30 insertions, 8 deletions
diff --git a/src/access/screen.rs b/src/access/screen.rs
index 89ca007..5584b2b 100644
--- a/src/access/screen.rs
+++ b/src/access/screen.rs
@@ -4,9 +4,11 @@
//!
//! A change is judged at the heads its writer saw. Those of a batch aren't in the
//! document yet, so one is judged at the changes of the document its batch ancestors
-//! build on: what rules read there (the members, the user registry, remake proposals,
-//! the policy, bans) is what its writer saw, unless one of those ancestors changed it. So a change that
-//! does (`relevant`) is applied before the next is judged: the rest go in at once.
+//! build on: what rules read there (the members, the user registry, remake records,
+//! votes, the policy, bans, whether a map it makes is there) is what its writer saw,
+//! unless one of those ancestors changed it. So a change that does (`relevant`), and
+//! those before a change making a map where they wrote, are applied before the next is
+//! judged: the rest go in at once.
//!
//! A member whose own change broke a rule, as its signature proves (signatures
//! required), is refused as a whole (`Screening::refusing`): the node sends it nothing
@@ -34,7 +36,7 @@ use std::collections::{BTreeSet, HashMap, HashSet};
use anyhow::Result;
use super::rules::{self, Refusal};
-use crate::document::inspect::{Inspector, Op, Path};
+use crate::document::inspect::{Action, Inspector, Op, Path};
use crate::document::meta;
use crate::document::replica::{Epoch, user_of};
use crate::document::signatures::Signatures;
@@ -348,6 +350,9 @@ pub(crate) fn apply(
let mut unsigned: HashSet<ChangeHash> = HashSet::new();
let mut forged: HashSet<ChangeHash> = HashSet::new();
let mut accepted: Vec<Change> = Vec::new();
+ // What the accepted, not applied yet, touch: a change making a map at one of these
+ // paths is judged with them in (`rules`' maps made where there are none).
+ let mut unapplied: BTreeSet<Path> = BTreeSet::new();
for (index, change) in ready.iter().enumerate() {
let hash = change.hash();
let committer = committers[index].as_deref();
@@ -404,6 +409,18 @@ pub(crate) fn apply(
waiting.0.push(change.clone());
continue;
}
+ // It makes a map where one accepted before may have: the rules read whether one
+ // is there, so those go in first.
+ if !accepted.is_empty()
+ && ops[index]
+ .iter()
+ .any(|op| op.action == Action::MakeMap && unapplied.contains(&op.path))
+ {
+ screened.applied += accepted.len();
+ apply_taken(doc, std::mem::take(&mut accepted), log)?;
+ frontier.clear();
+ unapplied.clear();
+ }
let mut seen_at: BTreeSet<ChangeHash> = BTreeSet::new();
for dep in change.deps() {
match frontier.get(dep) {
@@ -439,8 +456,10 @@ pub(crate) fn apply(
screened.applied += accepted.len();
apply_taken(doc, std::mem::take(&mut accepted), log)?;
frontier.clear();
+ unapplied.clear();
} else {
frontier.insert(hash, seen_at);
+ unapplied.extend(paths[index].iter().cloned());
}
}
Err(Refusal::Unready) => {
@@ -626,10 +645,12 @@ pub(crate) fn apply_bytes(
}
/// Whether a change touching `paths` changes what rules read: the members, the user
-/// registry, remake records, the policy and the rest of `_continuum/access`, bans, the
-/// protocol data as a whole; and, under a strict policy, values their users sign
-/// (`reaches_signed`). A rule that reads anything else (`rules::judge`) must add it
-/// here, or a batch judged at its frontier is judged at heads it doesn't hold.
+/// registry, remake records, votes, the policy and the rest of `_continuum/access`,
+/// bans, the protocol data as a whole; under a strict policy, values their users sign
+/// (`reaches_signed`); and, for a change making a map, whether one is there, which
+/// `apply` checks against what the accepted before it touch. A rule that reads anything
+/// else (`rules::judge`) must add it here, or a batch judged at its frontier is judged
+/// at heads it doesn't hold.
fn relevant(paths: &BTreeSet<Path>) -> bool {
paths.iter().any(|path| match path.as_slice() {
[] => true,
@@ -639,6 +660,7 @@ fn relevant(paths: &BTreeSet<Path>) -> bool {
meta::MEMBERS,
meta::USERS,
meta::REMAKES,
+ meta::VOTES,
meta::ACCESS,
meta::BANNED,
]