mirror of https://github.com/bitcoin/bitcoin.git
Merge bitcoin/bitcoin#32290: test: allow all functional tests to be run or skipped with --usecli
666016e56b
ci: use --usecli in one of the CI jobs (Martin Zumsande)7ea248a020
test: Disable several (sub)tests with cli (Martin Zumsande)f420b6356b
test: skip subtests that check for wrong types with cli (Martin Zumsande)6530d0015b
test: add function to convert to json for height_or_hash params (Martin Zumsande)54d28722ba
test: Don't send empty named args with cli (Martin Zumsande)cca422060e
test: convert tuple to json for cli (Martin Zumsande)af34e98086
test: make rpc_psbt.py usable with --usecli (Martin Zumsande)8f8ce9e174
test: rename .rpc to ._rpc and remove unnecessary uses (Martin Zumsande)5b08885986
test: enable functional tests with large rpc args for cli (Martin Zumsande)7d5352ac73
test: use -stdin for large rpc commands (Martin Zumsande)6c364e0c10
test: Enable various tests for usage with cli (Martin Zumsande) Pull request description: Fixes #32264 I looked into all current failures listed in the issue, as well all tests that are already disabled for the cli with `self.supports_cli = False`. There are several reasons why existing tests fail with `--usecli` on many systems, the most important ones are: - Most common reason is that the test executes a RPC call with a large arg that exceeds `MAX_ARG_STRLEN` of the OS, which is usually 128kb on linux: This is fixed by using `-stdin` for these large calls (idea by 0xB10C) - they test specifically the rpc interface - nothing to do there except disabling. - Some functional test submit wrong types to params on purpose to test the error message (which is different when using the cli) - deactivated these specific subtests locally for the cli when there is just one or two of them, deactivated the entire tests when there are more spots - When python sets `None` for an arg, the cli converts this to 'null' in `arg_to_cli`. This is fine e.g. for boolean args, but doesn't work for strings where it's interpreted as the string 'null'. Bypass this for named args by not including args in case the value is `None` for the cli is used (it's effectively the same as leaving the optional arg out). - the `height_or_hash` param used in some RPC needs to be converted to a JSON (effectively adding full quotes). - Some tests were marked with `self.supports_cli = False` in the past but run fine on master today - enabled those. In total, this PR fixes all tests that fail on master and reduces the number of tests that are deactivated (`self.supports_cli = False`) from 40 to 21. It also adds `--usecli` to one CI job (multiprocess, i686, DEBUG) to detect regressions. ACKs for top commit: maflcko: re-ACK666016e56b
🔀 pinheadmz: re-ACK666016e56b
Tree-SHA512: 7a1efd212649ca100b236a1239294d40ecd36e2720e3b173a230b14545bb40b135111db7fed8a0d1448120f5387da146a03f1912e2028c8d03a0b6a3ca8761b0
This commit is contained in:
commit
6251949443
|
@ -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' \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"])
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -33,7 +33,6 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
[
|
||||
],
|
||||
]
|
||||
self.supports_cli = False
|
||||
self.uses_wallet = None
|
||||
|
||||
def run_test(self):
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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 )")
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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__':
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue