From d77f35762ff86caa29ab79f5134c7f1d6091752a Mon Sep 17 00:00:00 2001 From: pasta Date: Sun, 4 Oct 2026 00:15:46 -0400 Subject: [PATCH] fix(init): restore the txindex requirement when governance validation is enabled Governance looks up proposal collateral transactions through the transaction index, so a node running governance validation with -txindex=0 rejects every proposal as "Invalid proposal collateral", and adds misbehavior score to every peer that relays one. Commit 91129d4eb1 removed the LoadChainstate check that refused this combination outside regtest, on the assumption that governance is now force-disabled in this case. Nothing does that: only -prune soft-sets -disablegovernance, so an explicit -txindex=0 starts a node with governance enabled and no warning. Bring the check back in AppInitParameterInteraction with the original error message and the regtest exemption, and cover it with a devnet functional test. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/init.cpp | 7 ++++ .../feature_governance_txindex_devnet.py | 35 +++++++++++++++++++ test/functional/test_runner.py | 1 + 3 files changed, 43 insertions(+) create mode 100755 test/functional/feature_governance_txindex_devnet.py diff --git a/src/init.cpp b/src/init.cpp index 4683a409b123..4fe62a4be749 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1439,6 +1439,13 @@ bool AppInitParameterInteraction(const ArgsManager& args) } } + // Governance needs the transaction index to look up proposal collateral transactions + if (!args.GetBoolArg("-disablegovernance", !DEFAULT_GOVERNANCE_ENABLE) && + !args.GetBoolArg("-txindex", DEFAULT_TXINDEX) && chainparams.NetworkIDString() != CBaseChainParams::REGTEST) { + return InitError(_("Transaction index can't be disabled with governance validation enabled. Either start with " + "-disablegovernance command line switch or enable transaction index.")); + } + if (args.GetBoolArg("-disablegovernance", !DEFAULT_GOVERNANCE_ENABLE)) { InitWarning(_("You are starting with governance validation disabled.") + (fPruneMode ? diff --git a/test/functional/feature_governance_txindex_devnet.py b/test/functional/feature_governance_txindex_devnet.py new file mode 100755 index 000000000000..6986bbfb2e50 --- /dev/null +++ b/test/functional/feature_governance_txindex_devnet.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# Copyright (c) 2026 The Dash Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test that a node refuses to run governance validation without the transaction index outside regtest. + +Regtest exempts nodes from this check, so it is exercised on devnet here. +""" + +from test_framework.governance import EXPECTED_STDERR_NO_GOV +from test_framework.test_framework import BitcoinTestFramework + + +class GovernanceTxindexDevnetTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.chain = "devnet" + self.num_nodes = 1 + + def run_test(self): + self.stop_node(0) + + self.log.info("Test that -txindex=0 is refused while governance validation is enabled") + self.nodes[0].assert_start_raises_init_error( + extra_args=["-txindex=0"], + expected_msg="Error: Transaction index can't be disabled with governance validation enabled. " + "Either start with -disablegovernance command line switch or enable transaction index.") + + self.log.info("Test that -txindex=0 is allowed together with -disablegovernance") + self.start_node(0, extra_args=["-txindex=0", "-disablegovernance"]) + self.stop_node(0, expected_stderr=EXPECTED_STDERR_NO_GOV) + + +if __name__ == '__main__': + GovernanceTxindexDevnetTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 919d68679b47..0b5e675ae1c8 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -340,6 +340,7 @@ 'p2p_compactblocks_blocksonly.py', 'p2p_mutated_blocks.py', # NOTE: needs dash_hash to pass 'p2p_connect_to_devnet.py', + 'feature_governance_txindex_devnet.py', 'feature_sporks.py', 'rpc_getblockstats.py', 'feature_bind_port_externalip.py',