feat(dlv): restart rebuilds a fenced settlement from its immutable bundle (5b of 5) - #777
Merged
Merged
Conversation
…ndle (5b of 5) Rev 15 Req 16.5, Req 15.3, Req 6.15. The concrete resume_one the restart driver (PR 4) hands each unresolved trader-parent fence. Builds on 5a's frozen SettlementBundle; no settle-path change (5c does the cutover). dsm_sdk::sdk::settlement_resume rebuilds and drives a fenced transaction WITHOUT the original constructor's private state: 1. resolve the committed storage set from the catalog (storage_set_id); 2. fetch the immutable bundle B by its content identity; 3. re-hash the fetched bytes and refuse anything that does not hash to the fence's committed identity (Req 15.3), and whose own commitments disagree; 4. rebuild K(B) and the trader successor from B alone; 5. resume through run_fenced, above the persisted ballot so none is reused. The fence's tx_id IS the bundle digest b (one bundle is one transaction, Req 16.2), so tx_id is both the GetImmutable fetch key and the identity the re-hash reproduces; value_digest == tx_id, value_addr == addr(B). `reconstruct` is pure and separately tested: it verifies FOUR identities against the fence — bundle_digest == tx_id, bundle_addr == value_addr, B.storage_set_id == fence.storage_set_id, B.trader_parent == fenced parent — before building the transaction, so recovery cannot be steered by a substituted bundle. `resume_one` / `recover_all` are the thin async wrapper (live only) over the catalog, GetImmutable, the HTTP transport, and the runner. Rust 1.98.0: workspace board 4026/0, make lint 0, production_safety_checks 0.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR 5b of the QuorumBind restoration — the concrete
resume_onereconstruction (Req 16.5, Req 15.3, Req 6.15). Builds on 5a's frozenSettlementBundle(#776). No settle-path change yet — 5c does the cutover.What this adds
recover_unresolved_fences(PR 4) hands each unresolved trader-parent fence to aresume_onethat must rebuild the transaction and drive it to a terminal outcome without the original constructor's private state (Req 6.15).dsm_sdk::sdk::settlement_resumeis that reconstruction:storage_set_id);Bby its content identity;K(B)and the trader successor fromBalone (5a'skey_set);The fence's
tx_idis the bundle digestb. One bundle is one transaction (Req 16.2), sotx_idis both the fetch key (the inner digestGetImmutableresolves) and the identity the re-hash must reproduce.value_digesttherefore equalstx_id;value_addrisaddr(B).Shape
reconstruct(pure). DecodesBcanonically, then verifies four identities against the fence before building anything:bundle_digest(Canon(B)) == fence.tx_id,bundle_addr(Canon(B)) == fence.value_addr,B.storage_set_id == fence.storage_set_id, andB.trader_parent == fence.trader_parent_state_commitment. A wrong, stale, or tampered bundle is refused, not driven. It then builds theBindingTransactionwithbase_ballot = fence.ballot, so the resumed engine opens the next ballot above the persisted one.resume_one/recover_all(thin async wrapper, live only). Resolve the set, fetchBviaGetImmutable(which itself re-verifies the bytes hash to the requested identity),reconstruct, build anHttpBindingTransportover the set's members, andrun_fenced. Any failure — set not resolvable, bundle not retrievable, verification mismatch — returns without resolving, leaving the parent fenced for a later pass.recover_alldrives every unresolved fence and reports how many remain.Tests
reconstruct(settlement_resume, 2): rebuilds the transaction andK(B)from the bundle and fence, withbase_ballotat the persisted ballot andvalue_digest == tx_id == b; and refuses a bundle that does not hash to the fence identity — wrong digest, wrong address, atrader_parentthat disagrees with the fenced parent, astorage_set_idthat disagrees, and non-bundle bytes each yield the specific refusal.The async wrapper is thin glue over already-tested pieces (5a's canonical layer, PR 4's transport and
recover_unresolved_fences, PR 3'srun_fenced), so its correctness rests on the purereconstructabove and those.Verification (Rust 1.98.0)
make lint— exit 0--workspace --exclude dsm_storage_node --release) — 4026 passed, 0 failed (75 suites)production_safety_checks(all-features clippy + TLA+) — exit 0 (TLA+ included)Not in this PR (by design)
DlvClose(one-phase fold, Req 6.30) andDlvSettle(full trader-acceptance, §16.2) settle paths to buildB,PutImmutableit, settx_id = b, and driverun_fenced; wire the fence gate into successor creation; callrecover_allon restart.settlement_slot_claim_local(§22 Create public SDK API boundary for third-party developers #12).