What changed, and why it matters
This commit is a routine cleanup of Bitcoin Core's functional test code. It removes a helper method called convert_to_json_for_cli that was used to wrap arguments when tests were run against the command-line bitcoin-cli tool. The change only affects internal test scripts and has no impact on the live Bitcoin network, wallets, or node security.
No action required. This is a test-only refactoring with no security relevance.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch deletes the convert_to_json_for_cli() helper from test_framework.py and updates six functional tests to pass raw Python values (block hashes, heights, hex strings) directly to RPC calls instead of JSON-encoding them first. The helper was originally needed because bitcoin-cli expects JSON-encoded arguments, but the test framework’s RPC proxy now handles this conversion automatically. No production code, consensus logic, networking, or wallet handling is modified.
Changed components
test/functional/test_framework/test_framework.pytest/functional/feature_assumeutxo.pytest/functional/feature_coinstatsindex.pytest/functional/feature_index_prune.pytest/functional/rpc_getblockstats.pytest/functional/wallet_reorgsrestore.pyInspect captured patch +13 / −20
diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py
index fc3c359c..20ebd823 100755
--- a/test/functional/feature_assumeutxo.py
+++ b/test/functional/feature_assumeutxo.py
@@ -481,7 +481,7 @@ class AssumeutxoTest(BitcoinTestFramework):
# Use a hash instead of a height
prev_snap_hash = n0.getblockhash(prev_snap_height)
- dump_output5 = n0.dumptxoutset('utxos5.dat', rollback=self.convert_to_json_for_cli(prev_snap_hash))
+ dump_output5 = n0.dumptxoutset('utxos5.dat', rollback=prev_snap_hash)
assert_equal(sha256sum_file(dump_output4['path']), sha256sum_file(dump_output5['path']))
# Ensure n0 is back at the tip
diff --git a/test/functional/feature_coinstatsindex.py b/test/functional/feature_coinstatsindex.py
index 13f321bc..6405be41 100755
--- a/test/functional/feature_coinstatsindex.py
+++ b/test/functional/feature_coinstatsindex.py
@@ -103,7 +103,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
assert_equal(res0, res2)
# Fetch old stats by hash
- res3 = index_node.gettxoutsetinfo(hash_option, self.convert_to_json_for_cli(res0['bestblock']))
+ res3 = index_node.gettxoutsetinfo(hash_option, res0['bestblock'])
del res3['block_info'], res3['total_unspendable_amount']
res3.pop('muhash', None)
assert_equal(res0, res3)
@@ -242,7 +242,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
assert_equal(res12, res10)
self.log.info("Test obtaining info for a non-existent block hash")
- assert_raises_rpc_error(-5, "Block not found", index_node.gettxoutsetinfo, hash_type="none", hash_or_height=self.convert_to_json_for_cli("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), use_index=True)
+ assert_raises_rpc_error(-5, "Block not found", index_node.gettxoutsetinfo, hash_type="none", hash_or_height="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", use_index=True)
def _test_use_index_option(self):
self.log.info("Test use_index option for nodes running the index")
@@ -277,7 +277,7 @@ class CoinStatsIndexTest(BitcoinTestFramework):
assert_not_equal(res["muhash"], res_invalid["muhash"])
# Test that requesting reorged out block by hash is still returning correct results
- res_invalid2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=self.convert_to_json_for_cli(reorg_block))
+ res_invalid2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=reorg_block)
assert_equal(res_invalid2["muhash"], res_invalid["muhash"])
assert_not_equal(res["muhash"], res_invalid2["muhash"])
diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py
index 1b28de59..81c75f2f 100755
--- a/test/functional/feature_index_prune.py
+++ b/test/functional/feature_index_prune.py
@@ -67,7 +67,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(tip)['filter']), 0)
for node in stats_nodes:
- assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(tip))['muhash']
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
self.generate(self.nodes[0], 500)
self.sync_index(height=700)
@@ -85,14 +85,14 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(tip)['filter']), 0)
for node in stats_nodes:
- assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(tip))['muhash']
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=tip)['muhash']
self.log.info("check if we can access the blockfilter and coinstats of a pruned block")
height_hash = self.nodes[0].getblockhash(2)
for node in filter_nodes:
assert_greater_than(len(node.getblockfilter(height_hash)['filter']), 0)
for node in stats_nodes:
- assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(height_hash))['muhash']
+ assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=height_hash)['muhash']
# mine and sync index up to a height that will later be the pruneheight
self.generate(self.nodes[0], 51)
@@ -106,7 +106,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, msg, node.getblockfilter, height_hash)
for node in stats_nodes:
msg = "Querying specific block heights requires coinstatsindex"
- assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", self.convert_to_json_for_cli(height_hash))
+ assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", height_hash)
self.generate(self.nodes[0], 749)
diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py
index 67452cac..7def4f8f 100755
--- a/test/functional/rpc_getblockstats.py
+++ b/test/functional/rpc_getblockstats.py
@@ -119,7 +119,7 @@ class GetblockstatsTest(BitcoinTestFramework):
# Check selecting block by hash too
blockhash = self.expected_stats[i]['blockhash']
- stats_by_hash = self.nodes[0].getblockstats(hash_or_height=self.convert_to_json_for_cli(blockhash))
+ stats_by_hash = self.nodes[0].getblockstats(hash_or_height=blockhash)
assert_equal(stats_by_hash, self.expected_stats[i])
# Make sure each stat can be queried on its own
@@ -161,10 +161,10 @@ class GetblockstatsTest(BitcoinTestFramework):
self.nodes[0].getblockstats, hash_or_height=1, stats=['minfee', f'aaa{inv_sel_stat}'])
# Mainchain's genesis block shouldn't be found on regtest
assert_raises_rpc_error(-5, 'Block not found', self.nodes[0].getblockstats,
- hash_or_height=self.convert_to_json_for_cli('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'))
+ hash_or_height='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')
# Invalid number of args
- assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, self.convert_to_json_for_cli('00'), 1, 2)
+ assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats, '00', 1, 2)
assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats)
self.log.info('Test block height 0')
@@ -185,7 +185,7 @@ class GetblockstatsTest(BitcoinTestFramework):
self.log.info("Test when only header is known")
block = self.generateblock(self.nodes[0], output="raw(55)", transactions=[], submit=False)
self.nodes[0].submitheader(block["hex"])
- assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: self.nodes[0].getblockstats(self.convert_to_json_for_cli(block['hash'])))
+ assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: self.nodes[0].getblockstats(block['hash']))
self.log.info('Test when block is missing')
(self.nodes[0].blocks_path / 'blk00000.dat').rename(self.nodes[0].blocks_path / 'blk00000.dat.backup')
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index 1ec10b28..47339761 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -8,7 +8,6 @@ import configparser
from enum import Enum
import argparse
from datetime import datetime, timezone
-import json
import logging
import os
import platform
@@ -1106,11 +1105,6 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def has_blockfile(self, node, filenum: str):
return (node.blocks_path/ f"blk{filenum}.dat").is_file()
- def convert_to_json_for_cli(self, text):
- if self.options.usecli:
- return json.dumps(text)
- return text
-
def inspect_sqlite_db(self, path, fn, *args, **kwargs):
try:
import sqlite3 # type: ignore[import]
@@ -1121,4 +1115,3 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
return result
except ImportError:
self.log.warning("sqlite3 module not available, skipping tests that inspect the database")
-
diff --git a/test/functional/wallet_reorgsrestore.py b/test/functional/wallet_reorgsrestore.py
index c8dc24cb..00693db8 100755
--- a/test/functional/wallet_reorgsrestore.py
+++ b/test/functional/wallet_reorgsrestore.py
@@ -104,7 +104,7 @@ class ReorgsRestoreTest(BitcoinTestFramework):
# Disconnect tip and sync wallet state
tip = wallet.getbestblockhash()
- tip_height = wallet.getblockstats(hash_or_height=self.convert_to_json_for_cli(tip))["height"]
+ tip_height = wallet.getblockstats(hash_or_height=tip)["height"]
wallet.invalidateblock(tip)
wallet.syncwithvalidationinterfacequeue()
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.