aboutsummaryrefslogtreecommitdiffstats
path: root/src/document
diff options
context:
space:
mode:
Diffstat (limited to 'src/document')
-rw-r--r--src/document/replica.rs15
-rw-r--r--src/document/signatures.rs48
2 files changed, 62 insertions, 1 deletions
diff --git a/src/document/replica.rs b/src/document/replica.rs
index a409969..cdf789c 100644
--- a/src/document/replica.rs
+++ b/src/document/replica.rs
@@ -230,6 +230,19 @@ impl Replica {
&mut self,
f: impl FnOnce(&mut Document, &mut automerge::PatchLog) -> (T, bool),
) -> T {
+ self.logged_signed(|doc, _, log| f(doc, log))
+ }
+
+ /// [`logged`](Self::logged), `f` given the document's signatures too
+ /// (`access::screen`, judging received changes, checks theirs).
+ pub(crate) fn logged_signed<T>(
+ &mut self,
+ f: impl FnOnce(
+ &mut Document,
+ &mut super::signatures::Signatures,
+ &mut automerge::PatchLog,
+ ) -> (T, bool),
+ ) -> T {
use crate::locks::MutexExt;
let before = sorted_heads(&self.doc);
let mut log = self.log.lock_or_recover();
@@ -238,7 +251,7 @@ impl Replica {
// lead here.
*log = Log::at(self.epoch_seq, before);
}
- let (out, whole) = f(&mut self.doc, &mut log.patches);
+ let (out, whole) = f(&mut self.doc, &mut self.signatures, &mut log.patches);
let after = sorted_heads(&self.doc);
if whole {
log.to = after;
diff --git a/src/document/signatures.rs b/src/document/signatures.rs
index 47e5917..63b19a5 100644
--- a/src/document/signatures.rs
+++ b/src/document/signatures.rs
@@ -340,6 +340,54 @@ impl Signatures {
(signatures, next)
}
+ /// Received signatures waiting for their changes (`offer`) checked against
+ /// `changes`, not in the document yet, each made by its committer (`committers`, as
+ /// `access::screen` finds them): one valid vouches for its actor's changes up to it,
+ /// these among them.
+ pub(crate) fn vouch_batch(&mut self, changes: &[super::Change], committers: &[Option<String>]) {
+ for (change, committer) in changes.iter().zip(committers) {
+ let hash = change.hash();
+ let Some(signature) = self.pending.remove(&hash) else {
+ continue;
+ };
+ let valid = committer
+ .as_deref()
+ .and_then(crate::identity::public_of)
+ .is_some_and(|key| crate::identity::verify(&key, &message(&hash), &signature));
+ if !valid {
+ continue;
+ }
+ self.insert(hash, signature);
+ let actor = change.actor_id();
+ if self
+ .latest
+ .get(actor)
+ .is_none_or(|latest| latest.seq < change.seq())
+ {
+ self.stamp += 1;
+ self.latest.insert(
+ actor.clone(),
+ Latest {
+ seq: change.seq(),
+ hash,
+ stamp: self.stamp,
+ },
+ );
+ }
+ }
+ }
+
+ /// Signs this node's latest change in `doc` with `key` if no signature of it is kept:
+ /// after a switch or a rejoin, the changes it replayed there (`remake::delta`), made
+ /// without one, vouched for at once.
+ pub(crate) fn sign_own_latest(&mut self, doc: &Document, key: &crate::identity::NodeKey) {
+ if let Some(change) = doc.get_last_local_change()
+ && !self.by_change.contains_key(&change.hash())
+ {
+ self.sign(doc, change.hash(), key);
+ }
+ }
+
/// Whether a signature vouches for `actor`'s change `seq`.
pub(crate) fn verified(&self, actor: &super::ActorId, seq: u64) -> bool {
self.latest