Repository navigation
fix(replication)!: require close-group proofs for every prune deletion - #266
mickvandijke wants to merge 3 commits into
Conversation
Distance alone no longer authorises deleting a stored record. A local routing-table view says which peers are closer, not that any of them holds the bytes, so deleting on topology could drop the last copy. - Chunks: remove the width-20 FastDelete path, its revalidation, and the no-proof shortcut in audited revalidation. Every deletion now needs 6-of-7 possession proofs from the current strict close group. Drop the width-20 lookup per stored key per pass. - Pointers: remove the matching "far outside the group" shortcut; others_hold is always required. - Remove the public MAX_FAST_PRUNE_DELETIONS_PER_PASS constant and the fast-path prune-pass stats. - Tests: replace the fast-path tests with regressions proving a pruner outside a complete paid-width group keeps records until proofs arrive. - Docs: withdraw the fast path in ADR-0005 decision 11, update ADR-0016 and REPLICATION_DESIGN.md. BREAKING CHANGE: removes replication::config::MAX_FAST_PRUNE_DELETIONS_PER_PASS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every pointer prune candidate now needs close-group proof, so the pass must not stall on candidates nobody can prove yet. - Rotate a cursor through candidates in address order, so unprovable ones no longer keep the rest from a turn. - Ask each candidate's capable group members at once; stop as soon as the threshold is met or can no longer be met, and skip a group with too few capable members entirely. - Prove up to 32 candidates at once, each within one fetch timeout, so a pass is bounded however many peers stay silent. - ADR-0016: record that far copies wait for capability until the gate is retired. - Rename the chunk regression test to the retention-width input it actually passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Candidates come in address order, so those in flight share one group. At 32 at once they queued behind their own requests at each peer's 8 outbound slots, which repair and possession checks share, and the per-candidate budget counted that queueing. - Prove 4 candidates at once, half of each peer's slots, so pruning never queues behind itself and repair keeps the other half. - Give each candidate 5 s, the storage audit's floor for one small read over a cold connection, so a pass still ends within about 5 minutes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaidSafe-Hermes
left a comment
There was a problem hiding this comment.
Review at 95a0afc. Coverage: 2/2 seats reviewed (sol-1 gpt-6.1-sol xhigh; glm-1 z-ai/glm-5.3); not unanimous (GLM recommends approve, sol is uncertain).
I verified the fairness concern: PointerStore::held_states sorts by address before candidate collection (src/pointer/store.rs:677-693), as next_prune_batch requires. The five-second proof bound and four-candidate cap are clear in src/replication/pointer.rs:164-181, 1906-1945; the relevant pointer unit tests cover rotation and early proof termination.
One residual safety concern is not established as a new blocker: proof results become a boolean in others_hold, then prune_candidate rechecks responsibility/commitment but not whether the proof-giving peers are still in the current close group (src/replication/pointer.rs:1941-1975). This can leave a group-change race against the docs’ current-group requirement; it merits a focused race test or peer-set revalidation.
The PR is still draft and its stated dev-testnet gate is outstanding. Exact-head CI has build/test, format, clippy and storage checks passing; Security Audit fails on crypto-bigint 0.5.5 (RUSTSEC-2026-0387), but Cargo.lock is unchanged from base, so this is inherited rather than introduced here. I am leaving a comment, not an approval.
|
Superseded by #271. It carries this PR's three commits rebased onto main (every prune deletion needs close-group proofs; the fast path and pointer far path are gone) and adds pressure-gated retention (ADR-0028): out-of-range records are erased only under disk pressure, farthest first. The pointer address cursor from this PR is replaced there by the shared erase order, which keeps the same fairness. |
Linear issue
Closes V2-1825
Risk tier
Compatibility
AuditChallengepath.replication::config::MAX_FAST_PRUNE_DELETIONS_PER_PASS. The prune-pass log line drops itsfast_delete_candidates,fast_delete_budget_deferredandfast_prunedfields.Semver impact
Test evidence
cargo test --lib --features test-utils replication::: 646 passed, 0 failed.cargo test --test e2e --features test-utils -- --test-threads=1 prun pointer: 20 passed, 0 failed (all prune and pointer e2e tests).revalidation_retains_record_outside_complete_group_without_proofs; e2eprune_deletes_at_proof_threshold_and_retains_below_it(now run with a paid width the ten-node harness completes) andpruning_deletes_only_once_the_close_group_proves_it_holds_the_record(pointers).a_prune_pass_starts_past_the_last_one_and_wraps_round,candidates_the_group_cannot_prove_never_keep_the_rest_from_a_turn) and for proofs that stop early (enough_proofs_are_taken_without_waiting_for_a_peer_that_stalls,a_group_that_can_no_longer_reach_the_threshold_is_given_up_at_once,a_group_too_small_to_reach_the_threshold_is_never_asked). With proofs run one at a time and no cursor, four of the five fail.cargo fmt --all -- --check: clean.cargo clippy --all-targets --all-features -- -D warnings: no findings in changed code. The remaining failures (chunk_store.rssignificant-drop lints,Durationunit lints inpointer.rsandpointer_replication.rstest code) already fail onmainwith the current toolchain.New dependency
none
ADR
Mitigation / rollback
Revert this PR to restore the fast path. Watch disk usage and the prune-pass
candidates,budget_deferredandaudit_below_thresholdcounters for backlogs draining too slowly.Summary
Every prune deletion now requires possession proofs from the current strict close group (6 of 7 at production parameters), however far outside the group the node has moved.
FastDeletepath, its revalidation, and the no-proof shortcut in audited revalidation. Drop the now-unused width-20 lookup per stored key per pass.others_holdis now always required. Because every pointer candidate now needs proof, the pointer pass is rebuilt so it stays fair and bounded:REPLICATION_DESIGN.mdupdated.A local routing-table view says which peers are closer, not that any of them holds the bytes. Deleting on distance alone could remove the last surviving copy.
Known limit, by design. Pointer requests go only to peers known to speak pointers, learned from their own pointer messages, so older peers are never asked something they cannot decode and never penalised for the silence. A node far outside a record's group may never hear from that group, so it keeps the record: storage held, never a copy lost. This ends when the capability gate is retired, once no pre-pointer peer remains (recorded in ADR-0016's consequences).
🤖 Generated with Claude Code