Skip to content

Conversation

kwvg
Copy link
Collaborator

@kwvg kwvg commented Oct 17, 2025

Additional Information

  • Dependency for backport: merge bitcoin#24595, 25830 (deployment backports) #6888

  • Dependency for backport: merge bitcoin#25065, #25290, #25494, #25439, #25648, #25772, #25222 (kernel backports: part 1) #6904

  • The help text for getblockchaininfo['softforks'] was introduced in bitcoin#16060 (backported in dash#5255) but the RPCResult help text was introduced in bitcoin#17809, backported before bitcoin#16060. This resulted in the help text for softforks deviating from upstream without the output to match (which is aligned with upstream).

    This has since been resolved as the output structure hasn't changed, only the help text.

  • bitcoin#22818 (backported in dash#6214) activated many softforks at height 1, which rendered the block generation calls in wallet_signrawtransactionwithwallet.py (source) no longer necessary, additionally bitcoin#22550 (backported in dash#6189) added assertions to validate CSV/CLTV activation that were not included in the backport.
    This has since been resolved, replacing the generate calls with assertions.

    • The locktime height was dropped from 1000 to 100 (matching with upstream, source) as we are no longer generating enough blocks to reach that height anymore.
  • In bitcoin#23508, AbstractThresholdConditionChecker::GetStateStatisticsFor() retains pindexEndOfPrevPeriod unlike upstream as it's used to calculate dynamic activation threshold (see dash#3692 for more information) but it isn't used to calculate elapsed as bitcoin#23508 no longer calculates the status of the next block but the current block, which prevents complete preservation of old logic.

    • Due to this change in behavior, test adjustments were necessary in feature_mnehf.py and feature_new_quorum_type_activation.py to mine one more block to get status information expected by the tests.
  • bitcoin#24595 is partial as Dash uses DeploymentActive{After,At}() more extensively than upstream, it is completed in dash#6888 after all Dash-specific usage is migrated over.

  • The minimum acceptable prune height in bitcoin#25315 is higher than upstream (945 vs 550) because minimum height is calculated using MIN_DISK_SPACE_FOR_BLOCK_FILES which was bumped in dash#1621, this has been reflected in functional tests.

Breaking Changes

Requesting deployment information from getblockchaininfo is now deprecated (replaced by getdeploymentinfo) and restoring old behaviour will require the runtime flag -deprecatedrpc=softforks.

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas (note: N/A)
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@kwvg kwvg added this to the 23 milestone Oct 17, 2025
Copy link

github-actions bot commented Oct 17, 2025

⚠️ Potential Merge Conflicts Detected

This PR has potential conflicts with the following open PRs:

Please coordinate with the authors of these PRs to avoid merge conflicts.

Copy link

This pull request has conflicts, please rebase.

@kwvg kwvg changed the title backport: merge bitcoin#23345, #23508, #24187, #24528, #24579, #24410, #15936, #25748, #25863, #24051, #25315, #26624, #26894, partial bitcoin#24595 (auxiliary backports: part 28) backport: merge bitcoin#23345, #23508, #24187, #24528, #24579, #24410, #15936, #25748, #25863, #24051, #25315, #26624, #26894, #25412, partial bitcoin#24595 (auxiliary backports: part 28) Oct 18, 2025
@kwvg kwvg marked this pull request as ready for review October 21, 2025 09:50
Copy link

coderabbitai bot commented Oct 21, 2025

Walkthrough

The patch moves coinstats APIs from node:: to kernel:: (types CCoinsStats, CoinStatsHashType) and introduces ComputeUTXOStats returning std::optional. CoinStatsIndex::LookUpStats now returns an optional. ChainstateManager now stores CChainParams, its constructor requires const CChainParams&, and several validation/block-processing APIs (AcceptBlockHeader, ProcessNewBlockHeaders, ProcessNewBlock, contextual checks, deployment helpers) were changed to use ChainstateManager rather than passing Params. A new getdeploymentinfo RPC and /rest/deploymentinfo REST endpoints were added. Settings persistence APIs and helpers were extended (ArgsManager, util::settings), FlatSigningProvider::Merge became an in-place member, many call sites and tests updated, and numerous signature changes propagated across rpc, validation, index, kernel, util, and test code.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.97% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title identifies this as a collection of Bitcoin backports (specifically backports 23345, 23508, 24187, 24528, 24579, 24410, 15936, 25748, 25863, 24051, 25315, 26624, 26894, 25412, and partial 24595), designated as "auxiliary backports: part 28." The raw summary confirms these backports address major changes including deployment info/softfork refactoring, coinstats namespace migration, chain parameter handling updates, RPC enhancements, and test adjustments. While the title is somewhat lengthy with multiple PR references, it is specific and directly related to the primary purpose of the changeset—merging a series of upstream Bitcoin backports with Dash-specific adaptations.
Description Check ✅ Passed The pull request description provides comprehensive context directly related to the changeset. It includes sections explaining dependencies, reconciliation of backport ordering, specific test adjustments and their rationale, partial backport decisions with deferred completion, adjustments to prune height due to Dash-specific constants, breaking changes (deprecation of softforks in getblockchaininfo), and a self-review checklist confirming testing and documentation updates. The description is neither vague nor off-topic; it thoroughly documents the reasoning behind changes and provides meaningful information about how Dash's backports differ from upstream Bitcoin.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
test/functional/rpc_blockchain.py (1)

192-251: Fix flake8 E121: continuation indent in assert_equal block

Indent the dict to align with the opening parenthesis to satisfy E121 and improve readability.

Apply this minimal reformat:

-    def check_signalling_deploymentinfo_result(self, gdi_result, height, blockhash, status_next):
+    def check_signalling_deploymentinfo_result(self, gdi_result, height, blockhash, status_next):
         assert height >= 144 and height <= 287
-
-        assert_equal(gdi_result, {
-          "hash": blockhash,
-          "height": height,
-          "deployments": {
+        assert_equal(
+            gdi_result,
+            {
+                "hash": blockhash,
+                "height": height,
+                "deployments": {
                 'bip34': {'type': 'buried', 'active': True, 'height': 2},
                 'bip66': {'type': 'buried', 'active': True, 'height': 3},
                 'bip65': {'type': 'buried', 'active': True, 'height': 4},
                 'csv': {'type': 'buried', 'active': True, 'height': 5},
                 'bip147': {'type': 'buried', 'active': True, 'height': 6},
                 'dip0001': { 'type': 'buried', 'active': True, 'height': 10},
                 'dip0003': { 'type': 'buried', 'active': False, 'height': 411},
                 'dip0008': { 'type': 'buried', 'active': True, 'height': 12},
                 'dip0020': { 'type': 'buried', 'active': True, 'height': 1},
                 'dip0024': { 'type': 'buried', 'active': True, 'height': 13},
                 'realloc': { 'type': 'buried', 'active': True, 'height': 14},
                 'v19': { 'type': 'buried', 'active': True, 'height': 15},
                 'v20': { 'type': 'buried', 'active': False, 'height': 412},
                 'mn_rr': { 'type': 'buried', 'active': False, 'height': 413},
                 'withdrawals': { 'type': 'buried', 'active': False, 'height': 600},
                 'v24': {
                     'type': 'bip9',
                     'bip9': {
                         'start_time': 0,
                         'timeout': 9223372036854775807,  # "v24" does not have a timeout so is set to the max int64 value
                         'min_activation_height': 0,
-                    'since': 0,
-                    'status': 'defined',
-                    'status_next': 'defined',
-                    'ehf': True,
+                        'since': 0,
+                        'status': 'defined',
+                        'status_next': 'defined',
+                        'ehf': True,
                     },
-                'active': False
+                    'active': False
                 },
                 'testdummy': {
                     'type': 'bip9',
                     'bip9': {
                         'bit': 28,
                         'start_time': 0,
                         'timeout': 9223372036854775807,  # testdummy does not have a timeout so is set to the max int64 value
-                    'min_activation_height': 0,
+                        'min_activation_height': 0,
                         'since': 144,
-                    'status': 'started',
-                    'status_next': status_next,
+                        'status': 'started',
+                        'status_next': status_next,
                         'statistics': {
                             'period': 144,
                             'threshold': 108,
-                        'elapsed': height - 143,
-                        'count': height - 143,
+                            'elapsed': height - 143,
+                            'count': height - 143,
                             'possible': True,
                         },
                         'ehf': False,
-                    'signalling': '#'*(height-143),
+                        'signalling': '#'*(height-143),
                     },
-                'active': False
+                    'active': False
                 }
-          }
-        })
+            },
+        )
src/init.cpp (1)

834-846: Do not hold cs_main while computing full UTXO stats (severe contention risk).

WITH_LOCK wraps the entire GetUTXOStats call, which can scan the whole UTXO DB when the coinstats index is unavailable. This holds cs_main for a long time, stalling validation, p2p, and RPC paths.

Apply this change to lock only for grabbing the view pointer, then compute without cs_main:

-    const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true));
+    CCoinsViewDB* coins_db = nullptr;
+    {
+        LOCK(::cs_main);
+        coins_db = &chainman.ActiveChainstate().CoinsDB();
+    }
+    // Let GetUTXOStats/ComputeUTXOStats resolve the best block internally; pass nullptr for pindex.
+    const auto maybe_stats = GetUTXOStats(
+        coins_db, chainman.m_blockman,
+        /*hash_type=*/CoinStatsHashType::NONE,
+        node.rpc_interruption_point,
+        /*pindex=*/nullptr,
+        /*index_requested=*/true);

Optional: if you need an explicit height for gauges, snapshot it under cs_main separately and only for reading scalar fields.

src/kernel/coinstats.cpp (1)

56-66: Serialization bug in ApplyHash(CHashWriter&): ternary precedence is wrong.

The expression writes 1 or 0 depending on (height2 + coinbase) rather than (height2 + (coinbase ? 1 : 0)). This corrupts the legacy serialized hash commitment.

Fix the precedence:

-            ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
+            ss << VARINT(it->second.nHeight * 2 + (it->second.fCoinBase ? 1u : 0u));

This matches upstream intent and preserves UTXO snapshot/assumeutxo commitments.

src/validation.h (1)

101-110: Updated MIN_DISK_SPACE_FOR_BLOCK_FILES — OK; minor doc nit

Value raised to 945 MiB fits Dash’s larger block/undo assumptions. Doc string has “2B MiB” (typo). Consider “2 MiB”.

-// At 2B MiB per block, 288 blocks = 576 MiB.
+// At 2 MiB per block, 288 blocks = 576 MiB.
🧹 Nitpick comments (25)
test/functional/wallet_crosschain.py (1)

68-69: LGTM! Teardown logic correctly handles descriptor and pruning state.

The conditional stderr handling properly accounts for which nodes are running with pruning enabled based on the descriptor test path.

The condition could be slightly simplified for readability:

-        self.nodes[idx].stop_node(expected_stderr=EXPECTED_STDERR_NO_GOV_PRUNE if not self.options.descriptors or (self.options.descriptors and idx == 1) else "")
+        self.nodes[idx].stop_node(expected_stderr=EXPECTED_STDERR_NO_GOV_PRUNE if (not self.options.descriptors or idx == 1) else "")
src/script/signingprovider.h (1)

9-9: Merge API with LIFETIMEBOUND is solid; verified no leftover free function calls.

The new FlatSigningProvider& Merge(FlatSigningProvider&&) member function is properly implemented. Verification confirms no calls to the old free Merge(a, b) function remain in the codebase.

Optional suggestion: Consider adding a const FlatSigningProvider& overload for ergonomics when merging lvalues without requiring an explicit temporary at the call site.

src/util/settings.cpp (1)

180-182: Non‑persistent sources correctly skipped. Add tests for CLI/forced cases.

Skipping COMMAND_LINE and FORCED when ignore_nonpersistent=true matches the intent. Please add a unit test covering both CLI and forced overrides to lock this behavior in.

I can supply a test diff in settings_tests exercising ignore_nonpersistent=true for both sources.

src/test/settings_tests.cpp (1)

109-116: Exercise ignore_nonpersistent=true in tests.

Current tests pass false; add one that asserts CLI/forced are ignored when true.

Apply this minimal test addition:

@@
 BOOST_FIXTURE_TEST_SUITE(settings_tests, BasicTestingSetup)
@@
 static void CheckValues(const util::Settings& settings, const std::string& single_val, const std::string& list_val)
 {
-    util::SettingsValue single_value = GetSetting(settings, "section", "name", false, false, false);
+    util::SettingsValue single_value = GetSetting(settings, "section", "name", false, false, false);
@@
 };
 
+BOOST_AUTO_TEST_CASE(NonPersistentIgnored)
+{
+    util::Settings settings;
+    // Non-persistent sources
+    settings.forced_settings["name"] = "forced";
+    settings.command_line_options["name"].push_back("cli");
+    // Persistent sources
+    settings.ro_config["section"]["name"].push_back("cfg");
+    settings.rw_settings["name"] = "rw";
+    // With ignore_nonpersistent=true we should prefer persistent sources
+    auto v = GetSetting(settings, "section", "name",
+                        /*ignore_default_section_config=*/false,
+                        /*ignore_nonpersistent=*/true,
+                        /*get_chain_name=*/false);
+    BOOST_CHECK_EQUAL(v.write(), R"("rw")");
+}
+
 BOOST_AUTO_TEST_CASE(Simple)
src/interfaces/node.h (1)

197-214: Doc nit: s/bitcoin.conf/dash.conf/.

Adjust comment to reflect Dash config filename.

Apply:

-    //! Return setting value from <datadir>/settings.json or bitcoin.conf.
+    //! Return setting value from <datadir>/settings.json or dash.conf.
src/node/interfaces.cpp (3)

447-456: Consider forced overrides in ignore check (or clarify doc).

isSettingIgnored() flags CLI overrides only. If forced_settings should also shadow settings.json, include them here or explicitly state CLI‑only in the interface docs.

Example:

 gArgs.LockSettings([&](util::Settings& settings) {
-    if (auto* options = util::FindKey(settings.command_line_options, name)) {
-        ignored = !options->empty();
-    }
+    if (const auto* options = util::FindKey(settings.command_line_options, name)) {
+        ignored |= !options->empty();
+    }
+    if (const auto* forced = util::FindKey(settings.forced_settings, name)) {
+        ignored |= !forced->isNull();
+    }
 });

457-468: updateRwSetting: consider surfacing write failure.

Method returns void; if WriteSettingsFile() fails, caller can’t react. Optional: return bool or log on failure.


479-486: Race condition confirmed: Between backup and clear, other writers can mutate settings.

The race window is real. LockSettings acquires cs_args only during its callback, and WriteSettingsFile also acquires cs_args internally. In resetSettings(), the first WriteSettingsFile(backup=true) releases cs_args before LockSettings([&](util::Settings& settings) { settings.rw_settings.clear(); }) acquires it again, allowing concurrent writes to mutate the settings file between backup and clear.

This differs from the pattern in updateRwSetting(), which wraps both the modification and write within a single LockSettings call, preventing the gap.

Risk is low since resetSettings() is unlikely called concurrently with other setting updates, and the backup becomes stale but causes no data corruption. However, to eliminate the race entirely and match the safer pattern used in updateRwSetting(), consider adding a higher-level ResetSettings() helper on ArgsManager that performs backup, clear, and write within a single cs_args acquisition.

src/util/system.cpp (5)

562-575: Backup path toggle looks correct; confirm intent (writes to .bak only).

backup appends “.bak” and affects the single computed path. Together with the temp suffix this yields settings.json.bak.tmpsettings.json.bak. If the intent was to write both primary and backup in one operation (“alongside” per PR text), callers must invoke writes twice or a wrapper should handle both. Recommend clarifying in the header comment and adding a convenience wrapper if dual-write is desired.


611-629: Write-to-backup behavior is explicit; consider optional wrapper for dual-write.

WriteSettingsFile(..., /*backup=*/true) persists only the backup file. If you want automatic “write primary then backup”, consider a small wrapper to call this twice or to copy the just-written primary to *.bak. Otherwise, document that callers must opt-in and call it explicitly.


649-653: SettingToString mirrors historical coercion.

Numeric via getValStr, bools to "0"/"1", else get_str(). Consider a brief doc comment noting these rules for future readers.


660-664: SettingToInt is consistent; minor doc nit.

Semantics match prior code. Optionally document overflow/invalid string behavior (Atoi→0).


671-675: SettingToBool behavior matches InterpretBool.

All good. Optional: add a note that non-numeric strings (e.g., "true"/"false") map to false per legacy rules.

src/util/system.h (3)

177-180: Helper prototypes added; consider namespacing or brief docs.

Exposing SettingTo* globally is fine; optionally place in a namespace or add short comments describing coercion rules.


483-487: WriteSettingsFile(..., bool backup) doc could be crisper.

Current wording (“or backup settings file”) matches behavior; consider stating that backup=true writes only the backup file.


488-493: GetPersistentSetting API addition LGTM.

Docstring clearly states exclusion of nonpersistent values. Consider [[nodiscard]] to encourage use of the result.

doc/REST-interface.md (1)

88-96: Fix heading style (MD003) and consider noting both accepted paths.

  • markdownlint flags “#### Deployment info”. Switch to setext style or align with the file’s convention to silence MD003.
  • The handler accepts both “/rest/deploymentinfo” and “/rest/deploymentinfo/”. Optionally document both to avoid ambiguity.

Apply one of:

-#### Deployment info
+Deployment info
+---------------

or keep ATX everywhere and adjust markdownlint config/rule for this doc.

src/test/util/setup_common.cpp (1)

482-483: Check ProcessNewBlock result to surface failures in tests.

The return value is ignored. Assert or throw on failure to make test failures explicit.

Apply:

-    Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, true, nullptr);
+    const bool accepted = Assert(m_node.chainman)->ProcessNewBlock(shared_pblock, /*force_processing=*/true, /*new_block=*/nullptr);
+    Assert(accepted);
src/rpc/mining.cpp (1)

134-139: Minor: avoid copying CChainParams.

Prefer a reference to Params() to skip an unnecessary copy.

Apply:

-    CChainParams chainparams(Params());
+    const CChainParams& chainparams = Params();
src/init.cpp (1)

834-846: Avoid heavy fallback when coinstatsindex is off (reduce periodic load).

PeriodicStats will iterate the entire UTXO set if the index is disabled. Consider skipping UTXO gauges (or sampling) unless g_coin_stats_index is available, to avoid I/O hotspots during runtime stats collection.

src/validation.cpp (5)

353-353: GetBlockScriptFlags now depends on ChainstateManager — add a precondition

The refactor is correct. Add an explicit precondition check to avoid accidental nullptr deref when called early (e.g., before tip exists).

Apply this diff:

 static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const ChainstateManager& chainman)
 {
+    assert(pindex != nullptr);
     unsigned int flags = SCRIPT_VERIFY_NONE;

Please confirm no call sites can pass nullptr. See follow-up script below to scan for usage contexts.

Also applies to: 2156-2185


1000-1005: Defensive guard if tip is not yet set in mempool path

Rare, but during early startup Tip() can be nullptr. Guard to a safe default to prevent UB.

-    unsigned int currentBlockScriptVerifyFlags{GetBlockScriptFlags(m_active_chainstate.m_chain.Tip(), m_active_chainstate.m_chainman)};
+    const CBlockIndex* tip = m_active_chainstate.m_chain.Tip();
+    const unsigned int currentBlockScriptVerifyFlags =
+        tip ? GetBlockScriptFlags(tip, m_active_chainstate.m_chainman)
+            : STANDARD_SCRIPT_VERIFY_FLAGS;

3991-4011: ContextualCheckBlockHeader refactor is sound; tweak log

  • Using blockman for checkpoints and chainman for consensus/time/PoW is the right split.
  • Minor: the “time-too-new” debug string still hardcodes “+ 2 * 60 * 60”. Prefer reflecting MAX_FUTURE_BLOCK_TIME to avoid drift.
-    return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", strprintf("block timestamp too far in the future %d %d", block.GetBlockTime(), nAdjustedTime + 2 * 60 * 60));
+    return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new",
+                         strprintf("block timestamp too far in the future %d %d",
+                                   block.GetBlockTime(), nAdjustedTime + MAX_FUTURE_BLOCK_TIME));

Also applies to: 4019-4020, 4035-4038


4251-4274: Header processing progress log: clamp to avoid >100% or negatives

blocks_left can be negative if clocks are skewed; clamp and guard divide-by-zero.

-            const int64_t blocks_left{(GetTime() - last_accepted.GetBlockTime()) / GetConsensus().nPowTargetSpacing};
-            const double progress{100.0 * last_accepted.nHeight / (last_accepted.nHeight + blocks_left)};
+            const int64_t spacing = std::max<int64_t>(1, GetConsensus().nPowTargetSpacing);
+            const int64_t delta = GetTime() - last_accepted.GetBlockTime();
+            const int64_t blocks_left = std::max<int64_t>(0, delta / spacing);
+            const double denom = std::max<int64_t>(1, last_accepted.nHeight + blocks_left);
+            const double progress = std::clamp(100.0 * last_accepted.nHeight / denom, 0.0, 100.0);

5764-5773: Snapshot validation via kernel ComputeUTXOStats — nice

  • Using kernel::ComputeUTXOStats with HASH_SERIALIZED and comparing against ExpectedAssumeutxo is correct.
  • Optional: avoid file-scope usings to reduce namespace pollution; call with fully-qualified names.
-using kernel::CCoinsStats;
-using kernel::CoinStatsHashType;
-using kernel::ComputeUTXOStats;
...
-const std::optional<CCoinsStats> maybe_stats = ComputeUTXOStats(CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, breakpoint_fnc);
+const std::optional<kernel::CCoinsStats> maybe_stats =
+    kernel::ComputeUTXOStats(kernel::CoinStatsHashType::HASH_SERIALIZED,
+                             snapshot_coinsdb, m_blockman, breakpoint_fnc);

Also applies to: 5879-5880, 5887-5889

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be20db0 and 908eb3d.

📒 Files selected for processing (59)
  • configure.ac (1 hunks)
  • doc/REST-interface.md (1 hunks)
  • doc/release-notes-6901.md (1 hunks)
  • src/Makefile.am (3 hunks)
  • src/index/coinstatsindex.cpp (2 hunks)
  • src/index/coinstatsindex.h (2 hunks)
  • src/init.cpp (4 hunks)
  • src/interfaces/node.h (2 hunks)
  • src/kernel/coinstats.cpp (5 hunks)
  • src/kernel/coinstats.h (3 hunks)
  • src/net_processing.cpp (4 hunks)
  • src/node/interfaces.cpp (1 hunks)
  • src/rest.cpp (2 hunks)
  • src/rpc/blockchain.cpp (15 hunks)
  • src/rpc/blockchain.h (3 hunks)
  • src/rpc/mining.cpp (3 hunks)
  • src/rpc/util.h (0 hunks)
  • src/script/descriptor.cpp (1 hunks)
  • src/script/signingprovider.cpp (1 hunks)
  • src/script/signingprovider.h (2 hunks)
  • src/test/blockfilter_index_tests.cpp (4 hunks)
  • src/test/coinstatsindex_tests.cpp (3 hunks)
  • src/test/descriptor_tests.cpp (5 hunks)
  • src/test/evo_deterministicmns_tests.cpp (9 hunks)
  • src/test/fuzz/coins_view.cpp (0 hunks)
  • src/test/fuzz/rpc.cpp (1 hunks)
  • src/test/fuzz/utxo_snapshot.cpp (1 hunks)
  • src/test/fuzz/versionbits.cpp (4 hunks)
  • src/test/miner_tests.cpp (1 hunks)
  • src/test/settings_tests.cpp (3 hunks)
  • src/test/util/mining.cpp (1 hunks)
  • src/test/util/setup_common.cpp (3 hunks)
  • src/test/validation_block_tests.cpp (4 hunks)
  • src/test/validation_chainstate_tests.cpp (1 hunks)
  • src/util/settings.cpp (2 hunks)
  • src/util/settings.h (1 hunks)
  • src/util/system.cpp (6 hunks)
  • src/util/system.h (2 hunks)
  • src/validation.cpp (28 hunks)
  • src/validation.h (8 hunks)
  • src/versionbits.cpp (3 hunks)
  • src/versionbits.h (2 hunks)
  • src/wallet/rpc/spend.cpp (1 hunks)
  • src/wallet/scriptpubkeyman.cpp (3 hunks)
  • test/functional/feature_asset_locks.py (1 hunks)
  • test/functional/feature_cltv.py (1 hunks)
  • test/functional/feature_dersig.py (1 hunks)
  • test/functional/feature_governance.py (5 hunks)
  • test/functional/feature_mnehf.py (2 hunks)
  • test/functional/feature_new_quorum_type_activation.py (1 hunks)
  • test/functional/interface_rest.py (1 hunks)
  • test/functional/p2p_dos_header_tree.py (4 hunks)
  • test/functional/rpc_blockchain.py (4 hunks)
  • test/functional/test_framework/blocktools.py (1 hunks)
  • test/functional/test_framework/util.py (1 hunks)
  • test/functional/wallet_crosschain.py (3 hunks)
  • test/functional/wallet_importdescriptors.py (1 hunks)
  • test/functional/wallet_signrawtransactionwithwallet.py (2 hunks)
  • test/lint/lint-circular-dependencies.py (1 hunks)
💤 Files with no reviewable changes (2)
  • src/rpc/util.h
  • src/test/fuzz/coins_view.cpp
🧰 Additional context used
📓 Path-based instructions (4)
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/interface_rest.py
  • test/functional/feature_governance.py
  • test/functional/p2p_dos_header_tree.py
  • test/functional/feature_cltv.py
  • test/functional/feature_asset_locks.py
  • test/functional/rpc_blockchain.py
  • test/functional/feature_new_quorum_type_activation.py
  • test/functional/wallet_importdescriptors.py
  • test/functional/wallet_signrawtransactionwithwallet.py
  • test/functional/test_framework/blocktools.py
  • test/functional/feature_dersig.py
  • test/functional/wallet_crosschain.py
  • test/functional/feature_mnehf.py
  • test/functional/test_framework/util.py
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/script/descriptor.cpp
  • src/test/fuzz/utxo_snapshot.cpp
  • src/test/util/mining.cpp
  • src/test/evo_deterministicmns_tests.cpp
  • src/index/coinstatsindex.h
  • src/versionbits.h
  • src/test/miner_tests.cpp
  • src/wallet/scriptpubkeyman.cpp
  • src/test/fuzz/versionbits.cpp
  • src/script/signingprovider.h
  • src/script/signingprovider.cpp
  • src/util/system.h
  • src/versionbits.cpp
  • src/util/settings.cpp
  • src/interfaces/node.h
  • src/rpc/blockchain.h
  • src/rpc/mining.cpp
  • src/wallet/rpc/spend.cpp
  • src/util/settings.h
  • src/test/validation_block_tests.cpp
  • src/rest.cpp
  • src/test/fuzz/rpc.cpp
  • src/validation.h
  • src/init.cpp
  • src/index/coinstatsindex.cpp
  • src/test/blockfilter_index_tests.cpp
  • src/test/descriptor_tests.cpp
  • src/kernel/coinstats.h
  • src/test/coinstatsindex_tests.cpp
  • src/test/validation_chainstate_tests.cpp
  • src/validation.cpp
  • src/net_processing.cpp
  • src/util/system.cpp
  • src/node/interfaces.cpp
  • src/test/util/setup_common.cpp
  • src/kernel/coinstats.cpp
  • src/test/settings_tests.cpp
  • src/rpc/blockchain.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/fuzz/utxo_snapshot.cpp
  • src/test/util/mining.cpp
  • src/test/evo_deterministicmns_tests.cpp
  • src/test/miner_tests.cpp
  • src/test/fuzz/versionbits.cpp
  • src/test/validation_block_tests.cpp
  • src/test/fuzz/rpc.cpp
  • src/test/blockfilter_index_tests.cpp
  • src/test/descriptor_tests.cpp
  • src/test/coinstatsindex_tests.cpp
  • src/test/validation_chainstate_tests.cpp
  • src/test/util/setup_common.cpp
  • src/test/settings_tests.cpp
doc/**

📄 CodeRabbit inference engine (CLAUDE.md)

Unless specifically prompted, avoid making changes to the doc directory (documentation)

Files:

  • doc/REST-interface.md
  • doc/release-notes-6901.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
🧬 Code graph analysis (38)
test/functional/interface_rest.py (2)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
test/functional/feature_governance.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/util/mining.cpp (2)
src/node/interfaces.cpp (9)
  • Assert (92-92)
  • Assert (93-93)
  • Assert (117-117)
  • Assert (259-259)
  • Assert (282-282)
  • Assert (404-404)
  • Assert (653-656)
  • Assert (865-865)
  • Assert (1171-1174)
src/node/miner.h (1)
  • node (40-77)
test/functional/feature_cltv.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
test/functional/feature_asset_locks.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/index/coinstatsindex.h (2)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/index/coinstatsindex.cpp (2)
  • LookUpStats (319-344)
  • LookUpStats (319-319)
src/versionbits.h (2)
src/versionbits.cpp (18)
  • GetStateStatisticsFor (134-180)
  • GetStateStatisticsFor (134-134)
  • pindex (258-261)
  • pindex (258-258)
  • params (227-227)
  • params (227-227)
  • params (243-243)
  • params (243-243)
  • params (244-244)
  • params (244-244)
  • params (245-245)
  • params (245-245)
  • params (246-256)
  • params (246-246)
  • params (265-265)
  • params (265-265)
  • Statistics (276-280)
  • Statistics (276-276)
src/test/fuzz/versionbits.cpp (12)
  • pindex (45-45)
  • pindex (45-45)
  • pindex (47-47)
  • pindex (47-47)
  • pindex (55-55)
  • pindex (55-55)
  • pindex (63-63)
  • pindex (63-63)
  • params (46-46)
  • params (46-46)
  • params (48-48)
  • params (48-48)
test/functional/rpc_blockchain.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (4)
  • getblockchaininfo (1501-1588)
  • getblockchaininfo (1501-1501)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/miner_tests.cpp (1)
src/node/interfaces.cpp (11)
  • Assert (92-92)
  • Assert (93-93)
  • Assert (117-117)
  • Assert (259-259)
  • Assert (282-282)
  • Assert (404-404)
  • Assert (653-656)
  • Assert (865-865)
  • Assert (1171-1174)
  • m_node (1082-1086)
  • m_node (1087-1091)
test/functional/feature_new_quorum_type_activation.py (1)
test/functional/test_framework/test_framework.py (1)
  • no_op (803-804)
src/test/fuzz/versionbits.cpp (1)
src/versionbits.cpp (4)
  • pindex (258-261)
  • pindex (258-258)
  • GetStateStatisticsFor (134-180)
  • GetStateStatisticsFor (134-134)
src/script/signingprovider.h (1)
src/script/signingprovider.cpp (2)
  • Merge (58-65)
  • Merge (58-58)
src/script/signingprovider.cpp (1)
src/script/descriptor.cpp (11)
  • scripts (759-764)
  • scripts (759-759)
  • pubkeys (512-512)
  • keys (712-712)
  • keys (712-712)
  • keys (723-728)
  • keys (723-723)
  • keys (742-749)
  • keys (742-742)
  • keys (780-793)
  • keys (780-780)
src/util/system.h (2)
src/util/system.cpp (14)
  • SettingToString (649-652)
  • SettingToString (649-649)
  • SettingToInt (660-663)
  • SettingToInt (660-660)
  • SettingToBool (671-674)
  • SettingToBool (671-671)
  • GetSettingsPath (562-575)
  • GetSettingsPath (562-562)
  • ReadSettingsFile (588-609)
  • ReadSettingsFile (588-588)
  • WriteSettingsFile (611-629)
  • WriteSettingsFile (611-611)
  • GetPersistentSetting (631-636)
  • GetPersistentSetting (631-631)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
test/functional/wallet_signrawtransactionwithwallet.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/versionbits.cpp (2)
src/validation.cpp (14)
  • pindex (2141-2141)
  • pindex (2141-2141)
  • pindex (2145-2151)
  • pindex (2145-2145)
  • pindex (3067-3074)
  • pindex (3067-3067)
  • params (2139-2139)
  • params (2139-2139)
  • params (2140-2140)
  • params (2140-2140)
  • params (2142-2142)
  • params (2142-2142)
  • params (2143-2143)
  • params (2143-2143)
src/test/fuzz/versionbits.cpp (15)
  • pindex (45-45)
  • pindex (45-45)
  • pindex (47-47)
  • pindex (47-47)
  • pindex (55-55)
  • pindex (55-55)
  • pindex (63-63)
  • pindex (63-63)
  • params (46-46)
  • params (46-46)
  • params (48-48)
  • params (48-48)
  • params (49-49)
  • params (49-49)
  • params (50-50)
src/interfaces/node.h (2)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
src/util/settings.h (1)
  • util (16-112)
src/rpc/blockchain.h (2)
src/kernel/coinstats.h (2)
  • CoinStatsHashType (23-76)
  • node (18-20)
src/rpc/blockchain.cpp (3)
  • GetUTXOStats (1106-1129)
  • GetUTXOStats (1106-1110)
  • view (1340-1340)
test/functional/test_framework/blocktools.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/util/settings.h (3)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/util/system.cpp (2)
  • GetSetting (1179-1185)
  • GetSetting (1179-1179)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
test/functional/feature_dersig.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/validation_block_tests.cpp (2)
src/net_processing.cpp (3)
  • pblock (606-606)
  • block (608-608)
  • block (612-612)
src/rpc/mining.cpp (2)
  • block (987-992)
  • block (987-987)
test/functional/wallet_crosschain.py (1)
test/functional/test_framework/test_framework.py (2)
  • stop_nodes (684-692)
  • start_nodes (660-678)
src/rest.cpp (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/validation.h (1)
src/validation.cpp (11)
  • ChainstateManager (5985-5995)
  • chainparams (565-575)
  • chainparams (565-567)
  • chainparams (578-587)
  • chainparams (578-579)
  • chainparams (590-599)
  • chainparams (590-591)
  • ProcessNewBlock (4371-4408)
  • ProcessNewBlock (4371-4371)
  • ProcessNewBlockHeaders (4250-4277)
  • ProcessNewBlockHeaders (4250-4250)
src/init.cpp (3)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/rpc/blockchain.cpp (2)
  • GetUTXOStats (1106-1129)
  • GetUTXOStats (1106-1110)
src/util/system.cpp (2)
  • CheckDiskSpace (158-164)
  • CheckDiskSpace (158-158)
test/functional/feature_mnehf.py (1)
test/functional/test_framework/test_framework.py (1)
  • generate (806-809)
test/functional/test_framework/util.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/index/coinstatsindex.cpp (1)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • GetBogoSize (26-34)
  • GetBogoSize (26-26)
  • TxOutSer (36-42)
  • TxOutSer (36-36)
src/test/descriptor_tests.cpp (1)
src/script/descriptor.cpp (6)
  • scripts (759-764)
  • scripts (759-759)
  • LEGACY (715-715)
  • LEGACY (731-731)
  • LEGACY (797-797)
  • nullopt (657-657)
src/kernel/coinstats.h (2)
src/rpc/blockchain.h (2)
  • kernel (26-28)
  • node (33-36)
src/kernel/coinstats.cpp (9)
  • CCoinsStats (21-23)
  • GetBogoSize (26-34)
  • GetBogoSize (26-26)
  • TxOutSer (36-42)
  • TxOutSer (36-36)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/test/coinstatsindex_tests.cpp (2)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/test/validation_chainstate_tests.cpp (3)
src/validation.cpp (6)
  • chainparams (565-575)
  • chainparams (565-567)
  • chainparams (578-587)
  • chainparams (578-579)
  • chainparams (590-599)
  • chainparams (590-591)
src/rpc/mining.cpp (2)
  • chainparams (134-134)
  • chainparams (359-359)
src/test/miner_tests.cpp (1)
  • chainparams (39-39)
src/validation.cpp (2)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/util/system.cpp (1)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
src/test/util/setup_common.cpp (1)
src/chainparams.cpp (2)
  • Params (1354-1357)
  • Params (1354-1354)
src/test/settings_tests.cpp (2)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/util/system.cpp (2)
  • GetSetting (1179-1185)
  • GetSetting (1179-1179)
src/rpc/blockchain.cpp (4)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (2)
  • CoinStatsHashType (23-76)
  • node (18-20)
src/rpc/server.cpp (2)
  • IsDeprecatedRPCEnabled (367-372)
  • IsDeprecatedRPCEnabled (367-367)
src/rest.cpp (1)
  • getdeploymentinfo (624-624)
🪛 Flake8 (7.3.0)
test/functional/rpc_blockchain.py

[error] 196-196: continuation line under-indented for hanging indent

(E121)

🪛 markdownlint-cli2 (0.18.1)
doc/REST-interface.md

88-88: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)

Comment on lines +624 to +656
RPCHelpMan getdeploymentinfo();

static bool rest_deploymentinfo(const CoreContext& context, HTTPRequest* req, const std::string& str_uri_part)
{
if (!CheckWarmup(req)) return false;

std::string hash_str;
const RESTResponseFormat rf = ParseDataFormat(hash_str, str_uri_part);

switch (rf) {
case RESTResponseFormat::JSON: {
JSONRPCRequest jsonRequest;
jsonRequest.context = context;
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);
}

req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, getdeploymentinfo().HandleRequest(jsonRequest).write() + "\n");
return true;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix parameter handling and error codes in rest_deploymentinfo

  • Use the already parsed hash for LookupBlockIndex (do not call ParseHashV on a string).
  • Pass params as a positional array (push_back), not object (pushKV).
  • Return 404 for “Block not found” to match other REST endpoints.
  • Keep ChainstateManager non-const for consistency with neighboring handlers.

Apply this diff:

-RPCHelpMan getdeploymentinfo();
+RPCHelpMan getdeploymentinfo();
 
 static bool rest_deploymentinfo(const CoreContext& context, HTTPRequest* req, const std::string& str_uri_part)
 {
     if (!CheckWarmup(req)) return false;
 
     std::string hash_str;
     const RESTResponseFormat rf = ParseDataFormat(hash_str, str_uri_part);
 
     switch (rf) {
     case RESTResponseFormat::JSON: {
         JSONRPCRequest jsonRequest;
         jsonRequest.context = context;
-        jsonRequest.params = UniValue(UniValue::VARR);
+        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);
+            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");
+            if (!WITH_LOCK(::cs_main, return chainman->m_blockman.LookupBlockIndex(hash))) {
+                return RESTERR(req, HTTP_NOT_FOUND, "Block not found");
             }
 
-            jsonRequest.params.pushKV("blockhash", hash_str);
+            jsonRequest.params.push_back(hash_str);
         }
 
         req->WriteHeader("Content-Type", "application/json");
         req->WriteReply(HTTP_OK, getdeploymentinfo().HandleRequest(jsonRequest).write() + "\n");
         return true;
     }
     default: {
         return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
     }
     }
 }
🤖 Prompt for AI Agents
In src/rest.cpp around lines 624 to 656, fix rest_deploymentinfo by using the
parsed uint256 hash (not ParseHashV on the string) when calling
LookupBlockIndex, change the ChainstateManager pointer to non-const
(ChainstateManager* chainman) for consistency, adjust the LookupBlockIndex call
to use the already-parsed hash variable inside the WITH_LOCK, change
jsonRequest.params.pushKV(...) to push a positional param (push_back) so params
are a positional array, and return HTTP_NOT_FOUND (404) instead of
HTTP_BAD_REQUEST when the block is not found.

@kwvg kwvg modified the milestones: 23, 23.1 Oct 21, 2025
Copy link

This pull request has conflicts, please rebase.

kwvg added 3 commits October 21, 2025 20:42
bitcoin#22550 adds assertions to validate CSV/CLTV activation and
replaces the `generate()` calls with a helper `generate_to_height()` but
bitcoin#22818 activates all forks from block 1 by default, so the
`generate_to_height()` calls have been dropped.

This leaves us with the `generate()` calls being swapped for assertions.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
test/functional/rpc_blockchain.py (1)

192-250: Fix indentation issue on line 196.

There's an indentation issue flagged by flake8 on line 196. The line should be indented to align with the opening bracket.

Apply this diff to fix the indentation:

         assert_equal(gdi_result, {
-          "hash": blockhash,
+            "hash": blockhash,
             "height": height,
             "deployments": {
src/kernel/coinstats.cpp (1)

56-72: Bug in serialized-hash height/coinbase encoding (missing parentheses).

?: precedence makes this encode (height*2 + coinbase) ? 1 : 0 instead of height*2 + (coinbase?1:0), corrupting the UTXO set hash/commitment.

Fix:

-            ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
+            ss << VARINT(it->second.nHeight * 2 + (it->second.fCoinBase ? 1u : 0u));
♻️ Duplicate comments (2)
src/test/descriptor_tests.cpp (1)

320-320: Remove stray debug comment.

The “/* --- it fails!!! */” line should not be committed in tests.

-    /* --- it fails!!! */
src/kernel/coinstats.h (1)

14-16: Include explicitly.

std::optional is used in this header; add the header to avoid relying on transitive includes.

 #include <cstdint>
 #include <functional>
+#include <optional>
🧹 Nitpick comments (11)
src/test/fuzz/versionbits.cpp (2)

253-259: Add assertion tying signals length to elapsed for tighter invariants

You already verify numeric equality across calls. Also assert the signals vector length equals stats.elapsed to guard assumptions about ordering/size.

-        const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals);
+        const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals);
         const BIP9Stats stats_no_signals = checker.GetStateStatisticsFor(current_block);
         assert(stats.period == stats_no_signals.period && stats.threshold == stats_no_signals.threshold
                && stats.elapsed == stats_no_signals.elapsed && stats.count == stats_no_signals.count
                && stats.possible == stats_no_signals.possible);
+        assert(signals.size() == static_cast<size_t>(stats.elapsed));

287-290: Strengthen final-period checks by validating returned signals vector

Also capture signals on the last block to ensure:

  • signals.size() == period
  • true-count equals stats.count

Requires for std::count.

-    const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
+    std::vector<bool> signals_final;
+    const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals_final);
     assert(stats.period == period);
     assert(stats.threshold == threshold);
     assert(stats.elapsed == period);
     assert(stats.count == blocks_sig);
     assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
+    assert(signals_final.size() == static_cast<size_t>(period));
+    assert(std::count(signals_final.begin(), signals_final.end(), true) == stats.count);

Additional include (top of file with other headers):

+#include <algorithm>
src/Makefile.am (1)

1089-1103: Consider refactoring dash-wallet LDADD to reduce duplication and improve link order

The dash_wallet block (lines 1089–1103) manually expands libraries that largely overlap with the shared bitcoin_bin_ldadd variable. Unlike dashd and dash_node which correctly reuse it, dash_wallet cannot use bitcoin_bin_ldadd directly because it excludes unnecessary node dependencies (LIBBITCOIN_ZMQ, LIBLEVELDB, LIBMEMENV).

Recommended approach: Factor wallet-specific libraries into a separate variable (e.g., bitcoin_wallet_ldadd) to eliminate duplication, or keep manual expansion but reorder crypto/consensus libs to appear after BLS and secp256k1 primitives (e.g., lines 1095–1098 should move after line 1098) to follow standard link-order conventions on non-Linux targets.

test/functional/feature_cltv.py (1)

137-141: Fix comment/semantics mismatch around “active”

The comments say “Not active as of current tip…” but test_cltv_info asserts active=True at that point. Update comments to reflect the intended semantics (enforcement state for the next block vs current tip) to avoid confusion. Example:

-        self.test_cltv_info(is_active=True)  # Not active as of current tip, but next block must obey rules
+        self.test_cltv_info(is_active=True)  # Enforcement for the next block is active (tip at CLTV_HEIGHT-1)

Also applies to: 192-195

test/functional/feature_governance.py (1)

176-180: Grammar nit in log message

Tiny wording fix.

-        self.log.info("v20 is expected to be activate since block 160")
+        self.log.info("v20 is expected to be active since block 160")
test/functional/interface_rest.py (2)

391-402: Nice REST parity test; add positive hash case

Good check that /rest/deploymentinfo matches RPC at tip and error paths. Add a positive hash case to assert /rest/deploymentinfo/ equals getdeploymentinfo():

         deployment_info = self.nodes[0].getdeploymentinfo()
         assert_equal(deployment_info, self.test_rest_request('/deploymentinfo'))
 
+        # Also verify explicit blockhash variant matches RPC
+        tip = self.nodes[0].getbestblockhash()
+        assert_equal(
+            self.nodes[0].getdeploymentinfo(tip),
+            self.test_rest_request(f'/deploymentinfo/{tip}')
+        )

396-402: HTTP status consistency (optional)

Other REST endpoints use 404 for missing blocks (e.g., /block/), while here “Block not found” returns 400. Consider aligning to 404 or documenting the difference in REST docs for predictability.

doc/REST-interface.md (1)

88-96: Docs read well; consider noting error responses

Optionally add a sentence about error codes for invalid hash (400) vs not found (currently tested as 400) to match behavior and reduce ambiguity.

src/test/settings_tests.cpp (1)

109-109: Consider testing the new ignore_nonpersistent parameter.

All GetSetting calls have been correctly updated to pass false for the new parameter, preserving existing behavior. However, there's no test coverage for the new ignore_nonpersistent=true behavior.

Consider adding a test case that exercises the new functionality, for example:

BOOST_AUTO_TEST_CASE(IgnoreNonPersistent)
{
    util::Settings settings;
    settings.command_line_options["name"].push_back("cmdline_val");
    settings.ro_config["section"]["name"].push_back("config_val");
    
    // With ignore_nonpersistent=false, command line takes precedence
    BOOST_CHECK_EQUAL(R"("cmdline_val")", GetSetting(settings, "section", "name", false, false, false).write().c_str());
    
    // With ignore_nonpersistent=true, config file value is returned
    BOOST_CHECK_EQUAL(R"("config_val")", GetSetting(settings, "section", "name", false, true, false).write().c_str());
}

Also applies to: 145-147, 228-228

src/init.cpp (2)

834-846: UTXO stats collection path looks good.

Locking and optional handling are correct. Optionally, only request index lookup when available to avoid an extra branch.

-    const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true));
+    const bool index_requested = (g_coin_stats_index != nullptr);
+    const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), index_requested));

2291-2307: Nice first‑startup disk‑space warning.

Logic matches PR intent. Consider casting to uint64_t to avoid accidental overflow when multiplying GiB.

-        uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
-            : chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024;
+        const uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
+            : static_cast<uint64_t>(chainparams.AssumedBlockchainSize()) * 1024ULL * 1024ULL * 1024ULL;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 908eb3d and c173da3.

📒 Files selected for processing (59)
  • configure.ac (1 hunks)
  • doc/REST-interface.md (1 hunks)
  • doc/release-notes-6901.md (1 hunks)
  • src/Makefile.am (3 hunks)
  • src/index/coinstatsindex.cpp (2 hunks)
  • src/index/coinstatsindex.h (2 hunks)
  • src/init.cpp (4 hunks)
  • src/interfaces/node.h (2 hunks)
  • src/kernel/coinstats.cpp (5 hunks)
  • src/kernel/coinstats.h (3 hunks)
  • src/net_processing.cpp (4 hunks)
  • src/node/interfaces.cpp (1 hunks)
  • src/rest.cpp (2 hunks)
  • src/rpc/blockchain.cpp (15 hunks)
  • src/rpc/blockchain.h (3 hunks)
  • src/rpc/mining.cpp (3 hunks)
  • src/rpc/util.h (0 hunks)
  • src/script/descriptor.cpp (1 hunks)
  • src/script/signingprovider.cpp (1 hunks)
  • src/script/signingprovider.h (2 hunks)
  • src/test/blockfilter_index_tests.cpp (4 hunks)
  • src/test/coinstatsindex_tests.cpp (3 hunks)
  • src/test/descriptor_tests.cpp (5 hunks)
  • src/test/evo_deterministicmns_tests.cpp (9 hunks)
  • src/test/fuzz/coins_view.cpp (0 hunks)
  • src/test/fuzz/rpc.cpp (1 hunks)
  • src/test/fuzz/utxo_snapshot.cpp (1 hunks)
  • src/test/fuzz/versionbits.cpp (4 hunks)
  • src/test/miner_tests.cpp (1 hunks)
  • src/test/settings_tests.cpp (3 hunks)
  • src/test/util/mining.cpp (1 hunks)
  • src/test/util/setup_common.cpp (3 hunks)
  • src/test/validation_block_tests.cpp (4 hunks)
  • src/test/validation_chainstate_tests.cpp (1 hunks)
  • src/util/settings.cpp (2 hunks)
  • src/util/settings.h (1 hunks)
  • src/util/system.cpp (6 hunks)
  • src/util/system.h (2 hunks)
  • src/validation.cpp (28 hunks)
  • src/validation.h (8 hunks)
  • src/versionbits.cpp (3 hunks)
  • src/versionbits.h (2 hunks)
  • src/wallet/rpc/spend.cpp (1 hunks)
  • src/wallet/scriptpubkeyman.cpp (3 hunks)
  • test/functional/feature_asset_locks.py (1 hunks)
  • test/functional/feature_cltv.py (1 hunks)
  • test/functional/feature_dersig.py (1 hunks)
  • test/functional/feature_governance.py (5 hunks)
  • test/functional/feature_mnehf.py (2 hunks)
  • test/functional/feature_new_quorum_type_activation.py (1 hunks)
  • test/functional/interface_rest.py (1 hunks)
  • test/functional/p2p_dos_header_tree.py (4 hunks)
  • test/functional/rpc_blockchain.py (4 hunks)
  • test/functional/test_framework/blocktools.py (1 hunks)
  • test/functional/test_framework/util.py (1 hunks)
  • test/functional/wallet_crosschain.py (3 hunks)
  • test/functional/wallet_importdescriptors.py (1 hunks)
  • test/functional/wallet_signrawtransactionwithwallet.py (2 hunks)
  • test/lint/lint-circular-dependencies.py (1 hunks)
💤 Files with no reviewable changes (2)
  • src/rpc/util.h
  • src/test/fuzz/coins_view.cpp
🚧 Files skipped from review as they are similar to previous changes (22)
  • src/test/fuzz/rpc.cpp
  • src/script/descriptor.cpp
  • src/test/miner_tests.cpp
  • test/functional/test_framework/blocktools.py
  • src/wallet/rpc/spend.cpp
  • test/functional/wallet_crosschain.py
  • src/rest.cpp
  • src/versionbits.h
  • test/functional/test_framework/util.py
  • src/test/util/mining.cpp
  • test/functional/p2p_dos_header_tree.py
  • src/interfaces/node.h
  • src/rpc/blockchain.h
  • test/functional/feature_new_quorum_type_activation.py
  • src/test/util/setup_common.cpp
  • src/util/system.h
  • test/functional/feature_dersig.py
  • src/util/system.cpp
  • src/node/interfaces.cpp
  • src/test/blockfilter_index_tests.cpp
  • src/net_processing.cpp
  • test/functional/feature_mnehf.py
🧰 Additional context used
📓 Path-based instructions (4)
doc/**

📄 CodeRabbit inference engine (CLAUDE.md)

Unless specifically prompted, avoid making changes to the doc directory (documentation)

Files:

  • doc/REST-interface.md
  • doc/release-notes-6901.md
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/wallet_signrawtransactionwithwallet.py
  • test/functional/feature_asset_locks.py
  • test/functional/rpc_blockchain.py
  • test/functional/feature_cltv.py
  • test/functional/feature_governance.py
  • test/functional/interface_rest.py
  • test/functional/wallet_importdescriptors.py
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/util/settings.h
  • src/test/coinstatsindex_tests.cpp
  • src/rpc/mining.cpp
  • src/index/coinstatsindex.cpp
  • src/versionbits.cpp
  • src/kernel/coinstats.h
  • src/test/evo_deterministicmns_tests.cpp
  • src/test/fuzz/utxo_snapshot.cpp
  • src/script/signingprovider.cpp
  • src/test/fuzz/versionbits.cpp
  • src/test/settings_tests.cpp
  • src/wallet/scriptpubkeyman.cpp
  • src/util/settings.cpp
  • src/test/descriptor_tests.cpp
  • src/kernel/coinstats.cpp
  • src/script/signingprovider.h
  • src/index/coinstatsindex.h
  • src/validation.h
  • src/init.cpp
  • src/test/validation_chainstate_tests.cpp
  • src/test/validation_block_tests.cpp
  • src/validation.cpp
  • src/rpc/blockchain.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/coinstatsindex_tests.cpp
  • src/test/evo_deterministicmns_tests.cpp
  • src/test/fuzz/utxo_snapshot.cpp
  • src/test/fuzz/versionbits.cpp
  • src/test/settings_tests.cpp
  • src/test/descriptor_tests.cpp
  • src/test/validation_chainstate_tests.cpp
  • src/test/validation_block_tests.cpp
🧠 Learnings (1)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
🧬 Code graph analysis (22)
test/functional/wallet_signrawtransactionwithwallet.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
test/functional/feature_asset_locks.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/util/settings.h (3)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/util/system.cpp (2)
  • GetSetting (1179-1185)
  • GetSetting (1179-1179)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
src/test/coinstatsindex_tests.cpp (2)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/index/coinstatsindex.cpp (1)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • GetBogoSize (26-34)
  • GetBogoSize (26-26)
  • TxOutSer (36-42)
  • TxOutSer (36-36)
src/versionbits.cpp (2)
src/validation.cpp (14)
  • pindex (2205-2205)
  • pindex (2205-2205)
  • pindex (2209-2215)
  • pindex (2209-2209)
  • pindex (3131-3138)
  • pindex (3131-3131)
  • params (2203-2203)
  • params (2203-2203)
  • params (2204-2204)
  • params (2204-2204)
  • params (2206-2206)
  • params (2206-2206)
  • params (2207-2207)
  • params (2207-2207)
src/test/fuzz/versionbits.cpp (15)
  • pindex (45-45)
  • pindex (45-45)
  • pindex (47-47)
  • pindex (47-47)
  • pindex (55-55)
  • pindex (55-55)
  • pindex (63-63)
  • pindex (63-63)
  • params (46-46)
  • params (46-46)
  • params (48-48)
  • params (48-48)
  • params (49-49)
  • params (49-49)
  • params (50-50)
src/kernel/coinstats.h (2)
src/rpc/blockchain.h (2)
  • kernel (26-28)
  • node (33-36)
src/kernel/coinstats.cpp (9)
  • CCoinsStats (21-23)
  • GetBogoSize (26-34)
  • GetBogoSize (26-26)
  • TxOutSer (36-42)
  • TxOutSer (36-36)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/script/signingprovider.cpp (1)
src/script/descriptor.cpp (11)
  • scripts (759-764)
  • scripts (759-759)
  • pubkeys (512-512)
  • keys (712-712)
  • keys (712-712)
  • keys (723-728)
  • keys (723-723)
  • keys (742-749)
  • keys (742-742)
  • keys (780-793)
  • keys (780-780)
src/test/fuzz/versionbits.cpp (1)
src/versionbits.cpp (4)
  • pindex (258-261)
  • pindex (258-258)
  • GetStateStatisticsFor (134-180)
  • GetStateStatisticsFor (134-134)
src/test/settings_tests.cpp (2)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/util/system.cpp (2)
  • GetSetting (1179-1185)
  • GetSetting (1179-1179)
test/functional/rpc_blockchain.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (4)
  • getblockchaininfo (1501-1588)
  • getblockchaininfo (1501-1501)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/descriptor_tests.cpp (1)
src/script/descriptor.cpp (5)
  • scripts (759-764)
  • scripts (759-759)
  • LEGACY (715-715)
  • LEGACY (731-731)
  • LEGACY (797-797)
test/functional/feature_cltv.py (2)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/script/signingprovider.h (1)
src/script/signingprovider.cpp (2)
  • Merge (58-65)
  • Merge (58-58)
src/index/coinstatsindex.h (3)
src/rpc/blockchain.h (1)
  • kernel (26-28)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/index/coinstatsindex.cpp (2)
  • LookUpStats (320-345)
  • LookUpStats (320-320)
src/validation.h (1)
src/validation.cpp (5)
  • ChainstateManager (6049-6059)
  • ProcessNewBlock (4435-4472)
  • ProcessNewBlock (4435-4435)
  • ProcessNewBlockHeaders (4314-4341)
  • ProcessNewBlockHeaders (4314-4314)
src/init.cpp (4)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/rpc/blockchain.cpp (2)
  • GetUTXOStats (1106-1129)
  • GetUTXOStats (1106-1110)
src/util/system.cpp (2)
  • CheckDiskSpace (158-164)
  • CheckDiskSpace (158-158)
src/fs.h (1)
  • quoted (94-97)
test/functional/feature_governance.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/validation_chainstate_tests.cpp (3)
src/validation.cpp (6)
  • chainparams (569-580)
  • chainparams (569-571)
  • chainparams (583-593)
  • chainparams (583-584)
  • chainparams (596-606)
  • chainparams (596-597)
src/rpc/mining.cpp (2)
  • chainparams (134-134)
  • chainparams (359-359)
src/test/miner_tests.cpp (3)
  • chainparams (39-39)
  • chainparams (40-40)
  • chainparams (41-41)
test/functional/interface_rest.py (2)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
src/validation.cpp (2)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (23-76)
src/rpc/blockchain.cpp (4)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (2)
  • CoinStatsHashType (23-76)
  • node (18-20)
src/rpc/server.cpp (2)
  • IsDeprecatedRPCEnabled (367-372)
  • IsDeprecatedRPCEnabled (367-367)
src/deploymentinfo.cpp (2)
  • DeploymentName (20-56)
  • DeploymentName (20-20)
🪛 Flake8 (7.3.0)
test/functional/rpc_blockchain.py

[error] 196-196: continuation line under-indented for hanging indent

(E121)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Lint / Run linters
  • GitHub Check: x86_64-w64-mingw32 / Build depends
  • GitHub Check: x86_64-apple-darwin / Build depends
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
  • GitHub Check: x86_64-pc-linux-gnu_nowallet / Build depends
  • GitHub Check: x86_64-pc-linux-gnu_multiprocess / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
🔇 Additional comments (58)
test/functional/wallet_importdescriptors.py (1)

131-131: LGTM! Good simplification.

Directly using key.p2pkh_addr removes redundant address computation and aligns with the usage pattern throughout the rest of the file (lines 97, 107, 117, 180).

src/versionbits.cpp (2)

134-180: LGTM! Clean implementation of per-block signalling statistics.

The changes correctly implement the optional signalling_blocks parameter with sound loop indexing and elapsed counter logic. The retention of pindexEndOfPrevPeriod for Dash-specific dynamic threshold calculation (lines 152-159) while using the new elapsed counter approach (lines 162-175) properly aligns with the PR objectives.


276-280: LGTM! Parameter forwarding is correct.

The updated signature and forwarding of the signalling_blocks parameter to GetStateStatisticsFor is properly implemented.

configure.ac (1)

1505-1509: LGTM! Reasonable build optimization.

This gating logic correctly disables networking features (UPnP, NAT-PMP, ZMQ) when none of the components that require them are being built. The condition appropriately checks the daemon, GUI, benchmarks, and tests—the primary consumers of these networking capabilities.

The pattern is consistent with the existing fuzzing mode logic (lines 1401-1417) and the placement before the actual library detection routines (lines 1512+) properly prevents unnecessary dependency checks.

src/test/fuzz/versionbits.cpp (3)

55-55: Adapter overload matches updated API

Wrapper cleanly forwards to AbstractThresholdConditionChecker::GetStateStatisticsFor with optional signals capture. No issues.


225-231: Baseline stats initialization at period boundary looks correct

Setting elapsed/count to 0 and possible = (period >= threshold) matches the upstream formula at the start of a period. Good.


267-270: Per-block signalling history checks are consistent

The sequence-size, last-bit, and full-sequence equality checks align with the signalling_blocks semantics. LGTM.

test/functional/wallet_signrawtransactionwithwallet.py (2)

133-133: Switch to getdeploymentinfo for CSV activation — LGTM

Accurately reflects the new RPC and removes brittle block-gen assumptions.


162-167: CLTV check/operand adjustment — LGTM

Using getdeploymentinfo and dropping CLTV operand to 100 is consistent with upstream; passing current height as locktime keeps the tx final.

src/Makefile.am (2)

262-262: Public header move to kernel/coinstats.h — LGTM

Matches the code relocation.


532-532: Add kernel/coinstats.cpp to node sources — LGTM

Consistent with the namespace move.

src/rpc/mining.cpp (3)

148-149: Update ProcessNewBlock signature usage — LGTM

Correctly removes Params() per the new API.


1044-1044: submitblock: ProcessNewBlock call updated — LGTM

Matches the refactored ChainstateManager interface.


1085-1085: submitheader: ProcessNewBlockHeaders call updated — LGTM

Signature change is applied correctly.

test/lint/lint-circular-dependencies.py (1)

22-22: Update expected cycle: kernel/coinstats ↔ validation — LGTM

Keeps the linter aligned with the namespace move.

test/functional/feature_asset_locks.py (1)

251-251: Use getdeploymentinfo for v20 activation — LGTM

Avoids deprecated getblockchaininfo['softforks'] and aligns tests with the new RPC.

test/functional/feature_cltv.py (1)

101-107: Good migration to getdeploymentinfo

Switching to getdeploymentinfo() for buried deployment checks is correct and future‑proof. Keys asserted here match the buried shape.

test/functional/feature_governance.py (1)

27-29: Consistent use of getdeploymentinfo for v20 state

All call sites now query v20 via getdeploymentinfo(). Looks consistent with the deprecation of softforks in getblockchaininfo.

Also applies to: 98-99, 105-106, 224-226, 364-365, 378-380

doc/release-notes-6901.md (2)

4-11: Clear note on softforks relocation

Release note accurately describes the move to getdeploymentinfo and the deprecation flag. LGTM.


16-17: REST endpoint mention

Good addition; no changes needed.

src/util/settings.cpp (2)

144-144: LGTM! Parameter addition is clean.

The new ignore_nonpersistent parameter is well-placed in the signature and aligns with the function's existing design pattern.


180-181: LGTM! Implementation is correct.

The logic correctly skips non-persistent settings (COMMAND_LINE and FORCED) when requested, and the placement in the control flow is appropriate.

src/test/fuzz/utxo_snapshot.cpp (1)

60-60: LGTM! API usage updated correctly.

The removal of the ::Params() argument from ProcessNewBlockHeaders is consistent with the ChainstateManager API changes where chain parameters are now held by the manager itself.

src/test/validation_chainstate_tests.cpp (1)

27-28: LGTM! ChainstateManager initialization updated correctly.

The explicit chain parameters binding and passing to the constructor aligns with the PR's API changes where ChainstateManager now holds CChainParams and requires explicit initialization.

src/script/signingprovider.h (2)

9-9: LGTM! Appropriate include for LIFETIMEBOUND.

The attributes.h include is necessary for the LIFETIMEBOUND attribute used in the new Merge member function.


59-60: Excellent refactor to member function with move semantics.

The conversion from a free function to a member function Merge(FlatSigningProvider&& b) offers several improvements:

  • Move semantics avoid unnecessary copies
  • In-place mutation is more efficient
  • Return reference enables method chaining
  • LIFETIMEBOUND attribute prevents lifetime issues
src/util/settings.h (1)

58-62: LGTM! Clear documentation and consistent API.

The new ignore_nonpersistent parameter is well-documented and the declaration correctly matches the implementation in src/util/settings.cpp.

Also applies to: 69-69

test/functional/rpc_blockchain.py (1)

252-283: LGTM! Comprehensive test coverage for getdeploymentinfo RPC.

The test method properly validates:

  • Deployment info at the current tip
  • Deployment info at a specific height
  • Historical queries using explicit block hash
  • Status transitions (started → locked_in)

The test setup with various activation heights and the validation helper provide good coverage of the new RPC endpoint.

src/index/coinstatsindex.h (2)

12-12: LGTM! Migration to kernel namespace.

The include change from node/coinstats.h to kernel/coinstats.h correctly reflects the UTXO statistics migration to the kernel namespace as outlined in the PR objectives.


59-59: Excellent API modernization with std::optional.

The signature change from an out-parameter pattern to returning std::optional<kernel::CCoinsStats> is a significant improvement:

  • Clearer semantics: std::nullopt explicitly indicates "not found"
  • Eliminates need for separate boolean return + out-parameter
  • More idiomatic modern C++
  • Safer: impossible to use uninitialized data on failure
src/wallet/scriptpubkeyman.cpp (3)

2212-2212: LGTM: Correct in-place merge pattern.

The change from *out_keys = Merge(*out_keys, it->second) to out_keys->Merge(FlatSigningProvider{it->second}) correctly uses the new in-place member function. Creating a temporary via brace-initialization is appropriate for merging cached data.


2249-2249: LGTM: Appropriate use of move semantics.

The in-place merge with std::move(*coin_keys) is correct. Since coin_keys is a temporary signing provider that won't be reused after this merge, moving it is efficient and appropriate.


2321-2321: LGTM: Consistent in-place merge pattern in PSBT filling.

Both merge calls correctly use the new in-place member function with move semantics. Since script_keys and pk_keys are temporary providers used only for accumulation, moving them into the destination is efficient and correct.

Also applies to: 2329-2329

src/test/validation_block_tests.cpp (1)

102-102: LGTM: Consistent API migration removing Params() arguments.

All call sites correctly updated to omit the Params() argument from ProcessNewBlockHeaders and ProcessNewBlock. This aligns with the PR's broader change where ChainstateManager now holds CChainParams internally, eliminating the need to pass it explicitly.

Also applies to: 159-159, 181-181, 187-187, 226-226

src/test/coinstatsindex_tests.cpp (2)

15-16: LGTM: Correct namespace migration for coin stats types.

Using declarations properly updated to reference kernel::CCoinsStats and kernel::CoinStatsHashType, aligning with the broader refactor moving these types into the kernel namespace.


31-31: LGTM: Clean migration to optional return pattern.

All LookUpStats call sites correctly updated to:

  • Call with only block_index parameter (no out-parameter)
  • Check the returned std::optional for presence/absence
  • Rely on the optional's boolean conversion in BOOST_CHECK

This is a cleaner API that makes the miss-vs-hit distinction explicit.

Also applies to: 47-47, 50-50, 64-64

src/test/evo_deterministicmns_tests.cpp (1)

266-266: LGTM: Consistent ProcessNewBlock API migration across Dash tests.

All ProcessNewBlock call sites correctly updated to remove the Params() argument. The changes are consistent with the broader API refactor where ChainstateManager now internally holds CChainParams. Test behavior and assertions remain unchanged.

Also applies to: 276-276, 304-304, 322-322, 342-342, 642-642, 788-788, 821-821, 834-834

src/script/signingprovider.cpp (1)

58-65: LGTM: Clean in-place merge implementation.

The new member function correctly:

  • Uses std::map::merge to transfer elements from source to destination (preserving existing entries)
  • Accepts rvalue reference to enable move semantics
  • Merges all four member containers (scripts, pubkeys, keys, origins)
  • Returns *this to enable method chaining

This is a cleaner API than the previous free function, making the in-place mutation explicit.

src/index/coinstatsindex.cpp (2)

17-20: LGTM: Correct kernel namespace usage.

Using declarations properly reference kernel::CCoinsStats, kernel::GetBogoSize, and kernel::TxOutSer, aligning with the coin stats types migration to the kernel namespace.


320-345: LGTM: Clean migration to optional return pattern.

The refactored LookUpStats correctly:

  • Returns std::optional<CCoinsStats> instead of using an out-parameter
  • Constructs CCoinsStats locally with block_height and block_hash constructor
  • Sets index_used = true to indicate index was queried
  • Populates all 13 stats fields from the DB entry
  • Returns std::nullopt on DB miss, making the miss-vs-hit case explicit

This is a cleaner, more modern API that eliminates the need for callers to pre-construct a stats object.

src/init.cpp (1)

1938-1939: Ctor update is consistent with new API.

Instantiation with chainparams aligns with the refactor.

Please verify all other ChainstateManager constructions pass CChainParams.

src/test/descriptor_tests.cpp (4)

78-80: Signature refactor: norm_pub only.

Updated DoCheck signature is consistent and clear.


237-244: New Merge usage: verify return type expectations.

FlatSigningProvider{...}.Merge(...) is used as an rvalue where a const SigningProvider& is expected. Ensure Merge returns a reference/value usable in this context.

Run build/tests to confirm no lifetime issues.


271-295: Wrapper Check updates look consistent.

Apostrophe replacement paths remain covered; passing norm_pub throughout is correct.


301-346: Bulk test vector updates.

Vectors reflect the new provider‑merge approach and normalization; looks fine.

src/kernel/coinstats.cpp (1)

139-165: Dispatcher looks correct.

Optional handling and block index lookup align with callers.

src/validation.h (3)

101-110: Prune target bump to 945 MiB.

Matches PR rationale for Dash disk space; OK.


1082-1100: Deployment helpers passthrough.

Thin wrappers are fine and reduce param threading.


908-931: All call sites correctly updated; chainparams successfully embedded in ChainstateManager.

Verification confirms the changes are complete:

  • Constructor is explicit and embeds CChainParams via member initialization
  • Accessors (GetParams(), GetConsensus()) are clean and functional
  • ProcessNewBlock and ProcessNewBlockHeaders signatures no longer take CChainParams parameters—they now access it via this->m_chainparams
  • All call sites (across net_processing.cpp, rpc/mining.cpp, test files) correctly invoke methods on the chainman instance without passing CChainParams directly
src/rpc/blockchain.cpp (9)

23-23: LGTM: Clean migration to kernel namespace.

The header include change from node/coinstats.h to kernel/coinstats.h and the corresponding using declarations properly reflect the migration of UTXO statistics APIs to the kernel namespace, as confirmed by the relevant code snippets.

Also applies to: 66-68


1106-1129: LGTM: Well-structured UTXO stats retrieval function.

The GetUTXOStats wrapper properly handles two paths:

  1. Using CoinStatsIndex when available and requested (for MUHASH/NONE)
  2. Computing stats directly via kernel::ComputeUTXOStats otherwise

The CHECK_NONFATAL at line 1126 correctly validates that without the index, pindex must be null or equal to the view's best block, which is a necessary constraint.


1186-1186: LGTM: Proper optional handling for GetUTXOStats.

The updates correctly adapt to the new GetUTXOStats API that returns std::optional<kernel::CCoinsStats>:

  • Lines 1229-1231: Properly checks has_value() before accessing stats
  • Lines 1250-1256: Correctly handles the case where previous block stats cannot be retrieved, throwing an appropriate error
  • Consistent use of the index_requested parameter throughout

Also applies to: 1207-1217, 1229-1276


1400-1492: LGTM: Clean refactoring to use ChainstateManager.

The SoftForkDescPushBack functions have been properly refactored to accept ChainstateManager instead of separate consensus parameters:

  • Both buried and BIP9 deployment versions now consistently use chainman.GetConsensus() to access consensus parameters
  • Line 1420: Sensible early return when blockindex is null for BIP9 deployments
  • Lines 1461-1477: Signalling bitstring generation is correct (using '#' for signaling blocks and '-' for non-signaling)

This aligns with the architectural change of ChainstateManager holding CChainParams as described in the AI summary.


1494-1498: LGTM: Proper deprecation handling for softforks reporting.

The changes correctly implement the deprecation of softforks reporting in getblockchaininfo:

  • Lines 1494-1498: Forward declarations properly handle the anonymous namespace structure
  • Lines 1579-1582: Softforks are only included when -deprecatedrpc=softforks is enabled, maintaining backward compatibility while encouraging migration to getdeploymentinfo
  • The help text clearly documents the deprecation at lines 1526-1531

This aligns with the PR objectives stating that requesting deployment info from getblockchaininfo is deprecated in favor of getdeploymentinfo.

Also applies to: 1501-1588


1590-1696: LGTM: Well-implemented getdeploymentinfo RPC.

The new getdeploymentinfo RPC provides a clean interface for querying deployment information:

  • Lines 1655, 1676-1685: Properly handles optional blockhash parameter, defaulting to chain tip
  • Line 1681: Validates block existence before proceeding
  • Lines 1619-1647: DeploymentInfo function correctly iterates through both buried deployments and EHF-enabled deployments (V24, TESTDUMMY)
  • The implementation properly separates concerns by delegating to the refactored SoftForkDescPushBack functions

This is the recommended replacement for the deprecated softforks field in getblockchaininfo.


2825-2825: LGTM: Consistent optional handling in CreateUTXOSnapshot.

The changes properly adapt CreateUTXOSnapshot to use the new GetUTXOStats API:

  • Line 2825: Declares maybe_stats as std::optional<CCoinsStats>
  • Lines 2845-2848: Calls GetUTXOStats and validates the result before proceeding
  • Lines 2851, 2858, 2880, 2884: All accesses to stats fields use the -> operator, which is safe after the validation check

The error handling is appropriate and consistent with the RPC error reporting pattern used elsewhere in this file.

Also applies to: 2845-2889


2907-2907: LGTM: Proper RPC registration.

The getdeploymentinfo RPC is correctly registered in the blockchain category at line 2907, maintaining alphabetical order with other commands.


1106-1129: No changes required—GetUTXOStats visibility is correctly implemented.

The function is properly declared in src/rpc/blockchain.h and used externally in src/init.cpp, confirming it is correctly exposed as a public API. The code follows the appropriate visibility pattern for functions that need to be called across module boundaries.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/init.cpp (1)

834-846: Don't hold cs_main while computing UTXO stats.

GetUTXOStats(...) can index/scan LevelDB and block for a while. Holding cs_main here increases contention and risks deadlocks. Capture the DB pointer under lock, release it, and call without cs_main; pass pindex=nullptr to avoid CHECK_NONFATAL trips when the index is unavailable.

-    const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true));
+    CCoinsView* coinsdb{nullptr};
+    {
+        LOCK(::cs_main);
+        coinsdb = &chainman.ActiveChainstate().CoinsDB();
+    }
+    const auto maybe_stats = GetUTXOStats(
+        coinsdb,
+        chainman.m_blockman,
+        /*hash_type=*/CoinStatsHashType::NONE,
+        node.rpc_interruption_point,
+        /*pindex=*/nullptr,
+        /*index_requested=*/true);
src/kernel/coinstats.cpp (1)

56-72: Critical: precedence bug corrupts UTXO stats hash.

?: binds to the sum; this changes the commitment format. Must wrap the conditional.

-            ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
+            ss << VARINT(it->second.nHeight * 2u + (it->second.fCoinBase ? 1u : 0u));
♻️ Duplicate comments (3)
src/test/descriptor_tests.cpp (1)

320-320: Remove stray debug comment.

The comment /* --- it fails!!! */ appears to be leftover debug noise that should be removed to keep the test file clean.

Apply this diff:

-    /* --- it fails!!! */
src/init.cpp (1)

34-34: Resolved: coinstats types are correctly included.

Adding <kernel/coinstats.h> fixes prior missing-declaration issues when using kernel coinstats types.

src/kernel/coinstats.h (1)

16-16: Resolved: explicit <optional> include.

Good fix to avoid relying on transitive headers.

🧹 Nitpick comments (5)
test/functional/rpc_blockchain.py (1)

195-250: Fix indentation in dictionary literal.

The continuation lines in the dictionary literal are under-indented. The keys should align with the opening brace or use consistent 4-space indentation.

Apply this diff to fix the indentation:

         assert_equal(gdi_result, {
-          "hash": blockhash,
-          "height": height,
-          "deployments": {
+            "hash": blockhash,
+            "height": height,
+            "deployments": {
             'bip34': {'type': 'buried', 'active': True, 'height': 2},

(Similar adjustments should be made to all continuation lines in this dictionary to maintain consistent indentation throughout the structure.)

src/util/system.cpp (1)

643-674: Excellent refactoring! Helper functions improve maintainability.

Extracting SettingToString, SettingToInt, and SettingToBool as standalone functions:

  • Eliminates code duplication from the original Get*Arg implementations
  • Enables reuse by other parts of the codebase (as seen in the node interfaces per the relevant code snippets)
  • Preserves the original conversion logic exactly

This is a well-executed refactoring that enhances code clarity without changing behavior.

src/validation.cpp (3)

4056-4076: ContextualCheckBlockHeader switched to ChainstateManager — small nit.

Logic is intact. Prefer std::abs over abs for doubles to avoid overload ambiguity.

-        if (abs(n1-n2) > n1*0.5) {
+        if (std::abs(n1 - n2) > n1 * 0.5) {

5939-5955: Snapshot validation now uses kernel::ComputeUTXOStats (optional) and verifies assumeutxo hash — solid.

Optional: add a brief comment noting HASH_SERIALIZED is required for assumeutxo verification.

Also applies to: 5956-5964, 5996-6003


146-147: Remaining direct Params() usages (informational).

A few legacy paths still call Params() (e.g., subsidy helpers). Given backport scope, OK to defer consolidating to chainman/m_params.

Based on learnings

Also applies to: 317-350, 4098-4104

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c173da3 and e861b66.

📒 Files selected for processing (59)
  • configure.ac (1 hunks)
  • doc/REST-interface.md (1 hunks)
  • doc/release-notes-6901.md (1 hunks)
  • src/Makefile.am (3 hunks)
  • src/index/coinstatsindex.cpp (2 hunks)
  • src/index/coinstatsindex.h (2 hunks)
  • src/init.cpp (5 hunks)
  • src/interfaces/node.h (2 hunks)
  • src/kernel/coinstats.cpp (5 hunks)
  • src/kernel/coinstats.h (3 hunks)
  • src/net_processing.cpp (4 hunks)
  • src/node/interfaces.cpp (1 hunks)
  • src/rest.cpp (2 hunks)
  • src/rpc/blockchain.cpp (15 hunks)
  • src/rpc/blockchain.h (3 hunks)
  • src/rpc/mining.cpp (3 hunks)
  • src/rpc/util.h (0 hunks)
  • src/script/descriptor.cpp (1 hunks)
  • src/script/signingprovider.cpp (1 hunks)
  • src/script/signingprovider.h (2 hunks)
  • src/test/blockfilter_index_tests.cpp (4 hunks)
  • src/test/coinstatsindex_tests.cpp (3 hunks)
  • src/test/descriptor_tests.cpp (5 hunks)
  • src/test/evo_deterministicmns_tests.cpp (9 hunks)
  • src/test/fuzz/coins_view.cpp (0 hunks)
  • src/test/fuzz/rpc.cpp (1 hunks)
  • src/test/fuzz/utxo_snapshot.cpp (1 hunks)
  • src/test/fuzz/versionbits.cpp (4 hunks)
  • src/test/miner_tests.cpp (1 hunks)
  • src/test/settings_tests.cpp (3 hunks)
  • src/test/util/mining.cpp (1 hunks)
  • src/test/util/setup_common.cpp (3 hunks)
  • src/test/validation_block_tests.cpp (4 hunks)
  • src/test/validation_chainstate_tests.cpp (1 hunks)
  • src/util/settings.cpp (2 hunks)
  • src/util/settings.h (1 hunks)
  • src/util/system.cpp (6 hunks)
  • src/util/system.h (2 hunks)
  • src/validation.cpp (28 hunks)
  • src/validation.h (8 hunks)
  • src/versionbits.cpp (3 hunks)
  • src/versionbits.h (3 hunks)
  • src/wallet/rpc/spend.cpp (1 hunks)
  • src/wallet/scriptpubkeyman.cpp (3 hunks)
  • test/functional/feature_asset_locks.py (1 hunks)
  • test/functional/feature_cltv.py (1 hunks)
  • test/functional/feature_dersig.py (1 hunks)
  • test/functional/feature_governance.py (5 hunks)
  • test/functional/feature_mnehf.py (2 hunks)
  • test/functional/feature_new_quorum_type_activation.py (1 hunks)
  • test/functional/interface_rest.py (1 hunks)
  • test/functional/p2p_dos_header_tree.py (4 hunks)
  • test/functional/rpc_blockchain.py (4 hunks)
  • test/functional/test_framework/blocktools.py (1 hunks)
  • test/functional/test_framework/util.py (1 hunks)
  • test/functional/wallet_crosschain.py (3 hunks)
  • test/functional/wallet_importdescriptors.py (1 hunks)
  • test/functional/wallet_signrawtransactionwithwallet.py (2 hunks)
  • test/lint/lint-circular-dependencies.py (1 hunks)
💤 Files with no reviewable changes (2)
  • src/rpc/util.h
  • src/test/fuzz/coins_view.cpp
🚧 Files skipped from review as they are similar to previous changes (33)
  • test/functional/test_framework/blocktools.py
  • test/functional/feature_asset_locks.py
  • test/functional/test_framework/util.py
  • test/functional/feature_dersig.py
  • src/test/validation_chainstate_tests.cpp
  • src/script/descriptor.cpp
  • src/script/signingprovider.h
  • src/test/fuzz/rpc.cpp
  • test/functional/p2p_dos_header_tree.py
  • src/test/validation_block_tests.cpp
  • test/functional/wallet_signrawtransactionwithwallet.py
  • test/functional/wallet_importdescriptors.py
  • src/node/interfaces.cpp
  • src/interfaces/node.h
  • test/lint/lint-circular-dependencies.py
  • src/util/settings.h
  • src/versionbits.h
  • src/test/fuzz/utxo_snapshot.cpp
  • src/util/system.h
  • test/functional/interface_rest.py
  • src/Makefile.am
  • doc/release-notes-6901.md
  • src/rpc/mining.cpp
  • src/util/settings.cpp
  • test/functional/wallet_crosschain.py
  • src/wallet/rpc/spend.cpp
  • test/functional/feature_cltv.py
  • src/rpc/blockchain.h
  • src/index/coinstatsindex.cpp
  • src/test/util/mining.cpp
  • src/wallet/scriptpubkeyman.cpp
  • src/rest.cpp
  • src/test/miner_tests.cpp
🧰 Additional context used
📓 Path-based instructions (4)
test/functional/**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

Functional tests should be written in Python and placed in test/functional/

Files:

  • test/functional/rpc_blockchain.py
  • test/functional/feature_governance.py
  • test/functional/feature_new_quorum_type_activation.py
  • test/functional/feature_mnehf.py
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/util/setup_common.cpp
  • src/validation.h
  • src/kernel/coinstats.h
  • src/index/coinstatsindex.h
  • src/script/signingprovider.cpp
  • src/kernel/coinstats.cpp
  • src/test/descriptor_tests.cpp
  • src/util/system.cpp
  • src/versionbits.cpp
  • src/net_processing.cpp
  • src/test/fuzz/versionbits.cpp
  • src/test/blockfilter_index_tests.cpp
  • src/test/coinstatsindex_tests.cpp
  • src/test/evo_deterministicmns_tests.cpp
  • src/test/settings_tests.cpp
  • src/rpc/blockchain.cpp
  • src/init.cpp
  • src/validation.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/util/setup_common.cpp
  • src/test/descriptor_tests.cpp
  • src/test/fuzz/versionbits.cpp
  • src/test/blockfilter_index_tests.cpp
  • src/test/coinstatsindex_tests.cpp
  • src/test/evo_deterministicmns_tests.cpp
  • src/test/settings_tests.cpp
doc/**

📄 CodeRabbit inference engine (CLAUDE.md)

Unless specifically prompted, avoid making changes to the doc directory (documentation)

Files:

  • doc/REST-interface.md
🧠 Learnings (1)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
🧬 Code graph analysis (18)
test/functional/rpc_blockchain.py (3)
test/functional/test_framework/util.py (1)
  • assert_equal (69-74)
test/functional/test_framework/test_framework.py (1)
  • start_node (649-658)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/util/setup_common.cpp (2)
src/validation.cpp (6)
  • chainparams (569-580)
  • chainparams (569-571)
  • chainparams (583-593)
  • chainparams (583-584)
  • chainparams (596-606)
  • chainparams (596-597)
src/chainparams.cpp (2)
  • Params (1354-1357)
  • Params (1354-1354)
src/validation.h (1)
src/validation.cpp (5)
  • ChainstateManager (6049-6059)
  • ProcessNewBlock (4435-4472)
  • ProcessNewBlock (4435-4435)
  • ProcessNewBlockHeaders (4314-4341)
  • ProcessNewBlockHeaders (4314-4314)
src/kernel/coinstats.h (2)
src/rpc/blockchain.h (2)
  • kernel (26-28)
  • node (33-36)
src/kernel/coinstats.cpp (9)
  • CCoinsStats (21-23)
  • GetBogoSize (26-34)
  • GetBogoSize (26-26)
  • TxOutSer (36-42)
  • TxOutSer (36-36)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/index/coinstatsindex.h (2)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/index/coinstatsindex.cpp (2)
  • LookUpStats (320-345)
  • LookUpStats (320-320)
src/script/signingprovider.cpp (1)
src/script/descriptor.cpp (11)
  • scripts (759-764)
  • scripts (759-759)
  • pubkeys (512-512)
  • keys (712-712)
  • keys (712-712)
  • keys (723-728)
  • keys (723-723)
  • keys (742-749)
  • keys (742-742)
  • keys (780-793)
  • keys (780-780)
src/test/descriptor_tests.cpp (1)
src/script/descriptor.cpp (6)
  • scripts (759-764)
  • scripts (759-759)
  • LEGACY (715-715)
  • LEGACY (731-731)
  • LEGACY (797-797)
  • nullopt (657-657)
src/util/system.cpp (2)
src/node/interfaces.cpp (16)
  • name (447-456)
  • name (447-447)
  • name (457-457)
  • name (457-457)
  • name (458-468)
  • name (458-458)
  • name (469-478)
  • name (469-469)
  • name (1130-1133)
  • name (1130-1130)
  • name (1134-1137)
  • name (1134-1134)
  • name (1138-1141)
  • name (1138-1138)
  • name (1142-1151)
  • name (1142-1142)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/versionbits.cpp (2)
src/validation.cpp (14)
  • pindex (2205-2205)
  • pindex (2205-2205)
  • pindex (2209-2215)
  • pindex (2209-2209)
  • pindex (3131-3138)
  • pindex (3131-3131)
  • params (2203-2203)
  • params (2203-2203)
  • params (2204-2204)
  • params (2204-2204)
  • params (2206-2206)
  • params (2206-2206)
  • params (2207-2207)
  • params (2207-2207)
src/test/fuzz/versionbits.cpp (15)
  • pindex (45-45)
  • pindex (45-45)
  • pindex (47-47)
  • pindex (47-47)
  • pindex (55-55)
  • pindex (55-55)
  • pindex (63-63)
  • pindex (63-63)
  • params (46-46)
  • params (46-46)
  • params (48-48)
  • params (48-48)
  • params (49-49)
  • params (49-49)
  • params (50-50)
test/functional/feature_governance.py (1)
src/rpc/blockchain.cpp (2)
  • getdeploymentinfo (1650-1696)
  • getdeploymentinfo (1650-1650)
src/test/fuzz/versionbits.cpp (1)
src/versionbits.cpp (4)
  • pindex (258-261)
  • pindex (258-258)
  • GetStateStatisticsFor (134-180)
  • GetStateStatisticsFor (134-134)
src/test/coinstatsindex_tests.cpp (2)
src/kernel/coinstats.cpp (1)
  • CCoinsStats (21-23)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (24-77)
src/test/settings_tests.cpp (2)
src/util/settings.cpp (2)
  • GetSetting (140-195)
  • GetSetting (140-145)
src/util/system.cpp (2)
  • GetSetting (1179-1185)
  • GetSetting (1179-1179)
src/rpc/blockchain.cpp (6)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (2)
  • CoinStatsHashType (24-77)
  • node (19-21)
src/rpc/server.cpp (2)
  • IsDeprecatedRPCEnabled (367-372)
  • IsDeprecatedRPCEnabled (367-367)
src/deploymentinfo.cpp (2)
  • DeploymentName (20-56)
  • DeploymentName (20-20)
src/rpc/server_util.cpp (4)
  • EnsureAnyNodeContext (28-45)
  • EnsureAnyNodeContext (28-28)
  • EnsureChainman (87-93)
  • EnsureChainman (87-87)
src/rest.cpp (1)
  • getdeploymentinfo (624-624)
src/init.cpp (4)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (24-77)
src/rpc/blockchain.cpp (2)
  • GetUTXOStats (1106-1129)
  • GetUTXOStats (1106-1110)
src/util/system.cpp (2)
  • CheckDiskSpace (158-164)
  • CheckDiskSpace (158-158)
src/fs.h (1)
  • quoted (94-97)
test/functional/feature_new_quorum_type_activation.py (1)
test/functional/test_framework/test_framework.py (1)
  • no_op (803-804)
test/functional/feature_mnehf.py (1)
test/functional/test_framework/test_framework.py (1)
  • generate (806-809)
src/validation.cpp (2)
src/kernel/coinstats.cpp (5)
  • CCoinsStats (21-23)
  • ComputeUTXOStats (100-137)
  • ComputeUTXOStats (100-100)
  • ComputeUTXOStats (139-165)
  • ComputeUTXOStats (139-139)
src/kernel/coinstats.h (1)
  • CoinStatsHashType (24-77)
🪛 Flake8 (7.3.0)
test/functional/rpc_blockchain.py

[error] 196-196: continuation line under-indented for hanging indent

(E121)

🪛 markdownlint-cli2 (0.18.1)
doc/REST-interface.md

88-88: Heading style
Expected: setext; Actual: atx

(MD003, heading-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: predict_conflicts
  • GitHub Check: Lint / Run linters
🔇 Additional comments (56)
test/functional/feature_new_quorum_type_activation.py (1)

25-25: Correct adjustment for upstream behavior change.

The increment from 9 to 10 blocks is necessary due to bitcoin#23508's change in elapsed block computation. With a window of 10 blocks, the 'started' status is now visible at block 10 (start of period 1) rather than block 9 (end of period 0), aligning with upstream behavior while preserving Dash's dynamic activation threshold logic.

src/script/signingprovider.cpp (1)

58-65: LGTM! Clean refactor to in-place member function.

The conversion from a free function to an in-place member function using move semantics is well-implemented. The use of container.merge() efficiently moves elements from b into this, preserving existing entries when keys conflict, and the returned reference enables method chaining.

src/test/descriptor_tests.cpp (3)

78-78: LGTM! Signature change aligns with upstream.

The parameter change from norm_prv to norm_pub is semantically correct—normalized descriptors should represent the public form. All call sites have been updated consistently throughout the test file.


237-243: LGTM! Temporary lifetime is safe.

The new merge pattern FlatSigningProvider{A}.Merge(FlatSigningProvider{B}) correctly creates temporaries that live until the end of the full expression, ensuring safe reference passing to IsSolvable and SignSignature. The rvalue reference binding in Merge works correctly with the temporary objects.


304-333: LGTM! Test cases updated consistently.

All test cases have been systematically updated to pass norm_pub as the third parameter, maintaining consistency with the new function signatures. The test data correctly provides normalized public descriptor forms.

src/test/fuzz/versionbits.cpp (4)

55-55: LGTM! Function signature correctly updated.

The signature change adds the optional signals parameter and renames pindexPrev to pindex, matching the updated implementation in src/versionbits.cpp (line 134).


224-231: LGTM! Proper initialization of statistics tracking.

The initialization correctly sets up baseline statistics reflecting the end of the previous period, with count and elapsed at zero and possible computed as (period >= threshold). The empty last_signals vector is properly initialized for per-block signalling history.


253-270: LGTM! Comprehensive validation of statistics collection.

The test thoroughly validates the new signalling API by:

  • Collecting statistics both with and without the signals parameter and asserting consistency (lines 254-258)
  • Validating per-block signal vector evolution: size growth, current signal value, and cumulative history (lines 267-270)

This ensures the optional signalling_blocks parameter doesn't affect core statistics computation.


287-289: LGTM! Final period-end assertions are correct.

The assertions properly validate that at the period boundary:

  • elapsed equals the full period length
  • count matches the total number of signalling blocks
  • possible is correctly computed using the formula (count + period >= elapsed + threshold)
src/versionbits.cpp (6)

134-134: LGTM! Function signature correctly extended.

The signature now accepts an optional signalling_blocks parameter to enable per-block signalling data collection, consistent with the upstream backport (bitcoin#23508).


141-149: LGTM! Proper initialization of period tracking.

The code correctly:

  • Returns early with zero-initialized stats when pindex is nullptr
  • Calculates blocks_in_period as the number of blocks from the start of the current period through pindex (inclusive)
  • Initializes the signalling_blocks vector with the appropriate size

152-159: LGTM! Preserves Dash-specific threshold logic.

The code correctly retains pindexEndOfPrevPeriod for dynamic threshold calculation (Dash-specific logic from dash#3692) while no longer using it to compute elapsed, aligning with the PR objective and upstream behavior change from bitcoin#23508.


162-173: LGTM! Loop logic correctly counts blocks and populates signalling data.

The do-while loop properly:

  • Counts blocks in the current period by incrementing elapsed
  • Uses blocks_in_period as a countdown index for the signalling_blocks vector
  • Populates signalling_blocks in chronological order (index 0 = earliest block in period)
  • Terminates when all blocks in the period have been processed

The indexing is safe: blocks_in_period is decremented before use (line 167), ensuring access within valid range [0, blocks_in_period-1].


175-175: LGTM! Elapsed now computed directly from block counting.

Setting stats.elapsed from the loop counter rather than deriving it from pindexEndOfPrevPeriod implements the upstream behavior change from bitcoin#23508. This approach is more explicit and straightforward.


276-279: LGTM! Statistics wrapper correctly updated.

The VersionBitsCache::Statistics method signature is properly extended to accept the signalling_blocks parameter and forwards it to the underlying GetStateStatisticsFor implementation. The parameter name change from pindexPrev to pindex maintains consistency with the implementation.

src/test/coinstatsindex_tests.cpp (2)

15-16: LGTM! Namespace migration correctly applied.

The using declarations properly reference the kernel namespace for CCoinsStats and CoinStatsHashType, aligning with the API relocation described in the PR objectives.


31-31: LGTM! Test correctly adapted to optional-returning API.

The test properly handles the new LookUpStats signature that returns std::optional<kernel::CCoinsStats> instead of taking an out-parameter. The boolean checks leverage implicit conversion from optional (nullopt converts to false, populated optional converts to true).

Also applies to: 47-47, 50-50, 64-64

src/test/evo_deterministicmns_tests.cpp (1)

266-266: LGTM! ProcessNewBlock calls consistently updated.

All 9 call sites correctly adapted to the new signature that no longer requires the Params() argument. The ChainstateManager now internally manages chain parameters, simplifying the call sites.

Also applies to: 276-276, 304-304, 322-322, 342-342, 642-642, 788-788, 821-821, 833-833

src/test/blockfilter_index_tests.cpp (2)

105-105: LGTM! ProcessNewBlockHeaders signature correctly updated.

The call properly omits the Params() argument, aligning with the API change where ChainstateManager now manages chain parameters internally.


177-177: LGTM! ProcessNewBlock calls consistently updated.

All three call sites correctly adapted to remove the Params() argument, consistent with the signature changes throughout the codebase.

Also applies to: 195-195, 226-226

src/util/system.cpp (4)

562-575: LGTM! Clean extension for backup file support.

The addition of the backup parameter with conditional ".bak" suffix appending is straightforward and maintains backward compatibility with the default false value.


611-629: LGTM! Backup support correctly propagated.

The WriteSettingsFile method properly passes the backup flag to both GetSettingsPath calls (for the target path and temporary path), ensuring consistent backup file naming.


631-636: LGTM! GetPersistentSetting correctly filters transient settings.

The new method appropriately calls util::GetSetting with ignore_nonpersistent=true, ensuring that only configuration file and read/write settings file values are returned, excluding command-line arguments and forced settings. This is useful for distinguishing persistent configuration from runtime overrides.


1114-1114: LGTM! GetSetting calls correctly use extended signature.

The additional boolean parameters are properly set:

  • Line 1114 (GetChainName): Uses ignore_nonpersistent=false to include command-line chain selection arguments
  • Lines 1183-1184 (GetSetting): Uses ignore_nonpersistent=false, get_chain_name=false for standard setting retrieval

These parameter values align with the intended behavior for each context.

Also applies to: 1183-1184

src/net_processing.cpp (4)

2768-2770: Rename to tx_iter is fine; semantics unchanged.

Locked access, null/empty check, and deref remain correct. No action needed.


3502-3503: Updated ProcessNewBlock call aligns with new signature.

Force-processing and new_block semantics unchanged; mapBlockSource cleanup remains intact.


4731-4732: CMPCTBLOCK path: header processing migrated to new API.

Consistent with earlier change; invalid-header punishment remains correct.


3197-3198: ProcessNewBlockHeaders and ProcessNewBlock API migration verified across all call sites.

Verification confirms all 15+ call sites (net_processing.cpp, test files, rpc/mining.cpp) use the new 3-parameter signatures without chainparams. The target calls at lines 3197–3198 and 3502 match the updated API. Invalid state handling preserved. No old-style 4-parameter calls remain.

src/init.cpp (2)

137-137: Namespace swap acknowledged.

Switching to using kernel::CoinStatsHashType; aligns with the move from node:: to kernel::.


1938-1939: Ctor update looks correct.

Constructing ChainstateManager(chainparams) matches the new API and centralizes param access.

src/kernel/coinstats.h (1)

23-30: API move to kernel namespace LGTM.

CoinStatsHashType and CCoinsStats relocation is consistent with callers.

src/kernel/coinstats.cpp (1)

139-165: ComputeUTXOStats dispatcher looks good.

Height/hash initialization and hash-type routing align with upstream patterns.

If you want, we can sanity-check that all call sites expect std::optional<CCoinsStats>.

src/validation.h (4)

17-20: Include additions acceptable.

Pulling in chainparams.h and deploymentstatus.h here is consistent with the new inline wrappers.


908-931: ChainstateManager now owns params — good direction.

m_chainparams + GetParams()/GetConsensus() centralize access and simplify callers.


1082-1100: Wrapper Deployment helpers LGTM.*

Inline wrappers delegate to deploymentstatus.h using consensus from chainman.


1046-1059: All call sites correctly use ChainstateManager — no stale or unqualified calls found.

Verification of ProcessNewBlock and ProcessNewBlockHeaders call sites shows all usages are properly qualified:

  • Method definitions in src/validation.cpp correctly implement ChainstateManager::ProcessNewBlock and ChainstateManager::ProcessNewBlockHeaders
  • All 25 ProcessNewBlock call sites use qualified member access (e.g., m_chainman.ProcessNewBlock(), chainman.ProcessNewBlock())
  • All 8 ProcessNewBlockHeaders call sites similarly use qualified member access
  • No stale free-function calls or unqualified invocations detected

The signature changes have been successfully propagated throughout the codebase.

src/rpc/blockchain.cpp (7)

23-23: LGTM: Namespace migration properly implemented.

The include and using declarations correctly reflect the migration of CCoinsStats and CoinStatsHashType to the kernel namespace.

Also applies to: 66-68


1106-1129: LGTM: Well-structured optional return pattern.

The GetUTXOStats function correctly implements the optional return pattern with proper branching for index vs. direct computation paths. The CHECK_NONFATAL on line 1126 appropriately enforces the invariant that without the coinstats index, the pindex must match the view's best block.


1229-1276: LGTM: Proper optional handling with error reporting.

The optional return values from GetUTXOStats are handled correctly with appropriate error messages when stats cannot be retrieved. The nested optional handling for prev_stats (lines 1250-1257) is also correct.


1579-1582: LGTM: Proper deprecation handling.

The conditional inclusion of softforks data based on the -deprecatedrpc=softforks flag correctly implements the breaking change mentioned in the PR objectives. The help text appropriately marks the field as optional and deprecated.


1650-1696: LGTM: New getdeploymentinfo RPC properly implemented.

The new RPC provides a clean replacement for the deprecated softforks field in getblockchaininfo. The implementation correctly:

  • Accepts an optional blockhash parameter
  • Fetches EHF signals from mnhf_manager
  • Returns comprehensive deployment information via DeploymentInfo

2825-2889: LGTM: Correct optional handling in CreateUTXOSnapshot.

The optional CCoinsStats is properly checked at line 2846 before being accessed throughout the rest of the function. All member accesses use the -> operator on the optional after confirming it has a value.


2907-2907: LGTM: RPC command properly registered.

The getdeploymentinfo RPC is correctly added to the blockchain command table.

src/validation.cpp (13)

22-22: Kernel coinstats migration looks correct.

Header and using-decls align with the new ComputeUTXOStats API. No issues.

Also applies to: 69-72


1023-1027: Consensus checks use chainman-driven flags — LGTM.

Using GetBlockScriptFlags(tip, m_chainman) keeps mempool cache checks consistent with active consensus.


1432-1441: Using active_chainstate.m_params in ProcessNewPackage.

Good removal of ::Params() here; consistent with storing CChainParams in CChainState.


1656-1658: CChainState now caches params from ChainstateManager.

Solid dependency direction; avoids globals. No concerns.


2416-2421: CSV enforcement and script flags now use ChainstateManager.

This brings ConnectBlock in line with the new deployment helpers. Looks good.


4084-4104: Checkpoints and version gating via chainman — LGTM.

Uses blockman + chainman params correctly.


4183-4311: ChainstateManager::AcceptBlockHeader updated to use internal params/consensus.

Flow and failure handling preserved. Good.


4315-4341: ProcessNewBlockHeaders refactor — progress log OK.

Minor: progress estimation can be noisy early; optional clamp already present. No action required.


4356-4433: AcceptBlock switched to ContextualCheckBlock(chainman).

Consistent with header changes; state updates maintained.


4435-4472: ProcessNewBlock uses GetConsensus() and AcceptBlock flow unchanged.

Good lock scoping and signals. No issues.


4519-4540: TestBlockValidity updated to chainman-based context.

Matches new signatures; good.


4115-4181: ContextualCheckBlock migration verified — all call sites updated correctly.

Search confirms that both call sites (lines 4396 and 4526 in src/validation.cpp) pass the new chainman parameter. No lingering old-style calls exist.


352-354: GetBlockScriptFlags refactor verified — all call sites properly updated.

Comprehensive search of the C++ codebase confirms all GetBlockScriptFlags references are using the new signature with ChainstateManager parameter. Both call sites (lines 1022 and 2420) are correctly passing chainman arguments. No stale calls remain.

Comment on lines +2291 to +2307
int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());

// On first startup, warn on low block storage space
if (!fReindex && !fReindexChainState && chain_active_height <= 1) {
uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
: chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024;

if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
InitWarning(strprintf(_(
"Disk space for %s may not accommodate the block files. " \
"Approximately %u GB of data will be stored in this directory."
),
fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
chainparams.AssumedBlockchainSize()
));
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix first‑startup disk‑space warning for -prune=1.

For manual prune (-prune=1) nPruneTarget == UINT64_MAX, so this branch always warns. Use the smaller of nPruneTarget and AssumedBlockchainSize().

-    // On first startup, warn on low block storage space
+    // On first startup, warn on low block storage space
     if (!fReindex && !fReindexChainState && chain_active_height <= 1) {
-        uint64_t additional_bytes_needed = fPruneMode ? nPruneTarget
-            : chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024;
+        const uint64_t approx_chain_bytes =
+            static_cast<uint64_t>(chainparams.AssumedBlockchainSize()) * 1024 * 1024 * 1024;
+        uint64_t additional_bytes_needed =
+            fPruneMode ? std::min(nPruneTarget, approx_chain_bytes) : approx_chain_bytes;
 
-        if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
-            InitWarning(strprintf(_(
-                    "Disk space for %s may not accommodate the block files. " \
-                    "Approximately %u GB of data will be stored in this directory."
-                ),
-                fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
-                chainparams.AssumedBlockchainSize()
-            ));
-        }
+        if (!CheckDiskSpace(args.GetBlocksDirPath(), additional_bytes_needed)) {
+            InitWarning(strprintf(_("Disk space for %s may not accommodate the block files. Approximately %u GB of data will be stored in this directory."),
+                fs::quoted(fs::PathToString(args.GetBlocksDirPath())),
+                chainparams.AssumedBlockchainSize()));
+        }
     }
🤖 Prompt for AI Agents
In src/init.cpp around lines 2291-2307, the first-startup disk-space warning
uses nPruneTarget directly when fPruneMode is true, but nPruneTarget ==
UINT64_MAX for manual prune (-prune=1) so the code always warns; compute the
assumed blockchain size in bytes (chainparams.AssumedBlockchainSize() * 1024 *
1024 * 1024) and when fPruneMode is true set additional_bytes_needed to the
smaller of nPruneTarget and that assumed size (use std::min), otherwise use the
assumed size; keep the displayed GB value as
chainparams.AssumedBlockchainSize().

Comment on lines +1415 to 1492
static void SoftForkDescPushBack(const CBlockIndex* blockindex, const std::unordered_map<uint8_t, int>& signals, UniValue& softforks, const ChainstateManager& chainman, Consensus::DeploymentPos id)
{
// For BIP9 deployments.

if (!DeploymentEnabled(consensusParams, id)) return;
if (!DeploymentEnabled(chainman, id)) return;
if (blockindex == nullptr) return;

auto get_state_name = [](const ThresholdState state) -> std::string {
switch (state) {
case ThresholdState::DEFINED: return "defined";
case ThresholdState::STARTED: return "started";
case ThresholdState::LOCKED_IN: return "locked_in";
case ThresholdState::ACTIVE: return "active";
case ThresholdState::FAILED: return "failed";
}
return "invalid";
};

UniValue bip9(UniValue::VOBJ);
const ThresholdState thresholdState = g_versionbitscache.State(active_chain_tip, consensusParams, id);
switch (thresholdState) {
case ThresholdState::DEFINED: bip9.pushKV("status", "defined"); break;
case ThresholdState::STARTED: bip9.pushKV("status", "started"); break;
case ThresholdState::LOCKED_IN: bip9.pushKV("status", "locked_in"); break;
case ThresholdState::ACTIVE: bip9.pushKV("status", "active"); break;
case ThresholdState::FAILED: bip9.pushKV("status", "failed"); break;
}
const bool has_signal = (ThresholdState::STARTED == thresholdState || ThresholdState::LOCKED_IN == thresholdState);

const ThresholdState next_state = g_versionbitscache.State(blockindex, chainman.GetConsensus(), id);
const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, chainman.GetConsensus(), id);

const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);

// BIP9 parameters
if (has_signal) {
bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
bip9.pushKV("bit", chainman.GetConsensus().vDeployments[id].bit);
}
bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
bip9.pushKV("ehf", consensusParams.vDeployments[id].useEHF);
if (auto it = signals.find(consensusParams.vDeployments[id].bit); it != signals.end()) {
bip9.pushKV("start_time", chainman.GetConsensus().vDeployments[id].nStartTime);
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);
}
int64_t since_height = g_versionbitscache.StateSinceHeight(active_chain_tip, consensusParams, id);

// BIP9 status
bip9.pushKV("status", get_state_name(current_state));
int64_t since_height = g_versionbitscache.StateSinceHeight(blockindex->pprev, chainman.GetConsensus(), id);
bip9.pushKV("since", since_height);
bip9.pushKV("status_next", get_state_name(next_state));

// BIP9 signalling status, if applicable
if (has_signal) {
UniValue statsUV(UniValue::VOBJ);
BIP9Stats statsStruct = g_versionbitscache.Statistics(active_chain_tip, consensusParams, id);
std::vector<bool> signals;
BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, chainman.GetConsensus(), id, &signals);
statsUV.pushKV("period", statsStruct.period);
statsUV.pushKV("elapsed", statsStruct.elapsed);
statsUV.pushKV("count", statsStruct.count);
if (ThresholdState::LOCKED_IN != thresholdState) {
if (ThresholdState::LOCKED_IN != current_state) {
statsUV.pushKV("threshold", statsStruct.threshold);
statsUV.pushKV("possible", statsStruct.possible);
}
bip9.pushKV("statistics", statsUV);

std::string sig;
sig.reserve(signals.size());
for (const bool s : signals) {
sig.push_back(s ? '#' : '-');
}
bip9.pushKV("signalling", sig);
}
if (ThresholdState::LOCKED_IN == thresholdState) {
bip9.pushKV("activation_height", since_height + static_cast<int>(consensusParams.vDeployments[id].nWindowSize));
if (ThresholdState::LOCKED_IN == current_state) {
bip9.pushKV("activation_height", since_height + static_cast<int>(chainman.GetConsensus().vDeployments[id].nWindowSize));
}
bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);

UniValue rv(UniValue::VOBJ);
rv.pushKV("type", "bip9");
rv.pushKV("bip9", bip9);
if (ThresholdState::ACTIVE == thresholdState) {
rv.pushKV("height", since_height);
if (ThresholdState::ACTIVE == next_state) {
rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, chainman.GetConsensus(), id));
}
rv.pushKV("active", ThresholdState::ACTIVE == thresholdState);
rv.pushKV("active", ThresholdState::ACTIVE == next_state);
rv.pushKV("bip9", bip9);

softforks.pushKV(DeploymentName(id), rv);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify null safety for pprev access.

Lines 1436 and 1454 access blockindex->pprev without checking if it's null. While BIP9 deployments typically activate well after the genesis block (where pprev would be null), this could still cause issues if:

  1. The function is called with a genesis block index
  2. g_versionbitscache.State() or StateSinceHeight() don't handle nullptr properly

Consider adding a defensive check:

if (!DeploymentEnabled(chainman, id)) return;
if (blockindex == nullptr) return;
if (blockindex->pprev == nullptr) return; // Add this check

Or verify that the versionbitscache functions safely handle nullptr for the block parameter.


🏁 Script executed:

#!/bin/bash
# Check if State and StateSinceHeight handle nullptr blocks
rg -n "ThresholdState.*State\s*\(" --type cpp -A 10 | head -30
rg -n "StateSinceHeight\s*\(" --type cpp -A 10 | head -30

Length of output: 4422


🏁 Script executed:

#!/bin/bash
# Find GetStateFor implementation and check how it handles nullptr
rg -n "GetStateFor\s*\(" --type cpp -A 15 | head -50

Length of output: 3859


🏁 Script executed:

#!/bin/bash
# Find StateSinceHeight implementation
rg -n "int\s+StateSinceHeight\s*\(" --type cpp -A 15

Length of output: 894


🏁 Script executed:

#!/bin/bash
# Check if there are any existing null checks for pindexPrev in versionbits
rg -n "pindexPrev.*nullptr\|nullptr.*pindexPrev" --type cpp -B 2 -A 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for how genesis block is typically handled (pprev is nullptr)
rg -n "genesis\|pprev.*nullptr" --type cpp --type h | head -20

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check callers of State() and StateSinceHeight() to see if they guard against nullptr pprev
rg -n "\.State\(.*pprev" --type cpp -B 3 -A 1

Length of output: 396


🏁 Script executed:

#!/bin/bash
# Look for practical usage patterns - does code generally pass nullptr?
rg -n "\.State\(\s*nullptr" --type cpp -B 2 -A 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if blockindex->pprev is validated before being passed to these functions elsewhere
rg -n "pprev\s*==\s*nullptr\|nullptr.*pprev" --type cpp src/rpc/ -B 2 -A 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at the full SoftForkDescPushBack to understand control flow better
sed -n '1415,1492p' src/rpc/blockchain.cpp

Length of output: 3444


🏁 Script executed:

#!/bin/bash
# Check versionbits.cpp more carefully for null handling in State
sed -n '270,290p' src/versionbits.cpp

Length of output: 971


🏁 Script executed:

#!/bin/bash
# Look for StateSinceHeight implementation in versionbits.cpp
rg -n "StateSinceHeight" src/versionbits.cpp -A 10

Length of output: 1695


🏁 Script executed:

#!/bin/bash
# Check VersionBitsConditionChecker to understand the actual implementation
rg -n "class VersionBitsConditionChecker" --type cpp -A 30

Length of output: 2461


🏁 Script executed:

#!/bin/bash
# Look for GetStateStatisticsFor to understand patterns
rg -n "GetStateStatisticsFor" src/versionbits.cpp -A 15 | head -40

Length of output: 1380


🏁 Script executed:

#!/bin/bash
# Check actual implementation of GetStateFor
rg -n "GetStateFor\s*\(" src/versionbits.cpp -A 20 | head -50

Length of output: 2280


🏁 Script executed:

#!/bin/bash
# Check if there's a guard for nullptr in the base implementation
rg -n "class.*Checker.*{" src/versionbits.cpp -A 50 | head -100

Length of output: 97


🏁 Script executed:

#!/bin/bash
# Look directly at versionbits.cpp for the complete function implementations
wc -l src/versionbits.cpp

Length of output: 23


🏁 Script executed:

#!/bin/bash
# Check the actual implementation line by line
sed -n '260,300p' src/versionbits.cpp

Length of output: 1782


🏁 Script executed:

#!/bin/bash
# Get full implementation of State and related functions
sed -n '1,100p' src/versionbits.cpp

Length of output: 4257


🏁 Script executed:

#!/bin/bash
# Look for how pprev nullptr is typically handled in consensus code
rg -n "pprev.*nullptr\|if.*pprev" --type cpp src/consensus/ -B 1 -A 1 | head -30

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Specifically search for GetStateFor in versionbits
grep -n "GetStateFor" src/versionbits.cpp

Length of output: 668


🏁 Script executed:

#!/bin/bash
# Find the actual class definition with GetStateFor implementation
cat src/versionbits.cpp | grep -n "GetStateFor\|ThresholdState" | head -30

Length of output: 1972


🏁 Script executed:

#!/bin/bash
# Look at versionbits implementation with extended context
head -400 src/versionbits.cpp | tail -150

Length of output: 6668


🏁 Script executed:

#!/bin/bash
# Search for where nullptr is explicitly tested with blocks
rg -n "if\s*\(\s*p.*[Bb]lock.*==\s*nullptr\|if\s*\(\s*!p.*[Bb]lock" --type cpp src/versionbits.cpp

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check simple practical thing - where is State() actually used with pprev?
rg -n "State\(" src/rpc/blockchain.cpp -B 2 -A 2

Length of output: 404


🏁 Script executed:

#!/bin/bash
# Check if this is a known issue or pattern
rg -n "blockindex->pprev" src/rpc/blockchain.cpp -B 2 -A 2

Length of output: 964


🏁 Script executed:

#!/bin/bash
# Try to get VersionBitsConditionChecker implementation
rg -n "class VersionBitsConditionChecker" src/versionbits.cpp -A 100 | head -120

Length of output: 4641


🏁 Script executed:

#!/bin/bash
# Final check - check if there are conditionals that prevent pprev nullptr
sed -n '1415,1465p' src/rpc/blockchain.cpp

Length of output: 2450


🏁 Script executed:

#!/bin/bash
# Look at actual usage and conditionals - extended view
sed -n '1410,1500p' src/rpc/blockchain.cpp

Length of output: 3962


🏁 Script executed:

#!/bin/bash
# Look at what calls this function to understand context better
rg -n "SoftForkDescPushBack" src/rpc/blockchain.cpp -B 5 -A 2

Length of output: 1537


🏁 Script executed:

#!/bin/bash
# Check if there's context about what blockindex values are passed
grep -n "SoftForkDescPushBack\|GetTip\|LookupBlockIndex" src/rpc/blockchain.cpp | head -20

Length of output: 1914


🏁 Script executed:

#!/bin/bash
# Look for the callers context - what calls SoftForkDescPushBack
rg -n "SoftForkDescPushBack\(" src/rpc/blockchain.cpp -B 10 | head -40

Length of output: 2133


🏁 Script executed:

#!/bin/bash
# Check RPC method that calls this
rg -n "getblockchaininfo\|softfork" src/rpc/blockchain.cpp -B 3 -A 3 | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at where this function is invoked
sed -n '1500,1600p' src/rpc/blockchain.cpp | head -50

Length of output: 3358


🏁 Script executed:

#!/bin/bash
# Find the actual caller and what blockindex is passed
rg -n "void.*BlockchainInfo\|getblockchaininfo" src/rpc/blockchain.cpp -A 50 | head -60

Length of output: 0


Add null check for genesis block to prevent crash in StateSinceHeight call.

Lines 1436 and 1454 pass blockindex->pprev to g_versionbitscache.State() and StateSinceHeight() without verifying it's not null. If this function is called with the genesis block (where pprev is null), GetStateSinceHeightFor() will dereference nullptr at versionbits.cpp:213 when accessing pindexPrev->nHeight.

Add a defensive check after line 1420:

if (blockindex->pprev == nullptr) return;

This prevents crashes when the RPC is invoked on the genesis block index, which while uncommon, is technically valid.

🤖 Prompt for AI Agents
In src/rpc/blockchain.cpp around lines 1415 to 1492, the code calls
g_versionbitscache.State(...) and StateSinceHeight(...) with blockindex->pprev
without ensuring pprev is non-null; this can crash when blockindex is the
genesis block. Add a defensive null check immediately after the early-return
checks (after the null check for blockindex) to return early if
blockindex->pprev == nullptr, preventing dereference of a null previous index
before any calls that use blockindex->pprev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant