backport: bitcoin#23508, #24187, #24528, #24579, #25412 (deployment backports)#6888
backport: bitcoin#23508, #24187, #24528, #24579, #25412 (deployment backports)#6888kwvg wants to merge 6 commits intodashpay:developfrom
Conversation
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
|
This pull request has conflicts, please rebase. |
f57c351 to
ffc7fdd
Compare
|
This pull request has conflicts, please rebase. |
|
This pull request has conflicts, please rebase. |
|
This pull request has conflicts, please rebase. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review infoConfiguration used: Repository UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
WalkthroughThe changes add a new RPC getdeploymentinfo and REST endpoints (/rest/deploymentinfo and /rest/deploymentinfo/.json) to expose deployment (softfork) state at the chain tip or at a supplied block. Softfork/VersionBits logic was refactored to compute deployment state from an arbitrary blockindex via a new DeploymentInfo path and to record per-block signalling history (threading an optional signalling_blocks vector through VersionBits statistics). getblockchaininfo was updated to optionally emit legacy softforks via the new DeploymentInfo path when deprecated RPCs are enabled. Extensive test updates and REST documentation were added to use and validate the new interfaces. Sequence DiagramsequenceDiagram
participant Client as Client
participant REST as REST/RPC Handler
participant Chain as Blockchain
participant Deploy as DeploymentInfo
participant VB as VersionBits
Client->>REST: GET /rest/deploymentinfo[/{blockhash}]
REST->>Chain: Validate blockhash (optional) / lookup CBlockIndex
Chain-->>REST: CBlockIndex
REST->>Deploy: DeploymentInfo(CBlockIndex)
Deploy->>VB: GetStateStatisticsFor(CBlockIndex, &signalling_blocks)
VB-->>Deploy: BIP9Stats + signalling_blocks
Deploy-->>REST: Aggregated deployments JSON
REST-->>Client: HTTP 200 JSON {blockhash, height, deployments}
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/rpc/blockchain.cpp (1)
1456-1462:⚠️ Potential issue | 🟠 MajorRemove duplicate
min_activation_heightfield inbip9output.Line 1456 already emits
min_activation_height, and Line 1461 emits it again. This produces duplicate JSON keys in the same object, which is ambiguous for clients.Proposed fix
bip9.pushKV("timeout", chainman.GetConsensus().vDeployments[id].nTimeout); bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height); bip9.pushKV("ehf", chainman.GetConsensus().vDeployments[id].useEHF); if (auto it = signals.find(chainman.GetConsensus().vDeployments[id].bit); it != signals.end()) { bip9.pushKV("ehf_height", it->second); } - bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/rpc/blockchain.cpp` around lines 1456 - 1462, The bip9 JSON object is emitting "min_activation_height" twice (via bip9.pushKV("min_activation_height", chainman.GetConsensus().vDeployments[id].min_activation_height)); remove the duplicate pushKV call so the field is only added once; locate the repeated call near the block that also sets "ehf" and optional "ehf_height" (references: bip9.pushKV, chainman.GetConsensus().vDeployments[id].min_activation_height, signals) and delete the second occurrence to avoid duplicate JSON keys.test/functional/rpc_blockchain.py (1)
194-252:⚠️ Potential issue | 🟡 MinorFix Flake8 E121 — continuation line under-indented for hanging indent (Line 198)
The dict literal passed to
assert_equalstarting at Line 197 has inconsistent hanging indent, triggering Flake8 E121.🔧 Proposed fix
- assert_equal(gdi_result, { - "hash": blockhash, - "height": height, - "deployments": { + assert_equal(gdi_result, { + "hash": blockhash, + "height": height, + "deployments": {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/functional/rpc_blockchain.py` around lines 194 - 252, The dict literal in check_signalling_deploymentinfo_result passed to assert_equal has inconsistent hanging indentation causing Flake8 E121; reformat the multi-line dict so the continuation lines are aligned under the opening parenthesis (or the first key) of the assert_equal call and ensure nested dicts maintain consistent indentation; update the block inside check_signalling_deploymentinfo_result (the big "deployments" dict and its nested bip9/testdummy entries) so all continuation lines use the same indent level and closing braces line up to remove the E121 violation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/rest.cpp`:
- Around line 639-653: jsonRequest.params is created as an array
(UniValue::VARR) but the code uses pushKV("blockhash", ...) which requires an
object and will throw; change the code that adds the optional blockhash
positional RPC parameter to use jsonRequest.params.push_back(...) with the
string/hash value instead of pushKV, keeping the existing validation flow
(ParseHashStr / ParseHashV checks, chainman lookup via WITH_LOCK(::cs_main,
...)) and ensuring the RPC call to getdeploymentinfo receives the positional
argument as expected.
---
Outside diff comments:
In `@src/rpc/blockchain.cpp`:
- Around line 1456-1462: The bip9 JSON object is emitting
"min_activation_height" twice (via bip9.pushKV("min_activation_height",
chainman.GetConsensus().vDeployments[id].min_activation_height)); remove the
duplicate pushKV call so the field is only added once; locate the repeated call
near the block that also sets "ehf" and optional "ehf_height" (references:
bip9.pushKV, chainman.GetConsensus().vDeployments[id].min_activation_height,
signals) and delete the second occurrence to avoid duplicate JSON keys.
In `@test/functional/rpc_blockchain.py`:
- Around line 194-252: The dict literal in
check_signalling_deploymentinfo_result passed to assert_equal has inconsistent
hanging indentation causing Flake8 E121; reformat the multi-line dict so the
continuation lines are aligned under the opening parenthesis (or the first key)
of the assert_equal call and ensure nested dicts maintain consistent
indentation; update the block inside check_signalling_deploymentinfo_result (the
big "deployments" dict and its nested bip9/testdummy entries) so all
continuation lines use the same indent level and closing braces line up to
remove the E121 violation.
ℹ️ Review info
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
doc/REST-interface.mddoc/release-notes-6888.mdsrc/rest.cppsrc/rpc/blockchain.cppsrc/test/fuzz/rpc.cppsrc/test/fuzz/versionbits.cppsrc/versionbits.cppsrc/versionbits.htest/functional/feature_asset_locks.pytest/functional/feature_cltv.pytest/functional/feature_dersig.pytest/functional/feature_governance.pytest/functional/feature_mnehf.pytest/functional/feature_new_quorum_type_activation.pytest/functional/interface_rest.pytest/functional/rpc_blockchain.pytest/functional/test_framework/blocktools.pytest/functional/test_framework/util.pytest/functional/wallet_signrawtransactionwithwallet.py
| jsonRequest.params = UniValue(UniValue::VARR); | ||
|
|
||
| if (!hash_str.empty()) { | ||
| uint256 hash; | ||
| if (!ParseHashStr(hash_str, hash)) { | ||
| return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hash_str); | ||
| } | ||
|
|
||
| const ChainstateManager* chainman = GetChainman(context, req); | ||
| if (!chainman) return false; | ||
| if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(ParseHashV(hash_str, "blockhash")))) { | ||
| return RESTERR(req, HTTP_BAD_REQUEST, "Block not found"); | ||
| } | ||
|
|
||
| jsonRequest.params.pushKV("blockhash", hash_str); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the actual code in src/rest.cpp at the specified lines
head -n 680 src/rest.cpp | tail -n 50Repository: dashpay/dash
Length of output: 1788
🏁 Script executed:
# Search for UniValue API definitions to understand pushKV behavior
fd -t f 'univalue.h' | head -5Repository: dashpay/dash
Length of output: 87
🏁 Script executed:
# Check what UniValue types are available and their methods
rg -A 20 'class UniValue' src/univalue/ 2>/dev/null | head -100Repository: dashpay/dash
Length of output: 1667
🏁 Script executed:
# Look for UniValue pushKV and push_back definitions with context
rg 'void push_back|void pushKV' src/univalue/ -A 3Repository: dashpay/dash
Length of output: 1429
🏁 Script executed:
# Check how other REST handlers use jsonRequest.params
rg -n 'jsonRequest\.params\.(push|pushKV)' src/rest.cppRepository: dashpay/dash
Length of output: 121
🏁 Script executed:
# Find pushKV implementation
rg -A 10 'void.*pushKV' src/univalue/ -m 50Repository: dashpay/dash
Length of output: 2497
🏁 Script executed:
# Find push_back implementation
rg -A 10 'void.*push_back\(' src/univalue/ | grep -v utfRepository: dashpay/dash
Length of output: 1328
🏁 Script executed:
# Check the getdeploymentinfo RPC method to see what it expects
rg -B 5 -A 15 'getdeploymentinfo\(' src/rpc/Repository: dashpay/dash
Length of output: 1380
🏁 Script executed:
# Look at other REST handlers that pass params to RPC methods to see the pattern
rg -B 3 -A 3 'jsonRequest\.params\.(push_back|pushKV)' src/rest.cpp | head -50Repository: dashpay/dash
Length of output: 279
🏁 Script executed:
# Check if there's checkType method that would fail on type mismatch
rg -B 2 -A 5 'checkType' src/univalue/lib/univalue.cpp | head -30Repository: dashpay/dash
Length of output: 626
🏁 Script executed:
# Look at other REST handlers to see how they construct params
rg -B 5 -A 10 'jsonRequest\.params = UniValue' src/rest.cppRepository: dashpay/dash
Length of output: 1270
🏁 Script executed:
# Specifically check if any other handlers use pushKV on a VARR
rg -B 10 'jsonRequest\.params.*VARR' src/rest.cpp | grep -A 10 'params = 'Repository: dashpay/dash
Length of output: 408
Use positional array argument instead of pushKV for RPC params.
jsonRequest.params is initialized as an array (VARR), but Line 653 uses pushKV(). Since pushKV() calls checkType(VOBJ) and will throw an exception when called on an array type, this breaks passing the optional blockhash parameter to the RPC handler. The getdeploymentinfo RPC expects a positional argument, so use push_back() instead.
Proposed fix
- jsonRequest.params.pushKV("blockhash", hash_str);
+ jsonRequest.params.push_back(hash_str);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| jsonRequest.params = UniValue(UniValue::VARR); | |
| if (!hash_str.empty()) { | |
| uint256 hash; | |
| if (!ParseHashStr(hash_str, hash)) { | |
| return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hash_str); | |
| } | |
| const ChainstateManager* chainman = GetChainman(context, req); | |
| if (!chainman) return false; | |
| if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(ParseHashV(hash_str, "blockhash")))) { | |
| return RESTERR(req, HTTP_BAD_REQUEST, "Block not found"); | |
| } | |
| jsonRequest.params.pushKV("blockhash", hash_str); | |
| jsonRequest.params = UniValue(UniValue::VARR); | |
| if (!hash_str.empty()) { | |
| uint256 hash; | |
| if (!ParseHashStr(hash_str, hash)) { | |
| return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hash_str); | |
| } | |
| const ChainstateManager* chainman = GetChainman(context, req); | |
| if (!chainman) return false; | |
| if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(ParseHashV(hash_str, "blockhash")))) { | |
| return RESTERR(req, HTTP_BAD_REQUEST, "Block not found"); | |
| } | |
| jsonRequest.params.push_back(hash_str); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/rest.cpp` around lines 639 - 653, jsonRequest.params is created as an
array (UniValue::VARR) but the code uses pushKV("blockhash", ...) which requires
an object and will throw; change the code that adds the optional blockhash
positional RPC parameter to use jsonRequest.params.push_back(...) with the
string/hash value instead of pushKV, keeping the existing validation flow
(ParseHashStr / ParseHashV checks, chainman lookup via WITH_LOCK(::cs_main,
...)) and ensuring the RPC call to getdeploymentinfo receives the positional
argument as expected.
Additional Information
Depends on backport: merge bitcoin#23345, #24410, #15936, #25748, #25863, #24051, #25315, #26624, #26894, #26673, #24462, #25815, #22949, #26723, #23395, #27016, #27189, #27317 (auxiliary backports: part 28) #6901
Depends on backport: merge bitcoin#24595 (move g_versionbitscache global to ChainstateManager) #6933
In bitcoin#23508,
AbstractThresholdConditionChecker::GetStateStatisticsFor()retainspindexEndOfPrevPeriodunlike upstream as it's used to calculate dynamic activation threshold (see dash#3692 for more information) but it isn't used to calculateelapsedas bitcoin#23508 no longer calculates the status of the next block but the current block, which prevents complete preservation of old logic.feature_mnehf.pyandfeature_new_quorum_type_activation.pyto mine one more block to get status information expected by the tests.Breaking Changes
Requesting deployment information from
getblockchaininfois now deprecated (replaced bygetdeploymentinfo) and restoring old behaviour will require the runtime flag-deprecatedrpc=softforks.Checklist