Skip to content

feat(dlv): the canonical SettlementBundle a quorum transaction binds (5a of 5) - #776

Merged
cryptskii merged 1 commit into
mainfrom
feat/quorumbind-switch-settle-paths
Sep 6, 2026
Merged

feat(dlv): the canonical SettlementBundle a quorum transaction binds (5a of 5)#776
cryptskii merged 1 commit into
mainfrom
feat/quorumbind-switch-settle-paths

Conversation

@cryptskii

Copy link
Copy Markdown
Collaborator

PR 5a of the QuorumBind restoration — the first of the five-part switch to QuorumBind (5a bundle, 5b resume, 5c cutover, 5d delete, 5e wipe). This lands the canonical SettlementBundle object (Def 6.14/6.17/6.19) that everything after it binds. No settle path changes here — this is the frozen protocol object, reviewed alone before anything depends on it.

What this adds

The bundle B (Def 6.14). A new canonical proto SettlementBundleV1 mirroring the definition explicitly — no normative field hidden inside another object:

SettlementBundleV1 {
  version, storage_set_id, q,
  intent_commitment (I), route_set_commitment (X), selected_route,
  trader_parent, trader_successor,
  vault_transitions[] { vault_id, parent_generation, parent_state_commitment (c_n),
                        parent_reserves_digest, successor_ccb, reserve_deltas, witnesses },
  proof_material[], bundle_signatures, recovery_material
}

It carries everything needed to verify the route and recover the DLV decision without a fresh constructor signature (Req 6.15): the exact trader parent (not only the successor), I and X explicitly, the complete sorted per-vault transitions, the proofs, the signatures, and the recovery material. version is present because this object freezes on deploy — a new shape is a new version, never a silent field change.

The canonical layer (dsm::dlv::settlement_bundle, pure, no I/O):

  • canon(B) — the canonical bytes: transitions must be strictly ascending by vault_id, and the message must re-encode to itself (unknown fields, non-minimal encodings, and empties all fail).
  • bundle_digestb = H(DSM/settlement-bundle ‖ Canon(B)) (Def 6.14).
  • bundle_addraddr(B) = H(DSM/storage-object ‖ DSM/settlement-bundle ‖ b) (Def 6.19), through the existing immutable-object construction so a new address rule cannot drift from the one every other immutable object uses.
  • resource_key(c_n)k_v = H(DSM/binding-keyset ‖ c_n) (Def 6.17). The vault id is not restated: c_n already commits it, so supplying both would admit a disagreeing pair.
  • key_set(B)K(B), the sorted distinct resource keys, derived only from the canonical bundle's committed parent states. Strictly ascending, so it is a valid QuorumBind key set; two vaults sharing a c_n are refused rather than silently collapsing to one key.

Two new domain tags, DSM/binding-keyset and DSM/settlement-bundle, both added to the tag-uniqueness registry.

Tests

  • Core (dsm::dlv::settlement_bundle, 4): Canon(B) round-trips and b/addr(B) match the spec construction, and different bytes give a different identity; a bad version, a mis-width field, or an empty bundle is refused; transitions must be strictly ascending by vault_id (unsorted or duplicate refused); K(B) is the sorted distinct resource keys over c_n, and two vaults sharing a c_n are refused.

Verification (Rust 1.98.0)

  • root make lintexit 0
  • workspace board (--workspace --exclude dsm_storage_node --release) — 4024 passed, 0 failed (75 suites)
  • production_safety_checks (all-features clippy + TLA+) — exit 0 (TLA+ included)

The committed TypeScript proto artifact was regenerated from the schema so the two stay in sync.

Not in this PR (by design)

  • 5b — the resume_one reconstruction (resolve the set, fetch B by addr, verify/rebuild K(B), resume through the runner without original private state).
  • 5c — switch the DlvClose (one-phase fold, Req 6.30) and DlvSettle (full trader-acceptance, §16.2) settle paths to run_fenced; wire the fence gate into successor creation.
  • 5d — delete the settlement-slot endpoint, table, driver, and settlement_slot_claim_local (§22 Create public SDK API boundary for third-party developers #12).
  • 5e — beta wipe + redeploy (operational).

…(5a of 5)

Rev 15 Def 6.14/6.17/6.19, Req 6.15. The first of the five-part switch to
QuorumBind (5a bundle, 5b resume, 5c cutover, 5d delete, 5e wipe). This lands
the canonical bundle object everything after it binds; NO settle path changes
here, so the frozen protocol object is reviewed alone.

The shipped settle path had no SettlementBundle and no resource keys — it signed
per-vault SettlementSlotClaimV2 envelopes — so the switch has to introduce this
object first.

SettlementBundleV1 mirrors Def 6.14 EXPLICITLY, no normative field hidden inside
another object: version, storage_set_id, q, intent_commitment (I),
route_set_commitment (X), selected_route, the exact trader_parent and
trader_successor, the complete sorted per-vault transitions {T_v}
(vault_id, parent_generation, c_n, parent_reserves_digest, successor_ccb,
reserve_deltas, witnesses), proof_material {P_v}, bundle_signatures, and
recovery_material — everything needed to verify the route and recover the DLV
decision without a fresh constructor signature (Req 6.15). A version field is
present because this object freezes on deploy.

dsm::dlv::settlement_bundle (pure): canon(B) requires transitions strictly
ascending by vault_id and re-encode-to-self; b = H(DSM/settlement-bundle ||
Canon(B)); addr(B) reuses the existing immutable-object construction so it
cannot drift; resource_key k_v = H(DSM/binding-keyset || c_n) (vault_id not
restated — c_n commits it); key_set K(B) is the sorted distinct resource keys,
derived ONLY from the canonical bytes, and refuses two vaults sharing a c_n. Two
new domain tags in the uniqueness registry. The committed TS proto artifact was
regenerated.

Rust 1.98.0: workspace board 4024/0, make lint 0, production_safety_checks 0.
@cryptskii
cryptskii merged commit 4548e81 into main Sep 6, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant