diff --git a/ci/test/00_setup_env_i686_multiprocess.sh b/ci/test/00_setup_env_i686_multiprocess.sh index 3144cf22fc..e19a45d169 100755 --- a/ci/test/00_setup_env_i686_multiprocess.sh +++ b/ci/test/00_setup_env_i686_multiprocess.sh @@ -13,7 +13,7 @@ export CI_IMAGE_PLATFORM="linux/amd64" export PACKAGES="llvm clang g++-multilib" export DEP_OPTS="DEBUG=1 MULTIPROCESS=1" export GOAL="install" -export TEST_RUNNER_EXTRA="--v2transport" +export TEST_RUNNER_EXTRA="--v2transport --usecli" export BITCOIN_CONFIG="\ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_C_COMPILER='clang;-m32' \ diff --git a/test/functional/feature_assumeutxo.py b/test/functional/feature_assumeutxo.py index a1213cbb1c..f044b6951e 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=prev_snap_hash) + dump_output5 = n0.dumptxoutset('utxos5.dat', rollback=self.convert_to_json_for_cli(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 7d43d06649..73f3e39372 100755 --- a/test/functional/feature_coinstatsindex.py +++ b/test/functional/feature_coinstatsindex.py @@ -41,7 +41,6 @@ class CoinStatsIndexTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 - self.supports_cli = False self.extra_args = [ [], ["-coinstatsindex"] @@ -104,7 +103,7 @@ class CoinStatsIndexTest(BitcoinTestFramework): assert_equal(res0, res2) # Fetch old stats by hash - res3 = index_node.gettxoutsetinfo(hash_option, res0['bestblock']) + res3 = index_node.gettxoutsetinfo(hash_option, self.convert_to_json_for_cli(res0['bestblock'])) del res3['block_info'], res3['total_unspendable_amount'] res3.pop('muhash', None) assert_equal(res0, res3) @@ -243,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="ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", use_index=True) + 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) def _test_use_index_option(self): self.log.info("Test use_index option for nodes running the index") @@ -278,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=reorg_block) + res_invalid2 = index_node.gettxoutsetinfo(hash_type='muhash', hash_or_height=self.convert_to_json_for_cli(reorg_block)) assert_equal(res_invalid2["muhash"], res_invalid["muhash"]) assert_not_equal(res["muhash"], res_invalid2["muhash"]) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index b6f16eedf5..ec7688e0b4 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -100,7 +100,6 @@ class BIP68_112_113Test(BitcoinTestFramework): self.extra_args = [[ f'-testactivationheight=csv@{CSV_ACTIVATION_HEIGHT}', ]] - self.supports_cli = False def create_self_transfer_from_utxo(self, input_tx): utxo = self.miniwallet.get_utxo(txid=input_tx.txid_hex, mark_as_spent=False) diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py index 81c75f2f02..1b28de5962 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=tip)['muhash'] + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(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=tip)['muhash'] + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(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=height_hash)['muhash'] + assert node.gettxoutsetinfo(hash_type="muhash", hash_or_height=self.convert_to_json_for_cli(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", height_hash) + assert_raises_rpc_error(-8, msg, node.gettxoutsetinfo, "muhash", self.convert_to_json_for_cli(height_hash)) self.generate(self.nodes[0], 749) diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index b72090b436..526f2ffa90 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -52,7 +52,6 @@ class MaxUploadTest(BitcoinTestFramework): self.extra_args = [[ f"-maxuploadtarget={UPLOAD_TARGET_MB}M", ]] - self.supports_cli = False def assert_uploadtarget_state(self, *, target_reached, serve_historical_blocks): """Verify the node's current upload target state via the `getnettotals` RPC call.""" diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index f5536027eb..bedfceee57 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -69,7 +69,6 @@ class PruneTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 6 - self.supports_cli = False self.uses_wallet = None # Create nodes 0 and 1 to mine. diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index 324dfa0817..3c9b21ddca 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -33,7 +33,6 @@ class ReplaceByFeeTest(BitcoinTestFramework): [ ], ] - self.supports_cli = False self.uses_wallet = None def run_test(self): diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index b9ee6a0a10..7c89dd98a7 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -31,7 +31,6 @@ class MempoolLimitTest(BitcoinTestFramework): self.extra_args = [[ "-maxmempool=5", ]] - self.supports_cli = False def test_rbf_carveout_disallowed(self): node = self.nodes[0] diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 680c132b98..53cb42f837 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -65,7 +65,6 @@ class MiningTest(BitcoinTestFramework): ["-fastprune", "-prune=1"] ] self.setup_clean_chain = True - self.supports_cli = False def mine_chain(self): self.log.info('Create some old blocks') diff --git a/test/functional/p2p_1p1c_network.py b/test/functional/p2p_1p1c_network.py index b098e4cf43..fbf242a06c 100755 --- a/test/functional/p2p_1p1c_network.py +++ b/test/functional/p2p_1p1c_network.py @@ -43,7 +43,6 @@ class PackageRelayTest(BitcoinTestFramework): self.extra_args = [[ "-maxmempool=5", ]] * self.num_nodes - self.supports_cli = False def raise_network_minfee(self): fill_mempool(self, self.nodes[0]) diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index 94be86475e..e7168b7254 100755 --- a/test/functional/p2p_disconnect_ban.py +++ b/test/functional/p2p_disconnect_ban.py @@ -15,7 +15,6 @@ from test_framework.util import ( class DisconnectBanTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 2 - self.supports_cli = False def run_test(self): self.log.info("Connect nodes both ways") diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py index 267a878323..fd955d86d7 100755 --- a/test/functional/p2p_opportunistic_1p1c.py +++ b/test/functional/p2p_opportunistic_1p1c.py @@ -61,7 +61,6 @@ class PackageRelayTest(BitcoinTestFramework): self.extra_args = [[ "-maxmempool=5", ]] - self.supports_cli = False def create_tx_below_mempoolminfee(self, wallet): """Create a 1-input 1sat/vB transaction using a confirmed UTXO. Decrement and use diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 0892d9d1a4..d2790f0382 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -221,7 +221,6 @@ class SegWitTest(BitcoinTestFramework): ["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "-par=1"], ["-acceptnonstdtxn=0", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}"], ] - self.supports_cli = False # Helper functions diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py index 654a22b149..1675aa0c52 100755 --- a/test/functional/rpc_createmultisig.py +++ b/test/functional/rpc_createmultisig.py @@ -28,7 +28,6 @@ class RpcCreateMultiSigTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - self.supports_cli = False def create_keys(self, num_keys): self.pub = [] diff --git a/test/functional/rpc_deprecated.py b/test/functional/rpc_deprecated.py index 043577ef11..6b0ef709ca 100755 --- a/test/functional/rpc_deprecated.py +++ b/test/functional/rpc_deprecated.py @@ -19,7 +19,7 @@ class DeprecatedRpcTest(BitcoinTestFramework): # such RPCs are fully removed. For example: # # self.log.info("Test generate RPC") - # assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].rpc.generate, 1) + # assert_raises_rpc_error(-32, 'The wallet generate rpc method is deprecated', self.nodes[0].generate, 1) # # Please ensure that for all the RPC methods tested here, there is # at least one other functional test that still tests the RPCs @@ -32,7 +32,7 @@ class DeprecatedRpcTest(BitcoinTestFramework): self.log.info("Tests for deprecated wallet-related RPC methods (if any)") self.log.info("Test settxfee RPC deprecation") self.nodes[0].createwallet("settxfeerpc") - assert_raises_rpc_error(-32, 'settxfee is deprecated and will be fully removed in v31.0.', self.nodes[0].rpc.settxfee, 0.01) + assert_raises_rpc_error(-32, 'settxfee is deprecated and will be fully removed in v31.0.', self.nodes[0].settxfee, 0.01) if __name__ == '__main__': DeprecatedRpcTest(__file__).main() diff --git a/test/functional/rpc_estimatefee.py b/test/functional/rpc_estimatefee.py index 05ceafbe4e..2b8772269e 100755 --- a/test/functional/rpc_estimatefee.py +++ b/test/functional/rpc_estimatefee.py @@ -21,17 +21,17 @@ class EstimateFeeTest(BitcoinTestFramework): assert_raises_rpc_error(-1, "estimatesmartfee", self.nodes[0].estimatesmartfee) assert_raises_rpc_error(-1, "estimaterawfee", self.nodes[0].estimaterawfee) - # wrong type for conf_target - assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimatesmartfee, 'foo') - assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 'foo') + # cli handles wrong types differently + if not self.options.usecli: + # wrong type for conf_target + assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimatesmartfee, 'foo') + assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 'foo') + # wrong type for estimatesmartfee(estimate_mode) + assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].estimatesmartfee, 1, 1) + # wrong type for estimaterawfee(threshold) + assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 1, 'foo') - # wrong type for estimatesmartfee(estimate_mode) - assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].estimatesmartfee, 1, 1) assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', self.nodes[0].estimatesmartfee, 1, 'foo') - - # wrong type for estimaterawfee(threshold) - assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].estimaterawfee, 1, 'foo') - # extra params assert_raises_rpc_error(-1, "estimatesmartfee", self.nodes[0].estimatesmartfee, 1, 'ECONOMICAL', 1) assert_raises_rpc_error(-1, "estimaterawfee", self.nodes[0].estimaterawfee, 1, 1, 1) diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 618bbb2e00..a68d9c3224 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -124,11 +124,12 @@ class RPCGenerateTest(BitcoinTestFramework): "cli option. Refer to -help for more information.\n" ) - self.log.info("Test rpc generate raises with message to use cli option") - assert_raises_rpc_error(-32601, message, self.nodes[0].rpc.generate) + if not self.options.usecli: + self.log.info("Test rpc generate raises with message to use cli option") + assert_raises_rpc_error(-32601, message, self.nodes[0]._rpc.generate) - self.log.info("Test rpc generate help prints message to use cli option") - assert_equal(message, self.nodes[0].help("generate")) + self.log.info("Test rpc generate help prints message to use cli option") + assert_equal(message, self.nodes[0].help("generate")) self.log.info("Test rpc generate is a hidden command not discoverable in general help") assert message not in self.nodes[0].help() diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index 05fe7699e0..a417ffcb31 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -67,8 +67,11 @@ class GetBlockFromPeerTest(BitcoinTestFramework): self.log.info("Arguments must be valid") assert_raises_rpc_error(-8, "hash must be of length 64 (not 4, for '1234')", self.nodes[0].getblockfrompeer, "1234", peer_0_peer_1_id) - assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].getblockfrompeer, 1234, peer_0_peer_1_id) - assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].getblockfrompeer, short_tip, "0") + + # cli handles wrong types differently + if not self.options.usecli: + assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", self.nodes[0].getblockfrompeer, 1234, peer_0_peer_1_id) + assert_raises_rpc_error(-3, "JSON value of type string is not of expected type number", self.nodes[0].getblockfrompeer, short_tip, "0") self.log.info("We must already have the header") assert_raises_rpc_error(-1, "Block header missing", self.nodes[0].getblockfrompeer, "00" * 32, 0) diff --git a/test/functional/rpc_getblockstats.py b/test/functional/rpc_getblockstats.py index 8a88aaa578..67452cacd6 100755 --- a/test/functional/rpc_getblockstats.py +++ b/test/functional/rpc_getblockstats.py @@ -36,7 +36,6 @@ class GetblockstatsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True - self.supports_cli = False def get_stats(self): return [self.nodes[0].getblockstats(hash_or_height=self.start_height + i) for i in range(self.max_stat_pos+1)] @@ -120,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=blockhash) + stats_by_hash = self.nodes[0].getblockstats(hash_or_height=self.convert_to_json_for_cli(blockhash)) assert_equal(stats_by_hash, self.expected_stats[i]) # Make sure each stat can be queried on its own @@ -162,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='000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f') + hash_or_height=self.convert_to_json_for_cli('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')) # Invalid number of args - 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.convert_to_json_for_cli('00'), 1, 2) assert_raises_rpc_error(-1, 'getblockstats hash_or_height ( stats )', self.nodes[0].getblockstats) self.log.info('Test block height 0') @@ -186,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(block['hash'])) + assert_raises_rpc_error(-1, "Block not available (not fully downloaded)", lambda: self.nodes[0].getblockstats(self.convert_to_json_for_cli(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/rpc_getdescriptorinfo.py b/test/functional/rpc_getdescriptorinfo.py index 65aa6dd47c..56a8faaff9 100755 --- a/test/functional/rpc_getdescriptorinfo.py +++ b/test/functional/rpc_getdescriptorinfo.py @@ -35,7 +35,9 @@ class DescriptorTest(BitcoinTestFramework): def run_test(self): assert_raises_rpc_error(-1, 'getdescriptorinfo', self.nodes[0].getdescriptorinfo) - assert_raises_rpc_error(-3, 'JSON value of type number is not of expected type string', self.nodes[0].getdescriptorinfo, 1) + # cli handles wrong types differently + if not self.options.usecli: + assert_raises_rpc_error(-3, 'JSON value of type number is not of expected type string', self.nodes[0].getdescriptorinfo, 1) assert_raises_rpc_error(-5, "'' is not a valid descriptor function", self.nodes[0].getdescriptorinfo, "") assert_raises_rpc_error(-5, "pk(): Key ' 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "pk( 0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)") assert_raises_rpc_error(-5, "pk(): Key '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 ' is invalid due to whitespace", self.nodes[0].getdescriptorinfo, "pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 )") diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index 01a633a83d..802a55492f 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -45,7 +45,6 @@ def process_mapping(fname): class HelpRpcTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.supports_cli = False self.uses_wallet = None def run_test(self): @@ -93,7 +92,8 @@ class HelpRpcTest(BitcoinTestFramework): assert_raises_rpc_error(-1, 'help', node.help, 'foo', 'bar') # invalid argument - assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", node.help, 0) + if not self.options.usecli: + assert_raises_rpc_error(-3, "JSON value of type number is not of expected type string", node.help, 0) # help of unknown command assert_equal(node.help('foo'), 'help: unknown command: foo') diff --git a/test/functional/rpc_invalid_address_message.py b/test/functional/rpc_invalid_address_message.py index bbd6955b56..25d8a68a1a 100755 --- a/test/functional/rpc_invalid_address_message.py +++ b/test/functional/rpc_invalid_address_message.py @@ -97,10 +97,12 @@ class InvalidAddressErrorMessageTest(BitcoinTestFramework): node = self.nodes[0] - # Missing arg returns the help text - assert_raises_rpc_error(-1, "Return information about the given bitcoin address.", node.validateaddress) - # Explicit None is not allowed for required parameters - assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", node.validateaddress, None) + + if not self.options.usecli: + # Missing arg returns the help text + assert_raises_rpc_error(-1, "Return information about the given bitcoin address.", node.validateaddress) + # Explicit None is not allowed for required parameters + assert_raises_rpc_error(-3, "JSON value of type null is not of expected type string", node.validateaddress, None) def test_getaddressinfo(self): node = self.nodes[0] diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index b5c12b28c1..3c7cce2f16 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -19,7 +19,6 @@ from test_framework.authproxy import JSONRPCException class RpcMiscTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.supports_cli = False def run_test(self): node = self.nodes[0] diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index 1bc9d4b76b..788098710b 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -36,7 +36,6 @@ class PreciousTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 - self.supports_cli = False def setup_network(self): self.setup_nodes() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 9527053a6f..236b05e26d 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -72,7 +72,6 @@ class PSBTTest(BitcoinTestFramework): # whitelist peers to speed up tx relay / mempool sync for args in self.extra_args: args.append("-whitelist=noban@127.0.0.1") - self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -96,7 +95,7 @@ class PSBTTest(BitcoinTestFramework): signed_psbt_obj.g.map[PSBT_GLOBAL_UNSIGNED_TX] = bytes.fromhex(raw) # Check that the walletprocesspsbt call succeeds but also recognizes that the transaction is not complete - signed_psbt_incomplete = wallet.walletprocesspsbt(signed_psbt_obj.to_base64(), finalize=False) + signed_psbt_incomplete = wallet.walletprocesspsbt(psbt=signed_psbt_obj.to_base64(), finalize=False) assert signed_psbt_incomplete["complete"] is False def test_utxo_conversion(self): @@ -1209,7 +1208,8 @@ class PSBTTest(BitcoinTestFramework): self.log.info("Test descriptorprocesspsbt raises if an invalid sighashtype is passed") assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[2].descriptorprocesspsbt, psbt, [descriptor], sighashtype="all") - self.test_sighash_mismatch() + if not self.options.usecli: + self.test_sighash_mismatch() self.test_sighash_adding() if __name__ == '__main__': diff --git a/test/functional/rpc_whitelist.py b/test/functional/rpc_whitelist.py index a35c89fadd..b103289fab 100755 --- a/test/functional/rpc_whitelist.py +++ b/test/functional/rpc_whitelist.py @@ -33,6 +33,7 @@ class RPCWhitelistTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 + self.supports_cli = False def run_test(self): # 0 => Username diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 5646e97bbc..0cb29f9eea 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -8,6 +8,7 @@ import configparser from enum import Enum import argparse from datetime import datetime, timezone +import json import logging import os import platform @@ -595,7 +596,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): node.wait_for_rpc_connection() if self.options.coveragedir is not None: - coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) + coverage.write_all_rpc_commands(self.options.coveragedir, node._rpc) def start_nodes(self, extra_args=None, *args, **kwargs): """Start multiple bitcoinds""" @@ -610,7 +611,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): if self.options.coveragedir is not None: for node in self.nodes: - coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) + coverage.write_all_rpc_commands(self.options.coveragedir, node._rpc) def stop_node(self, i, expected_stderr='', wait=0): """Stop a bitcoind test node""" @@ -1083,3 +1084,8 @@ 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 diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 9916fd7f9e..57b4b8c309 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -46,6 +46,8 @@ BITCOIND_PROC_WAIT_TIMEOUT = 60 # The size of the blocks xor key # from InitBlocksdirXorKey::xor_key.size() NUM_XOR_BYTES = 8 +CLI_MAX_ARG_SIZE = 131071 # many systems have a 128kb limit per arg (MAX_ARG_STRLEN) + # The null blocks key (all 0s) NULL_BLK_XOR_KEY = bytes([0] * NUM_XOR_BYTES) BITCOIN_PID_FILENAME_DEFAULT = "bitcoind.pid" @@ -153,7 +155,7 @@ class TestNode(): self.running = False self.process = None self.rpc_connected = False - self.rpc = None + self._rpc = None # Should usually not be accessed directly in tests to allow for --usecli mode self.reuse_http_connections = True # Must be set before calling get_rpc_proxy() i.e. before restarting node self.url = None self.log = logging.getLogger('TestFramework.node%d' % i) @@ -210,8 +212,8 @@ class TestNode(): if self.use_cli: return getattr(self.cli, name) else: - assert self.rpc_connected and self.rpc is not None, self._node_msg("Error: no RPC connection") - return getattr(self.rpc, name) + assert self.rpc_connected and self._rpc is not None, self._node_msg("Error: no RPC connection") + return getattr(self._rpc, name) def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, env=None, **kwargs): """Start the node.""" @@ -315,8 +317,8 @@ class TestNode(): self.rpc_connected = True if self.use_cli: return - self.rpc = rpc - self.url = self.rpc.rpc_url + self._rpc = rpc + self.url = self._rpc.rpc_url return except JSONRPCException as e: # Suppress these as they are expected during initialization. @@ -393,9 +395,9 @@ class TestNode(): if self.use_cli: return self.cli("-rpcwallet={}".format(wallet_name)) else: - assert self.rpc_connected and self.rpc, self._node_msg("RPC not connected") + assert self.rpc_connected and self._rpc, self._node_msg("RPC not connected") wallet_path = "wallet/{}".format(urllib.parse.quote(wallet_name)) - return self.rpc / wallet_path + return self._rpc / wallet_path def version_is_at_least(self, ver): return self.version is None or self.version >= ver @@ -450,7 +452,7 @@ class TestNode(): self.running = False self.process = None self.rpc_connected = False - self.rpc = None + self._rpc = None self.log.debug("Node stopped") return True @@ -879,7 +881,7 @@ def arg_to_cli(arg): return str(arg).lower() elif arg is None: return 'null' - elif isinstance(arg, dict) or isinstance(arg, list): + elif isinstance(arg, dict) or isinstance(arg, list) or isinstance(arg, tuple): return json.dumps(arg, default=serialization_fallback) else: return str(arg) @@ -916,16 +918,28 @@ class TestNodeCLI(): def send_cli(self, clicommand=None, *args, **kwargs): """Run bitcoin-cli command. Deserializes returned string as python object.""" pos_args = [arg_to_cli(arg) for arg in args] - named_args = [str(key) + "=" + arg_to_cli(value) for (key, value) in kwargs.items()] + named_args = [key + "=" + arg_to_cli(value) for (key, value) in kwargs.items() if value is not None] p_args = self.binaries.rpc_argv() + [f"-datadir={self.datadir}"] + self.options if named_args: p_args += ["-named"] + base_arg_pos = len(p_args) if clicommand is not None: p_args += [clicommand] p_args += pos_args + named_args + max_arg_size = max(len(arg) for arg in p_args) + stdin_data = self.input + if max_arg_size > CLI_MAX_ARG_SIZE: + self.log.debug(f"Cli: Command size {max_arg_size} too large, using stdin") + rpc_args = "\n".join([arg for arg in p_args[base_arg_pos:]]) + if stdin_data is not None: + stdin_data += "\n" + rpc_args + else: + stdin_data = rpc_args + p_args = p_args[:base_arg_pos] + ['-stdin'] + self.log.debug("Running bitcoin-cli {}".format(p_args[2:])) process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - cli_stdout, cli_stderr = process.communicate(input=self.input) + cli_stdout, cli_stderr = process.communicate(input=stdin_data) returncode = process.poll() if returncode: match = re.match(r'error code: ([-0-9]+)\nerror message:\n(.*)', cli_stderr) diff --git a/test/functional/wallet_address_types.py b/test/functional/wallet_address_types.py index cfb8f926f0..7f6cf73d9a 100755 --- a/test/functional/wallet_address_types.py +++ b/test/functional/wallet_address_types.py @@ -78,7 +78,6 @@ class AddressTypeTest(BitcoinTestFramework): ] # whitelist peers to speed up tx relay / mempool sync self.noban_tx_relay = True - self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_backwards_compatibility.py b/test/functional/wallet_backwards_compatibility.py index 864eed5a56..43001fb3f3 100755 --- a/test/functional/wallet_backwards_compatibility.py +++ b/test/functional/wallet_backwards_compatibility.py @@ -327,7 +327,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): for node in descriptors_nodes: self.log.info(f"- {node.version}") wallet_name = f"up_{node.version}" - node.rpc.createwallet(wallet_name=wallet_name, descriptors=True) + node.createwallet(wallet_name=wallet_name, descriptors=True) wallet_prev = node.get_wallet_rpc(wallet_name) address = wallet_prev.getnewaddress('', "bech32") addr_info = wallet_prev.getaddressinfo(address) @@ -395,9 +395,9 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): self.log.info(f"- {node.version}") wallet_name = f"legacy_up_{node.version}" if self.major_version_at_least(node, 21): - node.rpc.createwallet(wallet_name=wallet_name, descriptors=False) + node.createwallet(wallet_name=wallet_name, descriptors=False) else: - node.rpc.createwallet(wallet_name=wallet_name) + node.createwallet(wallet_name=wallet_name) wallet_prev = node.get_wallet_rpc(wallet_name) address = wallet_prev.getnewaddress('', "bech32") addr_info = wallet_prev.getaddressinfo(address) diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 23c1616f9c..bc641fa9bc 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -453,14 +453,14 @@ class WalletTest(BitcoinTestFramework): # - True: unicode escaped as \u.... # - False: unicode directly as UTF-8 for mode in [True, False]: - self.nodes[0].rpc.ensure_ascii = mode + self.nodes[0]._rpc.ensure_ascii = mode # unicode check: Basic Multilingual Plane, Supplementary Plane respectively for label in [u'рыба', u'𝅘𝅥𝅯']: addr = self.nodes[0].getnewaddress() self.nodes[0].setlabel(addr, label) test_address(self.nodes[0], addr, labels=[label]) assert label in self.nodes[0].listlabels() - self.nodes[0].rpc.ensure_ascii = True # restore to default + self.nodes[0]._rpc.ensure_ascii = True # restore to default # -reindex tests chainlimit = 6 diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 00ce40b447..05965caacd 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -139,8 +139,9 @@ class BumpFeeTest(BitcoinTestFramework): assert_raises_rpc_error(-8, msg, rbf_node.bumpfee, rbfid, fee_rate=zero_value) msg = "Invalid amount" # Test fee_rate values that don't pass fixed-point parsing checks. - for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: - assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value) + if not self.options.usecli: + for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: + assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value) # Test fee_rate values that cannot be represented in sat/vB. for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999]: assert_raises_rpc_error(-3, msg, rbf_node.bumpfee, rbfid, fee_rate=invalid_value) @@ -164,9 +165,10 @@ class BumpFeeTest(BitcoinTestFramework): rbf_node.bumpfee, rbfid, {"confTarget": 123, "conf_target": 456}) self.log.info("Test invalid estimate_mode settings") - for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): - assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string", - rbf_node.bumpfee, rbfid, estimate_mode=v) + if not self.options.usecli: + for k, v in {"number": 42, "object": {"foo": "bar"}}.items(): + assert_raises_rpc_error(-3, f"JSON value of type {k} for field estimate_mode is not of expected type string", + rbf_node.bumpfee, rbfid, estimate_mode=v) for mode in ["foo", Decimal("3.1415"), "sat/B", "BTC/kB"]: assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', rbf_node.bumpfee, rbfid, estimate_mode=mode) diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py index 10f2c3c81d..b54852b7c3 100755 --- a/test/functional/wallet_encryption.py +++ b/test/functional/wallet_encryption.py @@ -90,17 +90,18 @@ class WalletEncryptionTest(BitcoinTestFramework): assert_equal(actual_time, expected_time) self.nodes[0].walletlock() - # Test passphrase with null characters - passphrase_with_nulls = "Phrase\0With\0Nulls" - self.nodes[0].walletpassphrasechange(passphrase2, passphrase_with_nulls) - # walletpassphrasechange should not stop at null characters - assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase_with_nulls.partition("\0")[0], 10) - assert_raises_rpc_error(-14, "The wallet passphrase entered was incorrect", self.nodes[0].walletpassphrasechange, passphrase_with_nulls.partition("\0")[0], "abc") - assert_raises_rpc_error(-14, "wallet passphrase entered is incorrect. It contains a null character (ie - a zero byte)", self.nodes[0].walletpassphrase, passphrase_with_nulls + "\0", 10) - assert_raises_rpc_error(-14, "The old wallet passphrase entered is incorrect. It contains a null character (ie - a zero byte)", self.nodes[0].walletpassphrasechange, passphrase_with_nulls + "\0", "abc") - with WalletUnlock(self.nodes[0], passphrase_with_nulls): - sig = self.nodes[0].signmessage(address, msg) - assert self.nodes[0].verifymessage(address, sig, msg) + if not self.options.usecli: # can't be done with the test framework for cli since subprocess.Popen doesn't allow null characters + # Test passphrase with null characters + passphrase_with_nulls = "Phrase\0With\0Nulls" + self.nodes[0].walletpassphrasechange(passphrase2, passphrase_with_nulls) + # walletpassphrasechange should not stop at null characters + assert_raises_rpc_error(-14, "wallet passphrase entered was incorrect", self.nodes[0].walletpassphrase, passphrase_with_nulls.partition("\0")[0], 10) + assert_raises_rpc_error(-14, "The wallet passphrase entered was incorrect", self.nodes[0].walletpassphrasechange, passphrase_with_nulls.partition("\0")[0], "abc") + assert_raises_rpc_error(-14, "wallet passphrase entered is incorrect. It contains a null character (ie - a zero byte)", self.nodes[0].walletpassphrase, passphrase_with_nulls + "\0", 10) + assert_raises_rpc_error(-14, "The old wallet passphrase entered is incorrect. It contains a null character (ie - a zero byte)", self.nodes[0].walletpassphrasechange, passphrase_with_nulls + "\0", "abc") + with WalletUnlock(self.nodes[0], passphrase_with_nulls): + sig = self.nodes[0].signmessage(address, msg) + assert self.nodes[0].verifymessage(address, sig, msg) self.log.info("Test that wallets without private keys cannot be encrypted") self.nodes[0].createwallet(wallet_name="noprivs", disable_private_keys=True) diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index a3b1984733..2a0af8efe0 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -49,6 +49,7 @@ class RawTransactionsTest(BitcoinTestFramework): # whitelist peers to speed up tx relay / mempool sync self.noban_tx_relay = True self.rpc_timeout = 90 # to prevent timeouts in `test_transaction_too_large` + self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 4eb080329c..0beed9c02a 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -22,8 +22,6 @@ class WalletHDTest(BitcoinTestFramework): # whitelist peers to speed up tx relay / mempool sync self.noban_tx_relay = True - self.supports_cli = False - def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_miniscript.py b/test/functional/wallet_miniscript.py index ae2683b97d..606ddb3bfc 100755 --- a/test/functional/wallet_miniscript.py +++ b/test/functional/wallet_miniscript.py @@ -297,14 +297,14 @@ class WalletMiniscriptTest(BitcoinTestFramework): psbt.i[0].map[k] = bytes.fromhex(preimage) psbt = psbt.to_base64() res = self.ms_sig_wallet.walletprocesspsbt(psbt=psbt, finalize=False) - psbtin = self.nodes[0].rpc.decodepsbt(res["psbt"])["inputs"][0] + psbtin = self.nodes[0].decodepsbt(res["psbt"])["inputs"][0] sigs_field_name = "taproot_script_path_sigs" if is_taproot else "partial_signatures" assert len(psbtin[sigs_field_name]) == sigs_count res = self.ms_sig_wallet.finalizepsbt(res["psbt"]) assert res["complete"] == (stack_size is not None) if stack_size is not None: - txin = self.nodes[0].rpc.decoderawtransaction(res["hex"])["vin"][0] + txin = self.nodes[0].decoderawtransaction(res["hex"])["vin"][0] assert len(txin["txinwitness"]) == stack_size, txin["txinwitness"] self.log.info("Broadcasting the transaction.") # If necessary, satisfy a relative timelock diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index 067df43e50..21761775c5 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -29,6 +29,7 @@ class WalletSendTest(BitcoinTestFramework): self.num_nodes = 2 # whitelist peers to speed up tx relay / mempool sync self.noban_tx_relay = True + self.supports_cli = False self.extra_args = [ ["-walletrbf=1"], ["-walletrbf=1"] diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py index c6fb4ed7ee..ade33e412a 100755 --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -16,7 +16,6 @@ class WalletStartupTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 - self.supports_cli = True def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_taproot.py b/test/functional/wallet_taproot.py index 35cbf5666e..35d2d791f8 100755 --- a/test/functional/wallet_taproot.py +++ b/test/functional/wallet_taproot.py @@ -191,7 +191,6 @@ class WalletTaprootTest(BitcoinTestFramework): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [['-keypool=100'], ['-keypool=100']] - self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 33481ef42c..7dc392b006 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -17,7 +17,6 @@ from test_framework.messages import ( class TxnMallTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 - self.supports_cli = False self.extra_args = [[ "-deprecatedrpc=settxfee" ] for i in range(self.num_nodes)] diff --git a/test/functional/wallet_txn_doublespend.py b/test/functional/wallet_txn_doublespend.py index b61fb610b0..eb8f046e1f 100755 --- a/test/functional/wallet_txn_doublespend.py +++ b/test/functional/wallet_txn_doublespend.py @@ -14,7 +14,6 @@ from test_framework.util import ( class TxnMallTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 3 - self.supports_cli = False def skip_test_if_missing_module(self): self.skip_if_no_wallet()