test: Fix feature_dbcrash.py --usecli intermittent error
What changed, and why it matters
This is a fix for an unreliable test script, not a security fix in Bitcoin Core itself. The test intentionally crashes Bitcoin nodes to verify database crash recovery. When run with the --usecli option, the test sometimes failed because it only caught one type of error (OSError) but bitcoin-cli can raise a different error (CalledProcessError) when the node is temporarily unreachable. The change broadens the exception handling so the test can continue and verify the crash as intended. It does not change production code or introduce a vulnerability.
No security action required. Treat as a normal test reliability improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit modifies test/functional/feature_dbcrash.py. It changes verify_utxo_hash to catch Exception instead of only OSError, so that subprocess.CalledProcessError raised by bitcoin-cli during –usecli runs is also handled. It also converts restart_node’s expected_tip argument to a keyword-only argument and updates call sites. The change is purely in test infrastructure and improves test robustness; no node consensus, networking, wallet, or RPC runtime code is affected.
Changed components
test/functional/feature_dbcrash.pyInspect captured patch +4 / −4
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index b5b2f4e6..693bc50a 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -70,7 +70,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
self.start_nodes()
# Leave them unconnected, we'll use submitblock directly in this test
- def restart_node(self, node_index, expected_tip):
+ def restart_node(self, node_index, *, expected_tip):
"""Start up a given node id, wait for the tip to reach the given block hash, and calculate the utxo hash.
Exceptions during startup or subsequent RPC calls should indicate a node crash (due to -dbcrashratio), in which case we try again. Give up
@@ -139,7 +139,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
# wait_for_node_exit() enforces that bitcoind crashed.
self.wait_for_node_exit(i, timeout=30)
self.log.debug(f"Restarting node {i} after block hash {block_hash}")
- nodei_utxo_hash = self.restart_node(i, block_hash)
+ nodei_utxo_hash = self.restart_node(i, expected_tip=block_hash)
assert nodei_utxo_hash is not None
self.restart_counts[i] += 1
else:
@@ -168,9 +168,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
for i in range(3):
try:
nodei_utxo_hash = self.nodes[i].gettxoutsetinfo()['hash_serialized_3']
- except OSError:
+ except Exception:
# probably a crash on db flushing
- nodei_utxo_hash = self.restart_node(i, self.nodes[3].getbestblockhash())
+ nodei_utxo_hash = self.restart_node(i, expected_tip=self.nodes[3].getbestblockhash())
assert_equal(nodei_utxo_hash, node3_utxo_hash)
def generate_small_transactions(self, node, count, utxo_list):
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.