fix: require distinct outputs for duplicate superblock payments#7362
fix: require distinct outputs for duplicate superblock payments#7362thepastaclaw wants to merge 2 commits into
Conversation
CSuperblock::IsValid matched expected payments against txNew.vout using a forward scan that re-started at the previously matched index. Two adjacent expected payments with identical scriptPubKey and amount could both match the same coinbase output, so a superblock could shortchange payees by emitting only one of two duplicate payouts. Initialize the cursor to -1 and scan from nVoutIndex + 1 so each expected payment consumes a distinct output. Adds a unit-test regression covering both the missing-output and well-formed cases. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
|
@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 (6)
✅ Files skipped from review due to trivial changes (1)
WalkthroughThe PR extends superblock validation to enforce version-aware distinct output matching for duplicate governance payments. It adds an Sequence DiagramsequenceDiagram
participant ConnectBlock as CChainState::ConnectBlock
participant MNPayments as CMNPaymentsProcessor
participant Deployment as DeploymentActiveAfter
participant Superblock as CSuperblock::IsValid
participant Coinbase as Coinbase Tx
ConnectBlock->>MNPayments: IsBlockValueValid(block, pindexPrev, ...)
activate MNPayments
MNPayments->>Deployment: Check DEPLOYMENT_V24 active after pindexPrev
Deployment-->>MNPayments: is_v24 flag
MNPayments->>Superblock: IsValidSuperblock(..., is_v24)
activate Superblock
Superblock->>Coinbase: Search vouts with cursor init at -1
alt is_v24=true: strict distinct output matching
Coinbase-->>Superblock: Each payment matched at unique vout index
Superblock-->>MNPayments: VALID
else is_v24=false: pre-V24 behavior
Coinbase-->>Superblock: Payments matched, may reuse vouts
Superblock-->>MNPayments: VALID
end
deactivate Superblock
MNPayments-->>ConnectBlock: Validation result
deactivate MNPayments
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
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 |
The stricter rule requiring each expected superblock payment to consume a distinct coinbase output tightens consensus validation. Apply it only once DEPLOYMENT_V24 is active so all nodes flip the rule at the same height and already-validated history keeps the legacy (reuse-allowed) scan, avoiding a chain split during rollout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
✅ Review complete (commit e5895ab) |
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Tight, well-scoped fix for a superblock validation bug where two identical expected payments could match the same coinbase output. The change is correctly gated behind DEPLOYMENT_V24 to preserve historical validation, pre-V24 semantics are exactly preserved via std::max(nVoutIndex, 0), and a focused unit test covers the failing duplicate case, the valid two-output case, and the pre-V24 compatibility path. No in-scope issues.
Fix duplicate superblock payment matching
Issue being fixed or feature implemented
CSuperblock::IsValidmatched each expected superblock payment by scanningforward through the coinbase outputs, but the scan restarted at the previously
matched output index. If two adjacent expected payments had the same script and
amount, both expected payments could match the same coinbase output.
That could allow a block to include only one of two identical funded proposal
payouts while still passing validation, because the total payment cap counts
both expected payments.
What was done?
each expected payment must match a distinct coinbase output.
script and amount:
How Has This Been Tested?
Local macOS arm64 build using the existing depends config:
./autogen.sh CONFIG_SITE=.../depends/aarch64-apple-darwin/share/config.site \ ./configure --disable-bench --disable-fuzz --disable-fuzz-binary \ --disable-gui --with-incompatible-bdb --enable-suppress-external-warnings make -C src -j$(($(sysctl -n hw.ncpu) - 1)) test/test_dash ./src/test/test_dash --run_test=governance_superblock_tests \ --log_level=warning ./src/test/test_dash --run_test=governance_validators_tests \ --log_level=warningThe new regression test was also run against the original buggy scan logic,
where the one-output duplicate-payment case failed as expected, then rerun
after restoring the fix.
Pre-PR review gate:
Result:
ship.Breaking Changes
None.
Checklist
(for repository code-owners and collaborators only)