oor: reject incomplete ancestry index on incoming OOR receive (#374) - #442
oor: reject incomplete ancestry index on incoming OOR receive (#374)#442ellemouton wants to merge 1 commit into
Conversation
validateIncomingAncestry checked that each fragment's InputIndices was non-empty and within range, but did not reject duplicate indices or require the union of all fragments to cover every Ark tx input. An indexer/operator could return ancestry for only a subset of a multi-input OOR Ark tx — for example a two-input Ark tx with a single fragment naming only input 0 — and the descriptor would be accepted and persisted with incomplete recovery lineage. If the operator later disappears, the uncovered input has no rooted-path material for fraud-watch or unilateral-exit assembly, stranding the received VTXO. Track which input indices each fragment claims, reject duplicates at the malformed fragment, and require coverage of every Ark tx input before returning. Add direct table-driven coverage for the partition checks and a two-input materialization helper so the existing primary-ancestry normalization test exercises a genuine cross-round multi-input shape rather than a single-input PSBT with two fake fragments. Closes #374.
There was a problem hiding this comment.
Code Review
This pull request enhances the validation of incoming OOR VTXOs by ensuring that all Ark transaction inputs are uniquely covered by ancestry fragments. It introduces checks for duplicate input indices and missing coverage within the validateIncomingAncestry function to prevent potential fund loss. Corresponding tests and test helpers were added to verify these partition checks for multi-input transactions. Feedback suggests a potential optimization for the coverage check using a counter, though the current loop-based approach allows for more specific error messages regarding missing indices.
| for idx, ok := range covered { | ||
| if !ok { | ||
| return &ErrInvalidAncestry{ | ||
| Reason: fmt.Sprintf( | ||
| "ark tx input %d is not covered by "+ | ||
| "any ancestry fragment "+ | ||
| "(incoming ancestry must "+ | ||
| "cover every input)", idx, | ||
| ), | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
The coverage check iterates through the entire covered slice to find missing indices. While correct, this could be optimized by maintaining a counter of unique indices seen during the fragment loop. If the counter equals arkTxInputCount at the end, full coverage is guaranteed (since duplicates are already rejected). The current loop is only necessary if you want to identify the specific missing index for the error message.
There was a problem hiding this comment.
Keeping the explicit loop intentionally — the second pass lets the error message identify the specific missing input index, which is useful for debugging malformed indexer responses. Happy to revisit if the cost shows up in profiling.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Superseded by consolidated PR #459. Closing to reduce CI load. |
Closes #374.
Summary
oor.validateIncomingAncestrychecked that each fragment'sInputIndiceswas non-empty and within range, but it did not:InputIndicesto cover every Ark tx input.A malicious indexer could therefore return ancestry for only a subset of a multi-input OOR Ark tx; the descriptor would be accepted and persisted with incomplete recovery lineage, leaving the VTXO stranded if the operator later refuses cooperation (no rooted-path material for
fraud.BuildWatchPlanor unilateral-exit assembly on the uncovered inputs).This is on the same
IncomingVTXOMetadata.Ancestryartifact, distinct from #366 (PackageArtifactPSBT graph) and from #371 (resolver read path).Fix
oor/incoming_vtxo.go::validateIncomingAncestry:covered []boolsized to the Ark tx input countFailures continue to surface as
*ErrInvalidAncestryso the receive FSM routes to session-failure ack.Test plan
TestValidateIncomingAncestryInputCoverage— partitions: single/two-fragment partition success, missing-coverage truncation, mid-range gap, intra/cross-fragment duplicatesTestBuildIncomingVTXODescriptorNormalizesPrimaryAncestryupdated to use a new two-input materialization helper (the old setup was a single-input PSBT with two fake fragments — itself a coverage violation under the corrected rule)make lint-native— 0 issuesgo test ./oor ./darepod ./fraud ./vtxo ./db -count=1— passRelated: distinct from #366 (write path of persisted package graph) and from #371 (resolver / read path). No bundle.