multi: Register authenticated provisional lineage end to end#990
multi: Register authenticated provisional lineage end to end#990ellemouton wants to merge 12 commits into
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
@claude review this |
|
Claude finished @ellemouton's task in 4m 34s —— View job Review: PR #990 — Register authenticated provisional lineage end to endI reviewed the full diff against Below are observations, ordered roughly by significance. None are blockers. 1.
|
e428c4d to
b1f9ab8
Compare
f44d3e6 to
1e732f1
Compare
|
Review disposition for the current head: the CSV delay is intentionally operator-authored policy input because it is not derivable from the commitment transaction; all transaction-bound fields are authenticated, and the client still requires a positive delay. The output-index error path intentionally fails closed instead of copying the legacy confirmation-watch fallback. The duplicated receive-path coverage checks and failed-then-retried metric sequence are non-blocking cleanup notes; no correctness finding was left open in this PR. |
b1f9ab8 to
9655bde
Compare
8dbd209 to
c566338
Compare
9655bde to
659e6aa
Compare
c566338 to
899c934
Compare
659e6aa to
b2a5d3d
Compare
899c934 to
9d3b6b0
Compare
b2a5d3d to
c121b30
Compare
9d3b6b0 to
095039e
Compare
49e2003 to
9d19e5d
Compare
|
@claude review this — the current head adds canonicality-aware spendable and temporarily-unavailable balance reporting plus a real reorg/reconfirmation systest. |
|
Claude finished @ellemouton's task in 2m 56s —— View job Review: canonicality-aware balance reporting + reorg systestReviewed the head commits What's correct
Observations (all non-blocking)1. Proto docs omit the
Neither mentions unseen/unregistered lineage. Since a client rendering this figure will see freshly-created-but-unconfirmed live VTXOs land here, it's worth a word in the doc so the wire contract matches the behavior the test locks in. Fix this → 2. UX consideration for the unseen window. Following from (1): a just-received round/OOR VTXO whose commitment isn't confirmed yet is 3. Minor nil-guard asymmetry. The non-nil path guards 4. Per-RPC store fan-out. Nice, tight change — the classification predicate reusing |
9d19e5d to
97bd459
Compare
095039e to
7f636e7
Compare
|
@claude review this — final head is now rebased onto current main and includes canonicality-aware temporarily-unavailable balance reporting plus the real reorg systest. |
|
Claude finished @ellemouton's task in 2m 8s —— View job Review: PR #990 — final head (rebased onto main)
Re-reviewed the full stack (7 commits) against Rebase / correctness confirmations
Non-blocking observations (status of prior notes)1. Proto docs still omit the "unseen" bucket. 2. 3. Minor nil-guard asymmetry. The non-nil path guards Note on validationI could not run The authentication layer and the reuse of |
|
@claude review this — addressed the two actionable non-blocking notes: temporary-balance docs now include unseen/unregistered lineage, and all batch registrations now enforce positive CSV expiry with regression coverage. |
|
Review disposition: temporary-balance wire docs and positive CSV registration validation are fixed in the current head. The nil-reader descriptor note is unreachable because ListLiveVTXOs does not return nil descriptors; no correctness finding is left open. |
|
Claude finished @ellemouton's task in 2m 55s —— View job Review: follow-up fixes (CSV positivity + temporary-balance docs)
Reviewed the two new commits on top of the previously-signed-off stack. Both notes are addressed correctly. One small formatting issue that will fail CI. ✅ CSV-expiry positivity (
|
37ab56c to
6c63040
Compare
7f636e7 to
8943a38
Compare
d7cb561 to
c6fc5e3
Compare
|
@claude review this — current restacked head |
|
Claude finished @ellemouton's task in 1m 20s —— View job Review: PR #990 — restacked head
|
c6fc5e3 to
f3cf7bd
Compare
|
@claude review this |
|
Claude finished @ellemouton's task in 2m 13s —— View job Review: PR #990 — new head
|
f3cf7bd to
ecfc4c2
Compare
|
@claude review this — current head |
|
Claude finished @ellemouton's task in 1m 35s —— View job Review: PR #990 — restacked head
|
ecfc4c2 to
a08dd0b
Compare
4991fb7 to
a4f2c42
Compare
Build complete batch evidence from the retained commitment PSBT when a round confirms. Await durable canonicality registration before saving any new VTXO so the fail-closed admission gate never observes unregistered liquidity. Refresh registrations bind each consumed VTXO to its next lifecycle revision and complete creator lineage, allowing a terminally replaced round to restore only the exact forfeiture it owns.
Carry the commitment transaction and every input prevout in ancestry responses. Validate the transaction, output, and input bindings before receive paths register canonicality watches.
Persist authenticated evidence in the durable receive event and await canonicality registration before staging incoming VTXOs. Legacy indexers may omit the full additive extension, while partial or conflicting evidence fails closed.
Carry authenticated evidence through the round-receive ancestry lookup. Await canonicality registration before saving or notifying the VTXO manager. Missing legacy evidence remains blocked by the gate.
Custom OOR inputs bypass wallet coin selection and its fail-closed lineage gate. Reuse the full-lineage reader before maturity checks so reorged or invalidated inputs never reach checkpoint signing.
Expose reversible lineage limbo separately from spendable and pending VTXO balances so clients can explain why value is temporarily unusable.
Keep reorged, conflicted, unseen, and reconciling lineage out of the spendable figure while preserving it in a temporary-unavailability bucket. Exercise the classification across a real reorg and reconfirmation.
Reject malformed local or imported registration evidence before it can produce a height-derived expiry at the confirmation block itself.
Include unseen and unregistered lineage in the balance field contract so clients can explain the same fail-closed bucket the daemon reports.
Batch registration after a restart must use the immutable CSV delay under which the client signed the round. Persist and restore that per-round term instead of reconstructing it as zero.
Pass the local round start height and indexed commitment height into batch canonicality registration. Persist the indexer hint through OOR durable messages so delayed and replayed receive paths scan across already-mined confirmations.
a4f2c42 to
f2bfa75
Compare
a08dd0b to
a7d456b
Compare
|
@claude review this — head was rebuilt (height-hint watch clamp squashed into the batchcanon watch-hint story; client re-pins). CI is green. Please re-review the current head. |
|
Claude finished @ellemouton's task in 2m 12s —— View job Review: PR #990 — rebuilt head
|
The wired VTXO admission gate reads lineage availability straight from the durable store via LineageBlocked. When a reorg/conflict observation could not be persisted (a transient ApplyObservation failure), the in-memory watch was marked not-ready but the stale durable row stayed Ready(), so the gate kept admitting a VTXO whose commitment had just left the best chain. The overlay the code comments promised only ever protected the unwired actor QueryLineage path. Make the manager itself a batchcanon.Reader whose GetBatch overlays the in-memory watch: a not-ready watch forces the returned record not-ready, even when the durable row still reads Ready. Thread the manager (not the raw store) into the gate. The overlay only downgrades ready->not-ready, so it is strictly fail-closed. Add a wired-path test proving admission closes after a failed reorg persist.
Roasbeef
left a comment
There was a problem hiding this comment.
In this review, I found two P1 admission gaps and two recovery/evidence issues at the current head. Registration-before-exposure and the fail-closed overlay are the right direction, but the direct reader still has a stale-read interleaving, and unroll/fraud doesn't consume the new gate. I'm requesting changes on those paths before we use this PR as the client half of the #454 capstone.
| func (m *Manager) GetBatch(ctx context.Context, txid chainhash.Hash) (*Record, | ||
| error) { | ||
|
|
||
| record, err := m.cfg.Store.GetBatch(ctx, txid) |
There was a problem hiding this comment.
[P1] We need to take m.mu before the store read here. Right now the read can return Provisional@r, then a reorg callback takes the mutex and successfully persists ReorgedOut@(r+1). That complete snapshot leaves w.ready=true, so the overlay below doesn't downgrade the stale record and the caller still admits it. I think the clean fix is to linearize the store read with the watch snapshot under the same lock, then add a deterministic interleaving test.
| // activated once the batch producers (round, OOR) register their | ||
| // batches, or every unregistered VTXO is excluded. | ||
| BatchCanonicality batchcanon.Store | ||
| BatchCanonicality batchcanon.Reader |
There was a problem hiding this comment.
[P1] This gate reaches coin selection and explicit forfeit selection, but handleForceUnroll never consults BatchCanonicality, and fraud routes straight into that path. A VTXO with missing/reorged lineage can still enter UnilateralExitState and create proof/sweep side effects. We need the same lineage check at the unroll point of no return, with explicit behavior for objectively invalidated lineage.
| consumerEdges = append(consumerEdges, batchcanon.ConsumerEdge{ | ||
| ConsumedVTXO: outpoint, | ||
| ConsumerBatch: batchTxID, | ||
| ExpectedRevision: consumedVTXO.BusinessRevision + 1, |
There was a problem hiding this comment.
[P2] We register this future business revision before ForfeitConfirmedToVTXO has persisted the matching ForfeitedBy(consumer) marker. If the consumer becomes ConflictFinalized first, ResolveConsumerEdge defers; the later MarkForfeited doesn't redrive the edge. That can strand the VTXO until restart. We should redrive after MarkForfeited succeeds and add the ordering test where terminal conflict arrives before the outbox marker.
| i) | ||
| } | ||
|
|
||
| prevOut := input.GetPrevOut() |
There was a problem hiding this comment.
[P2] We're authenticating the outpoint/order against TxIn, but not the supplied prevout value/script. Any nonempty script and nonnegative value passes, and that script later keys the spend notifier. Unless the indexer is explicitly trusted for these fields, we need to resolve/prove the prevout against chain truth and test a changed nonempty script/value. At minimum, the PR should state this trust boundary instead of calling the payload authenticated.
What this PR does
Connects the real VTXO creation and receipt paths to the
batchcanonauthorityintroduced by #980. Without this PR the authority exists but production paths do
not consistently feed it.
It handles three production sources:
The indexer ancestry response supplies the serialized commitment transaction,
ordered commitment prevouts, CSV-delay evidence, and the parent lineage required
to validate a received VTXO. The recipient treats that response as untrusted
and authenticates: the commitment txid, the referenced output, every commitment
input, the input prevouts and their ordering, and the relationship between the
received VTXO and the supplied batch.
Registration happens before the VTXO is saved or exposed:
sequenceDiagram participant R as OOR receiver participant I as Indexer participant B as batchcanon participant V as VTXO store R->>I: Request ancestry I-->>R: Commitment, prevouts, and lineage R->>R: Authenticate evidence R->>B: Register complete lineage B-->>R: Registration durable R->>V: Materialize and save VTXOOnce registered, the client responds to later reorgs using its local chain
watches; it does not requery the indexer.
Wallet reporting uses the same authority: a lifecycle-live VTXO whose lineage is
reorged, conflicted, unseen, or still reconciling is excluded from spendable
balance and included in
temporarily_unavailable_sat. Terminally invalidatedvalue is excluded from both buckets.
Review focus
Full design & diagrams:
REORG_SAFETY_PR_REVIEW_GUIDE.md§4.3. Overallarchitecture and PR stack: lumos#454.