fix(log): report tx_state in the ConnectBlock CheckTxInputs failure log - #7713
Conversation
Consensus::CheckTxInputs fills in tx_state, but the log line printed state, the BlockValidationState, which is only invalidated on the next statement. ValidationState::ToString() short-circuits to the literal "Valid" for a state that has not been invalidated, so every one of these block-connect failures logged "Valid" instead of the reject reason that caused it. The mistake dates to the backport of bitcoin#15921, which introduced the separate tx_state but left the log reading state. Upstream later moved state.Invalid() ahead of the log so that state carried the copied reason by then; Dash instead collapsed it into a single `return state.Invalid(...)`, which fixes the opposite ordering, so read tx_state directly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review. Walkthrough
Priority: ⬇️ Low Estimated code review effort: 1 (Trivial) | ~3 minutes Merge Risk: ⚪ Minimal · up to This correction makes transaction rejection logs show the actual validation reason without changing transaction acceptance or rejection behavior. The change is ready to merge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
| if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) { | ||
| // Any transaction validation failure in ConnectBlock is a block consensus failure | ||
| LogError("%s: Consensus::CheckTxInputs: %s, %s\n", __func__, tx.GetHash().ToString(), state.ToString()); | ||
| LogError("%s: Consensus::CheckTxInputs: %s, %s\n", __func__, tx.GetHash().ToString(), tx_state.ToString()); |
There was a problem hiding this comment.
never had been fixed by mainstream, eventually code is removed / replaced by bitcoin#31112
It seems as no relevant backport to fix
Issue being fixed or feature implemented
In
Chainstate::ConnectBlock, the error path forConsensus::CheckTxInputslogs the wrong validation state:CheckTxInputsfills intx_state, notstate. At the point the log fires, theBlockValidationState& statehas not been invalidated yet — that happens on the very next statement.ValidationState::ToString()short-circuits onIsValid()and returns the literal string"Valid", so every one of these block-connect failures logs:The actual reason (
bad-txns-inputs-missingorspent,bad-txns-in-belowout,bad-txns-inputvalues-outofrange, …) is dropped. The reason still reaches theBlockValidationStatefor the caller, so this is a diagnostics-only defect — but it silently removes the useful half of the log line in exactly the situation where you need it.The mistake dates to the backport of bitcoin#15921, which introduced the separate
tx_statebut left the log readingstate. Upstream later reorderedstate.Invalid()ahead of the log, so by thenstatecarried the copied reject reason; Dash instead collapsed it into a singlereturn state.Invalid(...), which fixes the opposite ordering. Readingtx_statedirectly is the smaller fix and does not disturb the return.Split out of #7683, where it was an unrelated drive-by change in an otherwise mechanical
error(...)→LogError(...)refactor. The two branches no longer touch the same line and can land in either order.What was done?
Log
tx_state.ToString()instead ofstate.ToString()in theConnectBlockCheckTxInputsfailure path.How Has This Been Tested?
Inspection of the surrounding code path and
ValidationState::ToString()insrc/consensus/validation.h, which returns"Valid"wheneverIsValid()holds. Both variables are in scope at the call site (tx_stateis declared two lines above,stateis the function parameter), so the change is type- and scope-identical; no behavior outside the log string changes. CI covers the build and test suites.Breaking Changes
None. Log-string only; the
BlockValidationStatehanded back to the caller is unchanged.Checklist:
🤖 Generated with Claude Code