fix(validator): require BlockIDs+!Conflicting+!Locked before ErrTxNotFound shortcut#770
Conversation
…Found shortcut (refs #4568)
|
🤖 Claude Code Review Status: Complete Summary: Current Review:
Previous Reviews:
|
Benchmark Comparison ReportBaseline: Current: Summary
All benchmark results (sec/op)
Threshold: >10% with p < 0.05 | Generated: 2026-05-12 08:30 UTC |
| v.logger.Warnf("[Validate][%s] parent tx DAH-evicted, child already mined and not conflicting/locked, assuming blessed (BlockIDs=%v)", txID, txMetaData.BlockIDs) | ||
|
|
||
| return txMetaData, nil | ||
| return txMetaData, nil |
There was a problem hiding this comment.
[Minor] Consider similar fix for store implementations
This PR correctly addresses the validator-level shortcut, but similar patterns exist in:
stores/utxo/aerospike/spend.go- usess.Get()without checking BlockIDs/Conflicting/Lockedstores/utxo/sql/sql.go- uses simple existence check without metadata validation
Those store-level shortcuts may have the same vulnerability: accepting a transaction as "blessed" based solely on its existence during a DAH-eviction or reorg window.
Recommendation: Consider creating a follow-up issue to audit and potentially apply similar metadata checks (BlockIDs, Conflicting, Locked) in the store implementations.
|



Closes #4568.
Summary
When
spendUtxosreturnsErrTxNotFound(parent missing), the validator looked up the current tx in the UTXO store and, if found, returned(meta, nil)with a warning "assuming already blessed" — without checking whether the metadata actually confirmed prior validation. During a reorg or DAH-eviction window, a tx lookup can succeed while its parent is temporarily absent; the shortcut would silently accept the tx on the basis of its own existence rather than a verified prior validation.Fix
Gate the shortcut on three conditions that together imply prior full validation:
len(BlockIDs) > 0— tx has been included in at least one block.!Conflicting— tx is not flagged as conflicting.!Locked— tx is not locked (e.g., from a conflict aftermath).If any condition fails, surface the original
ErrTxNotFound. Use a localmetaErrso the outererr(stillErrTxNotFound) survives the metadata lookup for the fall-through error path.Also tightened
MockUtxostore.GetMetasoReturn(error)now correctly surfaces a lookup failure instead of panicking on a*meta.Datacast.Test plan
go test -race ./services/validator/...passes.go test -race ./stores/utxo/...passes.