fix: validate CbTx chainlock height diff#7363
Conversation
Reject an out-of-range bestCLHeightDiff that would otherwise produce a pre-genesis ancestor height when combined with pindex->nHeight, returning state.Invalid(BLOCK_CONSENSUS, "bad-cbtx-cldiff") before any GetAncestor() lookup. The GetAncestor() result is also null-checked as defense-in-depth. CheckCbTxBestChainlock is exposed in specialtxman.h alongside the existing Check* prototypes so a focused unit test can cover the new boundary in src/test/evo_cbtx_tests.cpp. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughThis PR introduces stricter validation for the Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
|
CI note: the only red item is |
|
✅ Review complete (commit dc82f29) |
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Small, well-scoped defensive fix that closes a remote crash vector in CheckCbTxBestChainlock by rejecting out-of-range bestCLHeightDiff before calling GetAncestor(), plus a defensive null check on the returned ancestor. The boundary math is correct and the change is strictly more-rejecting, so it cannot reject any historically valid block. Two minor non-blocking observations about test coverage and reject-reason granularity.
🟡 1 suggestion(s) | 💬 1 nitpick(s)
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `src/test/evo_cbtx_tests.cpp`:
- [SUGGESTION] src/test/evo_cbtx_tests.cpp:56-62: Defensive GetAncestor() null-check branch is not exercised
Both test cases set bestCLHeightDiff to nHeight (5) and uint32_max, so both trip the range check at specialtxman.cpp:77 and return before the new `if (pAncestor == nullptr)` branch at specialtxman.cpp:89 is reached. The commit message highlights the null check as an intentional defense, but from the unit test's perspective that branch is currently unexercised. A case with `bestCLHeightDiff = nHeight - 1` on a standalone CBlockIndex (pprev == nullptr) would pass the range check, compute curBlockCoinbaseCLHeight = 0, and drive GetAncestor() down a chain it cannot walk, covering the defensive path.
There was a problem hiding this comment.
Code Review
Small, well-scoped consensus-safety fix in CheckCbTxBestChainlock that rejects an out-of-range bestCLHeightDiff before it can produce a pre-genesis ancestor height, plus the defensive null check after GetAncestor() and a focused unit test for the boundary. Current head (dc82f29) addresses prior review nits by renaming the defensive reject reason to bad-cbtx-cldiff-ancestor and documenting why that branch is unreachable from a unit test. No in-scope code defects at this SHA; only a minor commit-history suggestion remains.
💬 1 nitpick(s)
Non-inline nitpick — Squash dc82f29 into 7312fff (or reword its subject)
dc82f29 only touches lines introduced one commit earlier by 7312fff: it renames the defensive reject reason from bad-cbtx-cldiff to bad-cbtx-cldiff-ancestor in src/evo/specialtxman.cpp and adds explanatory comments there and in the new unit test. Functionally this is the final shape of the original fix split across two commits, with the follow-up carrying a test: prefix even though it changes a production consensus-validation reject string in specialtxman.cpp. Since Dash Core preserves PR commits when merging via Merge #NNNN, leaving the split means git bisect/git blame for the reject string lands on a commit whose subject advertises only test changes. Recommend git rebase -i --autosquash (mark dc82f29 as fixup!) to fold it into 7312fff; if the split is intentionally preserved, reword its subject to something like evo: distinguish bad-cbtx-cldiff-ancestor reject reason and describe the rename in the body.
|
CI follow-up on the current red checks:
Leaving the branch unchanged: this does not appear to be an application/test regression in the CbTx height-diff validation change, and I am not going to force-push/no-op rebase just to churn CI. |
Issue being fixed or feature implemented
CheckCbTxBestChainlockderived an ancestor height frombestCLHeightDiffwithout first ensuring the derived height was in range. This PR adds an
explicit consensus rejection for out-of-range CbTx chainlock height diffs before
ancestor lookup.
What was done?
bestCLHeightDiffbefore deriving and using the referenced chainlockancestor height.
bad-cbtx-cldifffor out-of-range values.evo_cbtx_testssuite.How Has This Been Tested?
Tested locally on macOS arm64:
Results:
Pre-PR review gate:
Result:
ship.Breaking Changes
None expected. This only rejects malformed CbTx chainlock metadata that
references an invalid ancestor height.
Checklist