diff options
| author | tv <tv@krebsco.de> | 2026-11-08 09:33:41 +0000 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-08 10:35:31 +0100 |
| commit | b758c93a1887ea36b0f52ccd4a6f9824de77d819 (patch) | |
| tree | 96f7f4ca3007e393b185739a66b0474323b50872 /src/swarm | |
| parent | af3869df9ff3a0266857bd7c7534b75b36d04aa5 (diff) | |
access: an epoch's root is never dropped
A REFUSALS naming the swarm's first change made the node receiving it
judge that change again in a document that isn't empty, refuse it as
"a change without dependencies that isn't the epoch's root", and drop
it with everything built on it: its whole document.
The first epoch's root is now the first change a document holds, as it
comes to an empty one or as it is in one; a change judged again on a
peer's word is never refused for having no dependencies; and
drop_taken refuses to drop an epoch's root, or anything that would
leave nothing kept, logging an error instead.
Review finding 1 (critical).
Diffstat (limited to 'src/swarm')
| -rw-r--r-- | src/swarm/refusals.rs | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/src/swarm/refusals.rs b/src/swarm/refusals.rs index 2e5399a..fd857fa 100644 --- a/src/swarm/refusals.rs +++ b/src/swarm/refusals.rs @@ -99,6 +99,10 @@ fn judge_held( hash: &ChangeHash, ) -> Option<Result<(), String>> { let change = doc.get_change_by_hash(hash)?; + // An epoch's root is what the document is: never refused, whatever a peer says. + if change.deps().is_empty() { + return Some(Ok(())); + } let decoded = change.decode(); let ops = crate::document::inspect::Inspector::new(doc) .ops(std::slice::from_ref(&decoded)) |
