diff options
Diffstat (limited to 'src/state/mod.rs')
| -rw-r--r-- | src/state/mod.rs | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/src/state/mod.rs b/src/state/mod.rs index 671aff7..ef1559d 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -38,6 +38,7 @@ use tracing::{debug, error, warn}; use crate::document::lock::DocumentLock; use crate::document::replica::{Epoch, Stamp}; +use crate::document::signatures::Sign; use crate::document::store::{ChangeSet, StoreError}; use crate::document::{Document, Transaction}; use crate::locks::{MutexExt, RwLockExt}; @@ -143,7 +144,8 @@ pub(crate) struct AppState { pub(crate) protocol_writers: Arc<std::collections::HashSet<String>>, /// The swarm's first users, recorded by a genesis node (`NodeConfig::first_users`). pub(crate) first_users: Arc<crate::access::registry::FirstUsers>, - /// Signs the tokens this node issues (`NodeConfig::node_key`). + /// Signs the tokens this node issues and the changes it commits + /// (`NodeConfig::node_key`). pub(crate) node_key: Option<Arc<crate::identity::NodeKey>>, pub(crate) token_lifetime: Duration, pub(crate) session_lifetime: Duration, @@ -452,7 +454,7 @@ impl AppState { /// cancelled request can't leave a committed write unannounced. While a rejoin runs, /// the write goes into the document before it (`StaleView`), replayed when the /// rejoin ends; on a node that keeps none, it is refused (`StoreError::Rejoining`, - /// `f` not called). + /// `f` not called). Protocol data: the change is signed (`document::signatures`). pub(crate) async fn mutate_doc<T, E>( &self, f: impl FnOnce(&mut Transaction<'_>) -> Result<T, E> + Send + 'static, @@ -461,15 +463,19 @@ impl AppState { T: Send + 'static, E: From<StoreError> + Send + 'static, { - self.mutate_doc_for(None, f).await.map(|(out, _)| out) + self.mutate_doc_for(None, Sign::Protocol, f) + .await + .map(|(out, _)| out) } /// [`mutate_doc`](Self::mutate_doc) for `user`, who wrote through the API: the - /// change names them (`replica::Writer`). With the heads of the document written to - /// after the write (sorted): what a read must have to include it. + /// change names them (`replica::Writer`), and is signed as `sign` says, with this + /// node's key. With the heads of the document written to after the + /// write (sorted): what a read must have to include it. pub(crate) async fn mutate_doc_for<T, E>( &self, user: Option<String>, + sign: Sign, f: impl FnOnce(&mut Transaction<'_>) -> Result<T, E> + Send + 'static, ) -> Result<(T, Vec<crate::document::ChangeHash>), E> where @@ -511,7 +517,21 @@ impl AppState { node: state.local_id(), user: user.as_deref(), }; + let before = replica.doc.get_heads(); let result = replica.transact(state.clock.now_millis(), &writer, f); + if result.is_ok() + && let Some(key) = &state.node_key + { + // The change made, if any: the one head after it, as it builds on + // every head before. + let after = replica.doc.get_heads(); + if after != before + && let [hash] = after[..] + && sign.wanted(&replica.doc) + { + replica.signatures.sign(hash, key); + } + } replica.refresh_heads(); result.map(|out| (out, replica.heads().to_vec())) }; // lock released before notifying |
