diff options
Diffstat (limited to 'test')
52 files changed, 587 insertions, 227 deletions
diff --git a/test/functional/data/rpc_decodescript.json b/test/functional/data/rpc_decodescript.json index d1aa9ab00d..8903f5efac 100644 --- a/test/functional/data/rpc_decodescript.json +++ b/test/functional/data/rpc_decodescript.json @@ -4,6 +4,7 @@ { "asm": "1 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "address": "bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh", + "desc": "addr(bcrt1pamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqz6nvlh)#v52jnujz", "type": "witness_v1_taproot" } ], @@ -12,6 +13,7 @@ { "asm": "1 -28398", "address": "bcrt1pamhqk96edn", + "desc": "addr(bcrt1pamhqk96edn)#vkh8uj5a", "type": "witness_unknown" } ], @@ -20,6 +22,7 @@ { "asm": "0 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "address": "bcrt1qamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqgdn98t", + "desc": "addr(bcrt1qamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhwamhqgdn98t)#afaecevx", "type": "witness_v0_scripthash", "p2sh": "2MwGk8mw1GBP6U9D5X8gTvgvXpuknmAK3fo" } @@ -29,6 +32,7 @@ { "asm": "OP_HASH160 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee OP_EQUAL", "address": "2NF2b3KS8xXb9XHvbRMXdZh8s5g92rUZHtp", + "desc": "addr(2NF2b3KS8xXb9XHvbRMXdZh8s5g92rUZHtp)#ywfcpmh9", "type": "scripthash" } ], @@ -36,6 +40,7 @@ "6a00", { "asm": "OP_RETURN 0", + "desc": "raw(6a00)#ncfmkl43", "type": "nulldata" } ], @@ -43,6 +48,7 @@ "6aee", { "asm": "OP_RETURN OP_UNKNOWN", + "desc": "raw(6aee)#vsyzgqdt", "type": "nonstandard" } ], @@ -50,6 +56,7 @@ "6a02ee", { "asm": "OP_RETURN [error]", + "desc": "raw(6a02ee)#gvdwnlzl", "type": "nonstandard" } ], @@ -57,10 +64,12 @@ "02eeee", { "asm": "-28398", + "desc": "raw(02eeee)#5xzck7pr", "type": "nonstandard", "p2sh": "2N34iiGoUUkVSPiaaTFpJjB1FR9TXQu3PGM", "segwit": { "asm": "0 96c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42", + "desc": "addr(bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5)#5akkdska", "hex": "002096c2368fc30514a438a8bd909f93c49a1549d77198ccbdb792043b666cb24f42", "address": "bcrt1qjmprdr7rq522gw9ghkgfly7yng25n4m3nrxtmdujqsakvm9jfapqk795l5", "type": "witness_v0_scripthash", @@ -72,6 +81,7 @@ "ba", { "asm": "OP_CHECKSIGADD", + "desc": "raw(ba)#yy0eg44l", "type": "nonstandard" } ], @@ -79,6 +89,7 @@ "50", { "asm": "OP_RESERVED", + "desc": "raw(50)#a7tu03xf", "type": "nonstandard" } ] diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 7fd0d0140b..9d32749a08 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -92,7 +92,7 @@ class BIP65Test(BitcoinTestFramework): self.rpc_timeout = 480 def test_cltv_info(self, *, is_active): - assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip65'], { + assert_equal(self.nodes[0].getdeploymentinfo()['deployments']['bip65'], { "active": is_active, "height": CLTV_HEIGHT, "type": "buried", diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index f35ce7e0c9..9a46839969 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -60,7 +60,7 @@ class BIP66Test(BitcoinTestFramework): return self.miniwallet.create_self_transfer(utxo_to_spend=utxo_to_spend)['tx'] def test_dersig_info(self, *, is_active): - assert_equal(self.nodes[0].getblockchaininfo()['softforks']['bip66'], + assert_equal(self.nodes[0].getdeploymentinfo()['deployments']['bip66'], { "active": is_active, "height": DERSIG_HEIGHT, diff --git a/test/functional/feature_dirsymlinks.py b/test/functional/feature_dirsymlinks.py new file mode 100755 index 0000000000..85c8e27600 --- /dev/null +++ b/test/functional/feature_dirsymlinks.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test successful startup with symlinked directories. +""" + +import os +import sys + +from test_framework.test_framework import BitcoinTestFramework, SkipTest + + +def rename_and_link(*, from_name, to_name): + os.rename(from_name, to_name) + os.symlink(to_name, from_name) + assert os.path.islink(from_name) and os.path.isdir(from_name) + +class SymlinkTest(BitcoinTestFramework): + def skip_test_if_missing_module(self): + if sys.platform == 'win32': + raise SkipTest("Symlinks test skipped on Windows") + + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + self.stop_node(0) + + rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "blocks"), + to_name=os.path.join(self.nodes[0].datadir, self.chain, "newblocks")) + rename_and_link(from_name=os.path.join(self.nodes[0].datadir, self.chain, "chainstate"), + to_name=os.path.join(self.nodes[0].datadir, self.chain, "newchainstate")) + + self.start_node(0) + + +if __name__ == '__main__': + SymlinkTest().main() diff --git a/test/functional/feature_init.py b/test/functional/feature_init.py index 4b56b0c26b..d0cb1e10e2 100755 --- a/test/functional/feature_init.py +++ b/test/functional/feature_init.py @@ -3,8 +3,6 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Stress tests related to node initialization.""" -import random -import time import os from pathlib import Path @@ -26,7 +24,6 @@ class InitStressTest(BitcoinTestFramework): def run_test(self): """ - test terminating initialization after seeing a certain log line. - - test terminating init after seeing a random number of log lines. - test removing certain essential files to test startup error paths. """ # TODO: skip Windows for now since it isn't clear how to SIGTERM. @@ -67,6 +64,8 @@ class InitStressTest(BitcoinTestFramework): 'addcon thread start', 'loadblk thread start', 'txindex thread start', + 'block filter index thread start', + 'coinstatsindex thread start', 'msghand thread start', 'net thread start', 'addcon thread start', @@ -76,46 +75,14 @@ class InitStressTest(BitcoinTestFramework): for terminate_line in lines_to_terminate_after: self.log.info(f"Starting node and will exit after line '{terminate_line}'") - node.start(extra_args=['-txindex=1']) - - num_total_logs = node.wait_for_debug_log([terminate_line], ignore_case=True) - self.log.debug(f"Terminating node after {num_total_logs} log lines seen") + with node.wait_for_debug_log([terminate_line], ignore_case=True): + node.start(extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1']) + self.log.debug("Terminating node after terminate line was found") sigterm_node() check_clean_start() self.stop_node(0) - self.log.info( - f"Terminate at some random point in the init process (max logs: {num_total_logs})") - - for _ in range(40): - num_logs = len(Path(node.debug_log_path).read_text().splitlines()) - additional_lines = random.randint(1, num_total_logs) - self.log.debug(f"Starting node and will exit after {additional_lines} lines") - node.start(extra_args=['-txindex=1']) - logfile = open(node.debug_log_path, 'rb') - - MAX_SECS_TO_WAIT = 10 - start = time.time() - num_lines = 0 - - while True: - line = logfile.readline() - if line: - num_lines += 1 - - if num_lines >= (num_logs + additional_lines) or \ - (time.time() - start) > MAX_SECS_TO_WAIT: - self.log.debug(f"Terminating node after {num_lines} log lines seen") - sigterm_node() - break - - if node.process.poll() is not None: - raise AssertionError("node failed to start") - - check_clean_start() - self.stop_node(0) - self.log.info("Test startup errors after removing certain essential files") files_to_disturb = { @@ -144,7 +111,7 @@ class InitStressTest(BitcoinTestFramework): # investigate doing this later. node.assert_start_raises_init_error( - extra_args=['-txindex=1'], + extra_args=['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1'], expected_msg=err_fragment, match=ErrorMatch.PARTIAL_REGEX, ) diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py new file mode 100755 index 0000000000..87f9d6962d --- /dev/null +++ b/test/functional/feature_maxtipage.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test logic for setting nMaxTipAge on command line. + +Nodes don't consider themselves out of "initial block download" as long as +their best known block header time is more than nMaxTipAge in the past. +""" + +import time + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + + +DEFAULT_MAX_TIP_AGE = 24 * 60 * 60 + + +class MaxTipAgeTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = True + self.num_nodes = 2 + + def test_maxtipage(self, maxtipage, set_parameter=True): + node_miner = self.nodes[0] + node_ibd = self.nodes[1] + + self.restart_node(1, [f'-maxtipage={maxtipage}'] if set_parameter else None) + self.connect_nodes(0, 1) + + # tips older than maximum age -> stay in IBD + cur_time = int(time.time()) + node_ibd.setmocktime(cur_time) + for delta in [5, 4, 3, 2, 1]: + node_miner.setmocktime(cur_time - maxtipage - delta) + self.generate(node_miner, 1) + assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], True) + + # tip within maximum age -> leave IBD + node_miner.setmocktime(cur_time - maxtipage) + self.generate(node_miner, 1) + assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], False) + + def run_test(self): + self.log.info("Test IBD with maximum tip age of 24 hours (default).") + self.test_maxtipage(DEFAULT_MAX_TIP_AGE, set_parameter=False) + + for hours in [20, 10, 5, 2, 1]: + maxtipage = hours * 60 * 60 + self.log.info(f"Test IBD with maximum tip age of {hours} hours (-maxtipage={maxtipage}).") + self.test_maxtipage(maxtipage) + + +if __name__ == '__main__': + MaxTipAgeTest().main() diff --git a/test/functional/feature_syscall_sandbox.py b/test/functional/feature_syscall_sandbox.py index caf7f1e7fc..e430542845 100755 --- a/test/functional/feature_syscall_sandbox.py +++ b/test/functional/feature_syscall_sandbox.py @@ -14,7 +14,7 @@ class SyscallSandboxTest(BitcoinTestFramework): def skip_test_if_missing_module(self): if not self.is_syscall_sandbox_compiled(): raise SkipTest("bitcoind has not been built with syscall sandbox enabled.") - if self.options.nosandbox: + if self.disable_syscall_sandbox: raise SkipTest("--nosandbox passed to test runner.") def run_test(self): diff --git a/test/functional/interface_rest.py b/test/functional/interface_rest.py index 2842b2534d..a3d949c6a8 100755 --- a/test/functional/interface_rest.py +++ b/test/functional/interface_rest.py @@ -6,21 +6,32 @@ from decimal import Decimal from enum import Enum +import http.client from io import BytesIO import json from struct import pack, unpack - -import http.client import urllib.parse + +from test_framework.messages import ( + BLOCK_HEADER_SIZE, + COIN, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_greater_than, assert_greater_than_or_equal, ) +from test_framework.wallet import ( + MiniWallet, + getnewdestination, +) + + +INVALID_PARAM = "abc" +UNKNOWN_PARAM = "0000000000000000000000000000000000000000000000000000000000000000" -from test_framework.messages import BLOCK_HEADER_SIZE class ReqType(Enum): JSON = 1 @@ -39,14 +50,13 @@ def filter_output_indices_by_value(vouts, value): class RESTTest (BitcoinTestFramework): def set_test_params(self): - self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [["-rest", "-blockfilterindex=1"], []] + # 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() - def test_rest_request(self, uri, http_method='GET', req_type=ReqType.JSON, body='', status=200, ret_type=RetType.JSON): rest_uri = '/rest' + uri if req_type == ReqType.JSON: @@ -75,17 +85,11 @@ class RESTTest (BitcoinTestFramework): def run_test(self): self.url = urllib.parse.urlparse(self.nodes[0].url) - self.log.info("Mine blocks and send Bitcoin to node 1") - - # Random address so node1's balance doesn't increase - not_related_address = "2MxqoHEdNQTyYeX1mHcbrrpzgojbosTpCvJ" - - self.generate(self.nodes[0], 1) - self.generatetoaddress(self.nodes[1], 100, not_related_address) + self.wallet = MiniWallet(self.nodes[0]) + self.wallet.rescan_utxos() - assert_equal(self.nodes[0].getbalance(), 50) - - txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) + self.log.info("Broadcast test transaction and sync nodes") + txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN)) self.sync_all() self.log.info("Test the /tx URI") @@ -103,13 +107,17 @@ class RESTTest (BitcoinTestFramework): n, = filter_output_indices_by_value(json_obj['vout'], Decimal('0.1')) spending = (txid, n) + # Test /tx with an invalid and an unknown txid + resp = self.test_rest_request(uri=f"/tx/{INVALID_PARAM}", ret_type=RetType.OBJ, status=400) + assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid hash: {INVALID_PARAM}") + resp = self.test_rest_request(uri=f"/tx/{UNKNOWN_PARAM}", ret_type=RetType.OBJ, status=404) + assert_equal(resp.read().decode('utf-8').rstrip(), f"{UNKNOWN_PARAM} not found") + self.log.info("Query an unspent TXO using the /getutxos URI") - self.generatetoaddress(self.nodes[1], 1, not_related_address) + self.generate(self.wallet, 1) bb_hash = self.nodes[0].getbestblockhash() - assert_equal(self.nodes[1].getbalance(), Decimal("0.1")) - # Check chainTip response json_obj = self.test_rest_request(f"/getutxos/{spending[0]}-{spending[1]}") assert_equal(json_obj['chaintipHash'], bb_hash) @@ -151,7 +159,7 @@ class RESTTest (BitcoinTestFramework): response_hash = output.read(32)[::-1].hex() assert_equal(bb_hash, response_hash) # check if getutxo's chaintip during calculation was fine - assert_equal(chain_height, 102) # chain height must be 102 + assert_equal(chain_height, 201) # chain height must be 201 (pre-mined chain [200] + generated block [1]) self.log.info("Test the /getutxos URI with and without /checkmempool") # Create a transaction, check that it's found with /checkmempool, but @@ -159,7 +167,7 @@ class RESTTest (BitcoinTestFramework): # found with or without /checkmempool. # do a tx and don't sync - txid = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 0.1) + txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=getnewdestination()[1], amount=int(0.1 * COIN)) json_obj = self.test_rest_request(f"/tx/{txid}") # get the spent output to later check for utxo (should be spent by then) spent = (json_obj['vin'][0]['txid'], json_obj['vin'][0]['vout']) @@ -205,8 +213,8 @@ class RESTTest (BitcoinTestFramework): bb_hash = self.nodes[0].getbestblockhash() # Check result if block does not exists - assert_equal(self.test_rest_request('/headers/1/0000000000000000000000000000000000000000000000000000000000000000'), []) - self.test_rest_request('/block/0000000000000000000000000000000000000000000000000000000000000000', status=404, ret_type=RetType.OBJ) + assert_equal(self.test_rest_request(f"/headers/1/{UNKNOWN_PARAM}"), []) + self.test_rest_request(f"/block/{UNKNOWN_PARAM}", status=404, ret_type=RetType.OBJ) # Check result if block is not in the active chain self.nodes[0].invalidateblock(bb_hash) @@ -250,8 +258,8 @@ class RESTTest (BitcoinTestFramework): assert_equal(blockhash, bb_hash) # Check invalid blockhashbyheight requests - resp = self.test_rest_request("/blockhashbyheight/abc", ret_type=RetType.OBJ, status=400) - assert_equal(resp.read().decode('utf-8').rstrip(), "Invalid height: abc") + resp = self.test_rest_request(f"/blockhashbyheight/{INVALID_PARAM}", ret_type=RetType.OBJ, status=400) + assert_equal(resp.read().decode('utf-8').rstrip(), f"Invalid height: {INVALID_PARAM}") resp = self.test_rest_request("/blockhashbyheight/1000000", ret_type=RetType.OBJ, status=404) assert_equal(resp.read().decode('utf-8').rstrip(), "Block height out of range") resp = self.test_rest_request("/blockhashbyheight/-1", ret_type=RetType.OBJ, status=400) @@ -291,11 +299,13 @@ class RESTTest (BitcoinTestFramework): self.log.info("Test tx inclusion in the /mempool and /block URIs") - # Make 3 tx and mine them on node 1 + # Make 3 chained txs and mine them on node 1 txs = [] - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) - txs.append(self.nodes[0].sendtoaddress(not_related_address, 11)) + input_txid = txid + for _ in range(3): + utxo_to_spend = self.wallet.get_utxo(txid=input_txid) + txs.append(self.wallet.send_self_transfer(from_node=self.nodes[0], utxo_to_spend=utxo_to_spend)['txid']) + input_txid = txs[-1] self.sync_all() # Check that there are exactly 3 transactions in the TX memory pool before generating the block @@ -341,5 +351,6 @@ class RESTTest (BitcoinTestFramework): json_obj = self.test_rest_request("/chaininfo") assert_equal(json_obj['bestblockhash'], bb_hash) + if __name__ == '__main__': RESTTest().main() diff --git a/test/functional/mempool_updatefromblock.py b/test/functional/mempool_updatefromblock.py index 16c15e3f74..51de582ce0 100755 --- a/test/functional/mempool_updatefromblock.py +++ b/test/functional/mempool_updatefromblock.py @@ -17,7 +17,7 @@ from test_framework.util import assert_equal class MempoolUpdateFromBlockTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000']] + self.extra_args = [['-limitdescendantsize=1000', '-limitancestorsize=1000', '-limitancestorcount=100']] def skip_test_if_missing_module(self): self.skip_if_no_wallet() diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 4dd4899f74..2d96ba74b5 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -6,6 +6,7 @@ Test the following RPCs: - getblockchaininfo + - getdeploymentinfo - getchaintxstats - gettxoutsetinfo - getblockheader @@ -79,6 +80,7 @@ class BlockchainTest(BitcoinTestFramework): self._test_stopatheight() self._test_waitforblockheight() self._test_getblock() + self._test_getdeploymentinfo() assert self.nodes[0].verifychain(4, 0) def mine_chain(self): @@ -115,7 +117,6 @@ class BlockchainTest(BitcoinTestFramework): 'mediantime', 'pruned', 'size_on_disk', - 'softforks', 'time', 'verificationprogress', 'warnings', @@ -159,11 +160,6 @@ class BlockchainTest(BitcoinTestFramework): self.start_node(0, extra_args=[ '-stopatheight=207', '-prune=550', - '-testactivationheight=bip34@2', - '-testactivationheight=dersig@3', - '-testactivationheight=cltv@4', - '-testactivationheight=csv@5', - '-testactivationheight=segwit@6', ]) res = self.nodes[0].getblockchaininfo() @@ -177,7 +173,13 @@ class BlockchainTest(BitcoinTestFramework): assert_equal(res['prune_target_size'], 576716800) assert_greater_than(res['size_on_disk'], 0) - assert_equal(res['softforks'], { + def check_signalling_deploymentinfo_result(self, gdi_result, height, blockhash, status_next): + assert height >= 144 and height <= 287 + + assert_equal(gdi_result, { + "hash": blockhash, + "height": height, + "deployments": { 'bip34': {'type': 'buried', 'active': True, 'height': 2}, 'bip66': {'type': 'buried', 'active': True, 'height': 3}, 'bip65': {'type': 'buried', 'active': True, 'height': 4}, @@ -186,36 +188,65 @@ class BlockchainTest(BitcoinTestFramework): 'testdummy': { 'type': 'bip9', 'bip9': { - 'status': 'started', 'bit': 28, 'start_time': 0, 'timeout': 0x7fffffffffffffff, # testdummy does not have a timeout so is set to the max int64 value + 'min_activation_height': 0, + 'status': 'started', + 'status-next': status_next, 'since': 144, 'statistics': { 'period': 144, 'threshold': 108, - 'elapsed': HEIGHT - 143, - 'count': HEIGHT - 143, + 'elapsed': height - 143, + 'count': height - 143, 'possible': True, }, - 'min_activation_height': 0, + 'signalling': '#'*(height-143), }, 'active': False }, 'taproot': { 'type': 'bip9', 'bip9': { - 'status': 'active', 'start_time': -1, 'timeout': 9223372036854775807, - 'since': 0, 'min_activation_height': 0, + 'status': 'active', + 'status-next': 'active', + 'since': 0, }, 'height': 0, 'active': True } + } }) + def _test_getdeploymentinfo(self): + # Note: continues past -stopatheight height, so must be invoked + # after _test_stopatheight + + self.log.info("Test getdeploymentinfo") + self.stop_node(0) + self.start_node(0, extra_args=[ + '-testactivationheight=bip34@2', + '-testactivationheight=dersig@3', + '-testactivationheight=cltv@4', + '-testactivationheight=csv@5', + '-testactivationheight=segwit@6', + ]) + + gbci207 = self.nodes[0].getblockchaininfo() + self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(), gbci207["blocks"], gbci207["bestblockhash"], "started") + + # block just prior to lock in + self.generate(self.wallet, 287 - gbci207["blocks"]) + gbci287 = self.nodes[0].getblockchaininfo() + self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(), gbci287["blocks"], gbci287["bestblockhash"], "locked_in") + + # calling with an explicit hash works + self.check_signalling_deploymentinfo_result(self.nodes[0].getdeploymentinfo(gbci207["bestblockhash"]), gbci207["blocks"], gbci207["bestblockhash"], "started") + def _test_getchaintxstats(self): self.log.info("Test getchaintxstats") diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index a8e6acea45..759e43194b 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -4,8 +4,10 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the fundrawtransaction RPC.""" + from decimal import Decimal from itertools import product +from math import ceil from test_framework.descriptors import descsum_create from test_framework.key import ECKey @@ -1003,7 +1005,7 @@ class RawTransactionsTest(BitcoinTestFramework): ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0] # An external input without solving data should result in an error - raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): 15}) + raw_tx = wallet.createrawtransaction([ext_utxo], {self.nodes[0].getnewaddress(): ext_utxo["amount"] / 2}) assert_raises_rpc_error(-4, "Insufficient funds", wallet.fundrawtransaction, raw_tx) # Error conditions @@ -1011,6 +1013,12 @@ class RawTransactionsTest(BitcoinTestFramework): assert_raises_rpc_error(-5, "'01234567890a0b0c0d0e0f' is not a valid public key", wallet.fundrawtransaction, raw_tx, {"solving_data": {"pubkeys":["01234567890a0b0c0d0e0f"]}}) assert_raises_rpc_error(-5, "'not a script' is not hex", wallet.fundrawtransaction, raw_tx, {"solving_data": {"scripts":["not a script"]}}) assert_raises_rpc_error(-8, "Unable to parse descriptor 'not a descriptor'", wallet.fundrawtransaction, raw_tx, {"solving_data": {"descriptors":["not a descriptor"]}}) + assert_raises_rpc_error(-8, "Invalid parameter, missing vout key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"]}]}) + assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": -1}]}) + assert_raises_rpc_error(-8, "Invalid parameter, missing weight key", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"]}]}) + assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 164}]}) + assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be less than 165", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": -1}]}) + assert_raises_rpc_error(-8, "Invalid parameter, weight cannot be greater than", wallet.fundrawtransaction, raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 400001}]}) # But funding should work when the solving data is provided funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}}) @@ -1020,10 +1028,45 @@ class RawTransactionsTest(BitcoinTestFramework): assert signed_tx['complete'] funded_tx = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}}) - signed_tx = wallet.signrawtransactionwithwallet(funded_tx['hex']) - assert not signed_tx['complete'] - signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx['hex']) - assert signed_tx['complete'] + signed_tx1 = wallet.signrawtransactionwithwallet(funded_tx['hex']) + assert not signed_tx1['complete'] + signed_tx2 = self.nodes[0].signrawtransactionwithwallet(signed_tx1['hex']) + assert signed_tx2['complete'] + + unsigned_weight = self.nodes[0].decoderawtransaction(signed_tx1["hex"])["weight"] + signed_weight = self.nodes[0].decoderawtransaction(signed_tx2["hex"])["weight"] + # Input's weight is difference between weight of signed and unsigned, + # and the weight of stuff that didn't change (prevout, sequence, 1 byte of scriptSig) + input_weight = signed_weight - unsigned_weight + (41 * 4) + low_input_weight = input_weight // 2 + high_input_weight = input_weight * 2 + + # Funding should also work if the input weight is provided + funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}]}) + signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"]) + signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"]) + assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True) + assert_equal(signed_tx["complete"], True) + # Reducing the weight should have a lower fee + funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}]}) + assert_greater_than(funded_tx["fee"], funded_tx2["fee"]) + # Increasing the weight should have a higher fee + funded_tx2 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]}) + assert_greater_than(funded_tx2["fee"], funded_tx["fee"]) + # The provided weight should override the calculated weight when solving data is provided + funded_tx3 = wallet.fundrawtransaction(raw_tx, {"solving_data": {"descriptors": [desc]}, "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}]}) + assert_equal(funded_tx2["fee"], funded_tx3["fee"]) + # The feerate should be met + funded_tx4 = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], "fee_rate": 10}) + input_add_weight = high_input_weight - (41 * 4) + tx4_weight = wallet.decoderawtransaction(funded_tx4["hex"])["weight"] + input_add_weight + tx4_vsize = int(ceil(tx4_weight / 4)) + assert_fee_amount(funded_tx4["fee"], tx4_vsize, Decimal(0.0001)) + + # Funding with weight at csuint boundaries should not cause problems + funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 255}]}) + funded_tx = wallet.fundrawtransaction(raw_tx, {"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 65539}]}) + self.nodes[2].unloadwallet("extfund") def test_include_unsafe(self): diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py index effcebe854..b65322d920 100755 --- a/test/functional/rpc_getblockfrompeer.py +++ b/test/functional/rpc_getblockfrompeer.py @@ -40,12 +40,8 @@ class GetBlockFromPeerTest(BitcoinTestFramework): self.sync_blocks() self.log.info("Node 0 should only have the header for node 1's block 3") - for x in self.nodes[0].getchaintips(): - if x['hash'] == short_tip: - assert_equal(x['status'], "headers-only") - break - else: - raise AssertionError("short tip not synced") + x = next(filter(lambda x: x['hash'] == short_tip, self.nodes[0].getchaintips())) + assert_equal(x['status'], "headers-only") assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, short_tip) self.log.info("Fetch block from node 1") @@ -60,17 +56,15 @@ class GetBlockFromPeerTest(BitcoinTestFramework): assert_raises_rpc_error(-1, "Block header missing", self.nodes[0].getblockfrompeer, "00" * 32, 0) self.log.info("Non-existent peer generates error") - assert_raises_rpc_error(-1, f"Peer nodeid {peer_0_peer_1_id + 1} does not exist", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1) + assert_raises_rpc_error(-1, "Peer does not exist", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1) self.log.info("Successful fetch") result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id) self.wait_until(lambda: self.check_for_block(short_tip), timeout=1) - assert(not "warnings" in result) + assert_equal(result, {}) self.log.info("Don't fetch blocks we already have") - result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id) - assert("warnings" in result) - assert_equal(result["warnings"], "Block already downloaded") + assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id) if __name__ == '__main__': GetBlockFromPeerTest().main() diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 153a201e95..b037807b53 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -606,11 +606,15 @@ class PSBTTest(BitcoinTestFramework): assert_raises_rpc_error(-25, 'Inputs missing or spent', self.nodes[0].walletprocesspsbt, 'cHNidP8BAJoCAAAAAkvEW8NnDtdNtDpsmze+Ht2LH35IJcKv00jKAlUs21RrAwAAAAD/////S8Rbw2cO1020OmybN74e3Ysffkglwq/TSMoCVSzbVGsBAAAAAP7///8CwLYClQAAAAAWABSNJKzjaUb3uOxixsvh1GGE3fW7zQD5ApUAAAAAFgAUKNw0x8HRctAgmvoevm4u1SbN7XIAAAAAAAEAnQIAAAACczMa321tVHuN4GKWKRncycI22aX3uXgwSFUKM2orjRsBAAAAAP7///9zMxrfbW1Ue43gYpYpGdzJwjbZpfe5eDBIVQozaiuNGwAAAAAA/v///wIA+QKVAAAAABl2qRT9zXUVA8Ls5iVqynLHe5/vSe1XyYisQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAAAAAQEfQM0ClQAAAAAWABRmWQUcjSjghQ8/uH4Bn/zkakwLtAAAAA==') - # Test that we can fund psbts with external inputs specified + self.log.info("Test that we can fund psbts with external inputs specified") + eckey = ECKey() eckey.generate() privkey = bytes_to_wif(eckey.get_bytes()) + self.nodes[1].createwallet("extfund") + wallet = self.nodes[1].get_wallet_rpc("extfund") + # Make a weird but signable script. sh(pkh()) descriptor accomplishes this desc = descsum_create("sh(pkh({}))".format(privkey)) if self.options.descriptors: @@ -622,26 +626,97 @@ class PSBTTest(BitcoinTestFramework): addr_info = self.nodes[0].getaddressinfo(addr) self.nodes[0].sendtoaddress(addr, 10) + self.nodes[0].sendtoaddress(wallet.getnewaddress(), 10) self.generate(self.nodes[0], 6) ext_utxo = self.nodes[0].listunspent(addresses=[addr])[0] # An external input without solving data should result in an error - assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[1].walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 10 + ext_utxo['amount']}, 0, {'add_inputs': True}) + assert_raises_rpc_error(-4, "Insufficient funds", wallet.walletcreatefundedpsbt, [ext_utxo], {self.nodes[0].getnewaddress(): 15}) # But funding should work when the solving data is provided - psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}}) - signed = self.nodes[1].walletprocesspsbt(psbt['psbt']) + psbt = wallet.walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {"add_inputs": True, "solving_data": {"pubkeys": [addr_info['pubkey']], "scripts": [addr_info["embedded"]["scriptPubKey"]]}}) + signed = wallet.walletprocesspsbt(psbt['psbt']) assert not signed['complete'] signed = self.nodes[0].walletprocesspsbt(signed['psbt']) assert signed['complete'] self.nodes[0].finalizepsbt(signed['psbt']) - psbt = self.nodes[1].walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {'add_inputs': True, "solving_data":{"descriptors": [desc]}}) - signed = self.nodes[1].walletprocesspsbt(psbt['psbt']) + psbt = wallet.walletcreatefundedpsbt([ext_utxo], {self.nodes[0].getnewaddress(): 15}, 0, {"add_inputs": True, "solving_data":{"descriptors": [desc]}}) + signed = wallet.walletprocesspsbt(psbt['psbt']) assert not signed['complete'] signed = self.nodes[0].walletprocesspsbt(signed['psbt']) assert signed['complete'] - self.nodes[0].finalizepsbt(signed['psbt']) + final = self.nodes[0].finalizepsbt(signed['psbt'], False) + + dec = self.nodes[0].decodepsbt(signed["psbt"]) + for i, txin in enumerate(dec["tx"]["vin"]): + if txin["txid"] == ext_utxo["txid"] and txin["vout"] == ext_utxo["vout"]: + input_idx = i + break + psbt_in = dec["inputs"][input_idx] + # Calculate the input weight + # (prevout + sequence + length of scriptSig + 2 bytes buffer) * 4 + len of scriptwitness + len_scriptsig = len(psbt_in["final_scriptSig"]["hex"]) // 2 if "final_scriptSig" in psbt_in else 0 + len_scriptwitness = len(psbt_in["final_scriptwitness"]["hex"]) // 2 if "final_scriptwitness" in psbt_in else 0 + input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitness + low_input_weight = input_weight // 2 + high_input_weight = input_weight * 2 + + # Input weight error conditions + assert_raises_rpc_error( + -8, + "Input weights should be specified in inputs rather than in options.", + wallet.walletcreatefundedpsbt, + inputs=[ext_utxo], + outputs={self.nodes[0].getnewaddress(): 15}, + options={"input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 1000}]} + ) + + # Funding should also work if the input weight is provided + psbt = wallet.walletcreatefundedpsbt( + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}], + outputs={self.nodes[0].getnewaddress(): 15}, + options={"add_inputs": True} + ) + signed = wallet.walletprocesspsbt(psbt["psbt"]) + signed = self.nodes[0].walletprocesspsbt(signed["psbt"]) + final = self.nodes[0].finalizepsbt(signed["psbt"]) + assert self.nodes[0].testmempoolaccept([final["hex"]])[0]["allowed"] + # Reducing the weight should have a lower fee + psbt2 = wallet.walletcreatefundedpsbt( + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": low_input_weight}], + outputs={self.nodes[0].getnewaddress(): 15}, + options={"add_inputs": True} + ) + assert_greater_than(psbt["fee"], psbt2["fee"]) + # Increasing the weight should have a higher fee + psbt2 = wallet.walletcreatefundedpsbt( + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], + outputs={self.nodes[0].getnewaddress(): 15}, + options={"add_inputs": True} + ) + assert_greater_than(psbt2["fee"], psbt["fee"]) + # The provided weight should override the calculated weight when solving data is provided + psbt3 = wallet.walletcreatefundedpsbt( + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], + outputs={self.nodes[0].getnewaddress(): 15}, + options={'add_inputs': True, "solving_data":{"descriptors": [desc]}} + ) + assert_equal(psbt2["fee"], psbt3["fee"]) + + # Import the external utxo descriptor so that we can sign for it from the test wallet + if self.options.descriptors: + res = wallet.importdescriptors([{"desc": desc, "timestamp": "now"}]) + else: + res = wallet.importmulti([{"desc": desc, "timestamp": "now"}]) + assert res[0]["success"] + # The provided weight should override the calculated weight for a wallet input + psbt3 = wallet.walletcreatefundedpsbt( + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": high_input_weight}], + outputs={self.nodes[0].getnewaddress(): 15}, + options={"add_inputs": True} + ) + assert_equal(psbt2["fee"], psbt3["fee"]) if __name__ == '__main__': PSBTTest().main() diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 96691b2686..a839af0288 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -99,25 +99,36 @@ class RawTransactionsTest(BitcoinTestFramework): rawTx = self.nodes[1].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): 9.999}) rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx) txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex']) - self.generate(self.nodes[0], 1) + self.generateblock(self.nodes[0], output=self.nodes[0].getnewaddress(), transactions=[rawTxSigned['hex']]) + err_msg = ( + "No such mempool transaction. Use -txindex or provide a block hash to enable" + " blockchain transaction queries. Use gettransaction for wallet transactions." + ) for n in [0, 3]: self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex") - # 1. valid parameters - only supply txid - assert_equal(self.nodes[n].getrawtransaction(txId), rawTxSigned['hex']) - # 2. valid parameters - supply txid and 0 for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, 0), rawTxSigned['hex']) + if n == 0: + # With -txindex. + # 1. valid parameters - only supply txid + assert_equal(self.nodes[n].getrawtransaction(txId), rawTxSigned['hex']) - # 3. valid parameters - supply txid and False for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, False), rawTxSigned['hex']) + # 2. valid parameters - supply txid and 0 for non-verbose + assert_equal(self.nodes[n].getrawtransaction(txId, 0), rawTxSigned['hex']) - # 4. valid parameters - supply txid and 1 for verbose. - # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. - assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex']) + # 3. valid parameters - supply txid and False for non-verbose + assert_equal(self.nodes[n].getrawtransaction(txId, False), rawTxSigned['hex']) - # 5. valid parameters - supply txid and True for non-verbose - assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], rawTxSigned['hex']) + # 4. valid parameters - supply txid and 1 for verbose. + # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. + assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex']) + + # 5. valid parameters - supply txid and True for non-verbose + assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], rawTxSigned['hex']) + else: + # Without -txindex, expect to raise. + for verbose in [None, 0, False, 1, True]: + assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txId, verbose) # 6. invalid parameters - supply txid and invalid boolean values (strings) for verbose for value in ["True", "False"]: @@ -145,10 +156,6 @@ class RawTransactionsTest(BitcoinTestFramework): assert 'in_active_chain' not in gottx else: self.log.info("Test getrawtransaction without -txindex, without blockhash: expect the call to raise") - err_msg = ( - "No such mempool transaction. Use -txindex or provide a block hash to enable" - " blockchain transaction queries. Use gettransaction for wallet transactions." - ) assert_raises_rpc_error(-5, err_msg, self.nodes[n].getrawtransaction, txid=tx, verbose=True) # We should not get the tx if we provide an unrelated block assert_raises_rpc_error(-5, "No such transaction found", self.nodes[n].getrawtransaction, txid=tx, blockhash=block2) diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index e648040278..a2091b4ece 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -270,7 +270,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): getcontext().prec = 8 # Make sure CSV is active - assert self.nodes[0].getblockchaininfo()['softforks']['csv']['active'] + assert self.nodes[0].getdeploymentinfo()['deployments']['csv']['active'] # Create a P2WSH script with CSV script = CScript([1, OP_CHECKSEQUENCEVERIFY, OP_DROP]) @@ -305,7 +305,7 @@ class SignRawTransactionsTest(BitcoinTestFramework): getcontext().prec = 8 # Make sure CLTV is active - assert self.nodes[0].getblockchaininfo()['softforks']['bip65']['active'] + assert self.nodes[0].getdeploymentinfo()['deployments']['bip65']['active'] # Create a P2WSH script with CLTV script = CScript([100, OP_CHECKLOCKTIMEVERIFY, OP_DROP]) diff --git a/test/functional/test_framework/address.py b/test/functional/test_framework/address.py index 013522a5e1..c7fbf679b6 100644 --- a/test/functional/test_framework/address.py +++ b/test/functional/test_framework/address.py @@ -55,17 +55,15 @@ def create_deterministic_address_bcrt1_p2tr_op_true(): def byte_to_base58(b, version): result = '' - str = b.hex() - str = chr(version).encode('latin-1').hex() + str - checksum = hash256(bytes.fromhex(str)).hex() - str += checksum[:8] - value = int('0x' + str, 0) + b = bytes([version]) + b # prepend version + b += hash256(b)[:4] # append checksum + value = int.from_bytes(b, 'big') while value > 0: result = chars[value % 58] + result value //= 58 - while (str[:2] == '00'): + while b[0] == 0: result = chars[0] + result - str = str[2:] + b = b[1:] return result diff --git a/test/functional/test_framework/netutil.py b/test/functional/test_framework/netutil.py index 174dc44a2a..b64f66e69b 100644 --- a/test/functional/test_framework/netutil.py +++ b/test/functional/test_framework/netutil.py @@ -144,7 +144,6 @@ def test_ipv6_local(): ''' Check for (local) IPv6 support. ''' - import socket # By using SOCK_DGRAM this will not actually make a connection, but it will # fail if there is no route to IPv6 localhost. have_ipv6 = True diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 0b9154a030..289e83579b 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -422,7 +422,8 @@ class TestNode(): time.sleep(0.05) self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log)) - def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> int: + @contextlib.contextmanager + def wait_for_debug_log(self, expected_msgs, timeout=60, ignore_case=False): """ Block until we see a particular debug log message fragment or until we exceed the timeout. Return: @@ -432,6 +433,8 @@ class TestNode(): prev_size = self.debug_log_bytes() re_flags = re.MULTILINE | (re.IGNORECASE if ignore_case else 0) + yield + while True: found = True with open(self.debug_log_path, encoding='utf-8') as dl: @@ -443,8 +446,7 @@ class TestNode(): found = False if found: - num_logs = len(log.splitlines()) - return num_logs + return if time.time() >= time_end: print_log = " - " + "\n - ".join(log.splitlines()) @@ -456,7 +458,6 @@ class TestNode(): self._raise_assertion_error( 'Expected messages "{}" does not partially match log:\n\n{}\n\n'.format( str(expected_msgs), print_log)) - return -1 # useless return to satisfy linter @contextlib.contextmanager def profile_with_perf(self, profile_name: str): diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 195af14914..210025104e 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -36,6 +36,7 @@ def assert_approx(v, vexp, vspan=0.00001): def assert_fee_amount(fee, tx_size, feerate_BTC_kvB): """Assert the fee is in range.""" + assert isinstance(tx_size, int) target_fee = get_fee(tx_size, feerate_BTC_kvB) if fee < target_fee: raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)" % (str(fee), str(target_fee))) @@ -219,7 +220,13 @@ def str_to_b64str(string): def ceildiv(a, b): - """Divide 2 ints and round up to next int rather than round down""" + """ + Divide 2 ints and round up to next int rather than round down + Implementation requires python integers, which have a // operator that does floor division. + Other types like decimal.Decimal whose // operator truncates towards 0 will not work. + """ + assert isinstance(a, int) + assert isinstance(b, int) return -(-a // b) @@ -227,7 +234,7 @@ def get_fee(tx_size, feerate_btc_kvb): """Calculate the fee in BTC given a feerate is BTC/kvB. Reflects CFeeRate::GetFee""" feerate_sat_kvb = int(feerate_btc_kvb * Decimal(1e8)) # Fee in sat/kvb as an int to avoid float precision errors target_fee_sat = ceildiv(feerate_sat_kvb * tx_size, 1000) # Round calculated fee up to nearest sat - return satoshi_round(target_fee_sat / Decimal(1e8)) # Truncate BTC result to nearest sat + return target_fee_sat / Decimal(1e8) # Return result in BTC def satoshi_round(amount): @@ -438,7 +445,7 @@ def delete_cookie_file(datadir, chain): def softfork_active(node, key): """Return whether a softfork is active.""" - return node.getblockchaininfo()['softforks'][key]['active'] + return node.getdeploymentinfo()['deployments'][key]['active'] def set_node_times(nodes, t): diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index eb2d030f4a..516e8be638 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -198,6 +198,7 @@ BASE_SCRIPTS = [ 'wallet_keypool.py --legacy-wallet', 'wallet_keypool.py --descriptors', 'wallet_descriptor.py --descriptors', + 'feature_maxtipage.py', 'p2p_nobloomfilter_messages.py', 'p2p_filter.py', 'rpc_setban.py', @@ -308,6 +309,7 @@ BASE_SCRIPTS = [ 'feature_coinstatsindex.py --legacy-wallet', 'feature_coinstatsindex.py --descriptors', 'wallet_orphanedreward.py', + 'wallet_timelock.py', 'p2p_node_network_limited.py', 'p2p_permissions.py', 'feature_blocksdir.py', @@ -319,6 +321,7 @@ BASE_SCRIPTS = [ 'rpc_getdescriptorinfo.py', 'rpc_mempool_entry_fee_fields_deprecation.py', 'rpc_help.py', + 'feature_dirsymlinks.py', 'feature_help.py', 'feature_shutdown.py', 'p2p_ibd_txrelay.py', @@ -530,8 +533,11 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= max_len_name = len(max(test_list, key=len)) test_count = len(test_list) + all_passed = True i = 0 while i < test_count: + if failfast and not all_passed: + break for test_result, testdir, stdout, stderr in job_queue.get_next(): test_results.append(test_result) i += 1 @@ -541,6 +547,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= elif test_result.status == "Skipped": logging.debug("%s skipped" % (done_str)) else: + all_passed = False print("%s failed, Duration: %s s\n" % (done_str, test_result.time)) print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n') print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n') @@ -574,7 +581,7 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage= if not os.listdir(tmpdir): os.rmdir(tmpdir) - all_passed = all(map(lambda test_result: test_result.was_successful, test_results)) and coverage_passed + all_passed = all_passed and coverage_passed # Clean up dangling processes if any. This may only happen with --failfast option. # Killing the process group will also terminate the current process but that is diff --git a/test/functional/wallet_abandonconflict.py b/test/functional/wallet_abandonconflict.py index 27d9d8da88..36fcdb36d6 100755 --- a/test/functional/wallet_abandonconflict.py +++ b/test/functional/wallet_abandonconflict.py @@ -29,20 +29,25 @@ class AbandonConflictTest(BitcoinTestFramework): self.skip_if_no_wallet() def run_test(self): + # create two wallets to tests conflicts from both sender's and receiver's sides + alice = self.nodes[0].get_wallet_rpc(self.default_wallet_name) + self.nodes[0].createwallet(wallet_name="bob") + bob = self.nodes[0].get_wallet_rpc("bob") + self.generate(self.nodes[1], COINBASE_MATURITY) - balance = self.nodes[0].getbalance() - txA = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) - txB = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) - txC = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), Decimal("10")) + balance = alice.getbalance() + txA = alice.sendtoaddress(alice.getnewaddress(), Decimal("10")) + txB = alice.sendtoaddress(alice.getnewaddress(), Decimal("10")) + txC = alice.sendtoaddress(alice.getnewaddress(), Decimal("10")) self.sync_mempools() self.generate(self.nodes[1], 1) # Can not abandon non-wallet transaction - assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', lambda: self.nodes[0].abandontransaction(txid='ff' * 32)) + assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', lambda: alice.abandontransaction(txid='ff' * 32)) # Can not abandon confirmed transaction - assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: self.nodes[0].abandontransaction(txid=txA)) + assert_raises_rpc_error(-5, 'Transaction not eligible for abandonment', lambda: alice.abandontransaction(txid=txA)) - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert balance - newbalance < Decimal("0.001") #no more than fees lost balance = newbalance @@ -50,9 +55,9 @@ class AbandonConflictTest(BitcoinTestFramework): self.disconnect_nodes(0, 1) # Identify the 10btc outputs - nA = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txA)["details"] if tx_out["amount"] == Decimal("10")) - nB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txB)["details"] if tx_out["amount"] == Decimal("10")) - nC = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txC)["details"] if tx_out["amount"] == Decimal("10")) + nA = next(tx_out["vout"] for tx_out in alice.gettransaction(txA)["details"] if tx_out["amount"] == Decimal("10")) + nB = next(tx_out["vout"] for tx_out in alice.gettransaction(txB)["details"] if tx_out["amount"] == Decimal("10")) + nC = next(tx_out["vout"] for tx_out in alice.gettransaction(txC)["details"] if tx_out["amount"] == Decimal("10")) inputs = [] # spend 10btc outputs from txA and txB @@ -60,39 +65,40 @@ class AbandonConflictTest(BitcoinTestFramework): inputs.append({"txid": txB, "vout": nB}) outputs = {} - outputs[self.nodes[0].getnewaddress()] = Decimal("14.99998") - outputs[self.nodes[1].getnewaddress()] = Decimal("5") - signed = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) + outputs[alice.getnewaddress()] = Decimal("14.99998") + outputs[bob.getnewaddress()] = Decimal("5") + signed = alice.signrawtransactionwithwallet(alice.createrawtransaction(inputs, outputs)) txAB1 = self.nodes[0].sendrawtransaction(signed["hex"]) # Identify the 14.99998btc output - nAB = next(tx_out["vout"] for tx_out in self.nodes[0].gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998")) + nAB = next(tx_out["vout"] for tx_out in alice.gettransaction(txAB1)["details"] if tx_out["amount"] == Decimal("14.99998")) #Create a child tx spending AB1 and C inputs = [] inputs.append({"txid": txAB1, "vout": nAB}) inputs.append({"txid": txC, "vout": nC}) outputs = {} - outputs[self.nodes[0].getnewaddress()] = Decimal("24.9996") - signed2 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) + outputs[alice.getnewaddress()] = Decimal("24.9996") + signed2 = alice.signrawtransactionwithwallet(alice.createrawtransaction(inputs, outputs)) txABC2 = self.nodes[0].sendrawtransaction(signed2["hex"]) # Create a child tx spending ABC2 signed3_change = Decimal("24.999") inputs = [{"txid": txABC2, "vout": 0}] - outputs = {self.nodes[0].getnewaddress(): signed3_change} - signed3 = self.nodes[0].signrawtransactionwithwallet(self.nodes[0].createrawtransaction(inputs, outputs)) + outputs = {alice.getnewaddress(): signed3_change} + signed3 = alice.signrawtransactionwithwallet(alice.createrawtransaction(inputs, outputs)) # note tx is never directly referenced, only abandoned as a child of the above self.nodes[0].sendrawtransaction(signed3["hex"]) # In mempool txs from self should increase balance from change - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance - Decimal("30") + signed3_change) balance = newbalance # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction self.restart_node(0, extra_args=["-minrelaytxfee=0.0001"]) + alice = self.nodes[0].get_wallet_rpc(self.default_wallet_name) assert self.nodes[0].getmempoolinfo()['loaded'] # Verify txs no longer in either node's mempool @@ -101,25 +107,25 @@ class AbandonConflictTest(BitcoinTestFramework): # Not in mempool txs from self should only reduce balance # inputs are still spent, but change not received - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance - signed3_change) # Unconfirmed received funds that are not in mempool, also shouldn't show # up in unconfirmed balance - balances = self.nodes[0].getbalances()['mine'] + balances = alice.getbalances()['mine'] assert_equal(balances['untrusted_pending'] + balances['trusted'], newbalance) # Also shouldn't show up in listunspent - assert not txABC2 in [utxo["txid"] for utxo in self.nodes[0].listunspent(0)] + assert not txABC2 in [utxo["txid"] for utxo in alice.listunspent(0)] balance = newbalance # Abandon original transaction and verify inputs are available again # including that the child tx was also abandoned - self.nodes[0].abandontransaction(txAB1) - newbalance = self.nodes[0].getbalance() + alice.abandontransaction(txAB1) + newbalance = alice.getbalance() assert_equal(newbalance, balance + Decimal("30")) balance = newbalance self.log.info("Check abandoned transactions in listsinceblock") - listsinceblock = self.nodes[0].listsinceblock() + listsinceblock = alice.listsinceblock() txAB1_listsinceblock = [d for d in listsinceblock['transactions'] if d['txid'] == txAB1 and d['category'] == 'send'] for tx in txAB1_listsinceblock: assert_equal(tx['abandoned'], True) @@ -128,49 +134,53 @@ class AbandonConflictTest(BitcoinTestFramework): # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned self.restart_node(0, extra_args=["-minrelaytxfee=0.00001"]) + alice = self.nodes[0].get_wallet_rpc(self.default_wallet_name) assert self.nodes[0].getmempoolinfo()['loaded'] assert_equal(len(self.nodes[0].getrawmempool()), 0) - assert_equal(self.nodes[0].getbalance(), balance) + assert_equal(alice.getbalance(), balance) # But if it is received again then it is unabandoned # And since now in mempool, the change is available # But its child tx remains abandoned self.nodes[0].sendrawtransaction(signed["hex"]) - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance - Decimal("20") + Decimal("14.99998")) balance = newbalance # Send child tx again so it is unabandoned self.nodes[0].sendrawtransaction(signed2["hex"]) - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance - Decimal("10") - Decimal("14.99998") + Decimal("24.9996")) balance = newbalance # Remove using high relay fee again self.restart_node(0, extra_args=["-minrelaytxfee=0.0001"]) + alice = self.nodes[0].get_wallet_rpc(self.default_wallet_name) assert self.nodes[0].getmempoolinfo()['loaded'] assert_equal(len(self.nodes[0].getrawmempool()), 0) - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance - Decimal("24.9996")) balance = newbalance self.log.info("Test transactions conflicted by a double spend") + self.nodes[0].loadwallet("bob") + bob = self.nodes[0].get_wallet_rpc("bob") + # Create a double spend of AB1 by spending again from only A's 10 output # Mine double spend from node 1 inputs = [] inputs.append({"txid": txA, "vout": nA}) outputs = {} - outputs[self.nodes[1].getnewaddress()] = Decimal("9.9999") - tx = self.nodes[0].createrawtransaction(inputs, outputs) - signed = self.nodes[0].signrawtransactionwithwallet(tx) - self.nodes[1].sendrawtransaction(signed["hex"]) - self.generate(self.nodes[1], 1, sync_fun=self.no_op) - + outputs[self.nodes[1].getnewaddress()] = Decimal("3.9999") + outputs[bob.getnewaddress()] = Decimal("5.9999") + tx = alice.createrawtransaction(inputs, outputs) + signed = alice.signrawtransactionwithwallet(tx) + double_spend_txid = self.nodes[1].sendrawtransaction(signed["hex"]) self.connect_nodes(0, 1) - self.sync_blocks() + self.generate(self.nodes[1], 1) - tx_list = self.nodes[0].listtransactions() + tx_list = alice.listtransactions() conflicted = [tx for tx in tx_list if tx["confirmations"] < 0] assert_equal(4, len(conflicted)) @@ -179,7 +189,7 @@ class AbandonConflictTest(BitcoinTestFramework): assert_equal(2, len(wallet_conflicts)) double_spends = [tx for tx in tx_list if tx["walletconflicts"] and tx["confirmations"] > 0] - assert_equal(1, len(double_spends)) + assert_equal(2, len(double_spends)) # one for each output double_spend = double_spends[0] # Test the properties of the conflicted transactions, i.e. with confirmations < 0. @@ -198,8 +208,19 @@ class AbandonConflictTest(BitcoinTestFramework): assert_equal(double_spend["walletconflicts"], [tx["txid"]]) assert_equal(tx["walletconflicts"], [double_spend["txid"]]) + # Test walletconflicts on the receiver's side + txinfo = bob.gettransaction(txAB1) + assert_equal(txinfo['confirmations'], -1) + assert_equal(txinfo['walletconflicts'], [double_spend['txid']]) + + double_spends = [tx for tx in bob.listtransactions() if tx["walletconflicts"] and tx["confirmations"] > 0] + assert_equal(1, len(double_spends)) + double_spend = double_spends[0] + assert_equal(double_spend_txid, double_spend['txid']) + assert_equal(double_spend["walletconflicts"], [txAB1]) + # Verify that B and C's 10 BTC outputs are available for spending again because AB1 is now conflicted - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() assert_equal(newbalance, balance + Decimal("20")) balance = newbalance @@ -207,7 +228,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Invalidate the block with the double spend and B's 10 BTC output should no longer be available # Don't think C's should either self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) - newbalance = self.nodes[0].getbalance() + newbalance = alice.getbalance() #assert_equal(newbalance, balance - Decimal("10")) self.log.info("If balance has not declined after invalidateblock then out of mempool wallet tx which is no longer") self.log.info("conflicted has not resumed causing its inputs to be seen as spent. See Issue #7315") diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 0b868dde6c..dcb82bbbe9 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -11,6 +11,7 @@ from threading import Thread import os import shutil import stat +import sys import time from test_framework.authproxy import JSONRPCException @@ -141,7 +142,7 @@ class MultiWalletTest(BitcoinTestFramework): # should raise rpc error if wallet path can't be created err_code = -4 if self.options.descriptors else -1 - assert_raises_rpc_error(err_code, "boost::filesystem::create_directory:", self.nodes[0].createwallet, "w8/bad") + assert_raises_rpc_error(err_code, "filesystem error:" if sys.platform != 'win32' else "create_directories:", self.nodes[0].createwallet, "w8/bad") # check that all requested wallets were created self.stop_node(0) diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py index d77d554baa..86e36be8f7 100755 --- a/test/functional/wallet_send.py +++ b/test/functional/wallet_send.py @@ -16,6 +16,7 @@ from test_framework.util import ( assert_fee_amount, assert_greater_than, assert_raises_rpc_error, + count_bytes, ) from test_framework.wallet_util import bytes_to_wif @@ -320,20 +321,20 @@ class WalletSendTest(BitcoinTestFramework): res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=7, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00007")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00007")) # "unset" and None are treated the same for estimate_mode res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, fee_rate=2, estimate_mode="unset", add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00002")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00002")) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=4.531, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00004531")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00004531")) res = self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=3, add_to_wallet=False) fee = self.nodes[1].decodepsbt(res["psbt"])["fee"] - assert_fee_amount(fee, Decimal(len(res["hex"]) / 2), Decimal("0.00003")) + assert_fee_amount(fee, count_bytes(res["hex"]), Decimal("0.00003")) # Test that passing fee_rate as both an argument and an option raises. self.test_send(from_wallet=w0, to_wallet=w1, amount=1, arg_fee_rate=1, fee_rate=1, add_to_wallet=False, @@ -518,5 +519,45 @@ class WalletSendTest(BitcoinTestFramework): assert signed["complete"] self.nodes[0].finalizepsbt(signed["psbt"]) + dec = self.nodes[0].decodepsbt(signed["psbt"]) + for i, txin in enumerate(dec["tx"]["vin"]): + if txin["txid"] == ext_utxo["txid"] and txin["vout"] == ext_utxo["vout"]: + input_idx = i + break + psbt_in = dec["inputs"][input_idx] + # Calculate the input weight + # (prevout + sequence + length of scriptSig + 2 bytes buffer) * 4 + len of scriptwitness + len_scriptsig = len(psbt_in["final_scriptSig"]["hex"]) // 2 if "final_scriptSig" in psbt_in else 0 + len_scriptwitness = len(psbt_in["final_scriptwitness"]["hex"]) // 2 if "final_scriptwitness" in psbt_in else 0 + input_weight = ((41 + len_scriptsig + 2) * 4) + len_scriptwitness + + # Input weight error conditions + assert_raises_rpc_error( + -8, + "Input weights should be specified in inputs rather than in options.", + ext_wallet.send, + outputs={self.nodes[0].getnewaddress(): 15}, + options={"inputs": [ext_utxo], "input_weights": [{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": 1000}]} + ) + + # Funding should also work when input weights are provided + res = self.test_send( + from_wallet=ext_wallet, + to_wallet=self.nodes[0], + amount=15, + inputs=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "weight": input_weight}], + add_inputs=True, + psbt=True, + include_watching=True, + fee_rate=10 + ) + signed = ext_wallet.walletprocesspsbt(res["psbt"]) + signed = ext_fund.walletprocesspsbt(res["psbt"]) + assert signed["complete"] + tx = self.nodes[0].finalizepsbt(signed["psbt"]) + testres = self.nodes[0].testmempoolaccept([tx["hex"]])[0] + assert_equal(testres["allowed"], True) + assert_fee_amount(testres["fees"]["base"], testres["vsize"], Decimal(0.0001)) + if __name__ == '__main__': WalletSendTest().main() diff --git a/test/functional/wallet_signer.py b/test/functional/wallet_signer.py index 9e2db517b6..423cfecdc0 100755 --- a/test/functional/wallet_signer.py +++ b/test/functional/wallet_signer.py @@ -72,10 +72,12 @@ class WalletSignerTest(BitcoinTestFramework): self.nodes[1].createwallet(wallet_name='hww', disable_private_keys=True, descriptors=True, external_signer=True) hww = self.nodes[1].get_wallet_rpc('hww') + assert_equal(hww.getwalletinfo()["external_signer"], True) # Flag can't be set afterwards (could be added later for non-blank descriptor based watch-only wallets) self.nodes[1].createwallet(wallet_name='not_hww', disable_private_keys=True, descriptors=True, external_signer=False) not_hww = self.nodes[1].get_wallet_rpc('not_hww') + assert_equal(not_hww.getwalletinfo()["external_signer"], False) assert_raises_rpc_error(-8, "Wallet flag is immutable: external_signer", not_hww.setwalletflag, "external_signer", True) # assert_raises_rpc_error(-4, "Multiple signers found, please specify which to use", wallet_name='not_hww', disable_private_keys=True, descriptors=True, external_signer=True) diff --git a/test/functional/wallet_timelock.py b/test/functional/wallet_timelock.py new file mode 100755 index 0000000000..cf233a00ef --- /dev/null +++ b/test/functional/wallet_timelock.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# Copyright (c) 2022 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + + +class WalletLocktimeTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + node = self.nodes[0] + + mtp_tip = node.getblockheader(node.getbestblockhash())["mediantime"] + + self.log.info("Get new address with label") + label = "timelock⌛🔓" + address = node.getnewaddress(label=label) + + self.log.info("Send to new address with locktime") + node.send( + outputs={address: 5}, + options={"locktime": mtp_tip - 1}, + ) + self.generate(node, 1) + + self.log.info("Check that clock can not change finality of confirmed txs") + amount_before_ad = node.getreceivedbyaddress(address) + amount_before_lb = node.getreceivedbylabel(label) + list_before_ad = node.listreceivedbyaddress(address_filter=address) + list_before_lb = node.listreceivedbylabel(include_empty=False) + balance_before = node.getbalances()["mine"]["trusted"] + coin_before = node.listunspent(maxconf=1) + node.setmocktime(mtp_tip - 1) + assert_equal(node.getreceivedbyaddress(address), amount_before_ad) + assert_equal(node.getreceivedbylabel(label), amount_before_lb) + assert_equal(node.listreceivedbyaddress(address_filter=address), list_before_ad) + assert_equal(node.listreceivedbylabel(include_empty=False), list_before_lb) + assert_equal(node.getbalances()["mine"]["trusted"], balance_before) + assert_equal(node.listunspent(maxconf=1), coin_before) + + +if __name__ == "__main__": + WalletLocktimeTest().main() diff --git a/test/lint/commit-script-check.sh b/test/lint/commit-script-check.sh index 6a8a15d05c..9449b393f1 100755 --- a/test/lint/commit-script-check.sh +++ b/test/lint/commit-script-check.sh @@ -17,6 +17,11 @@ if test -z "$1"; then exit 1 fi +if ! sed --help 2>&1 | grep -q 'GNU'; then + echo "Error: the installed sed package is not compatible. Please make sure you have GNU sed installed in your system."; + exit 1; +fi + RET=0 PREV_BRANCH=$(git name-rev --name-only HEAD) PREV_HEAD=$(git rev-parse HEAD) diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index 98d5021657..9e72831ee9 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -54,8 +54,6 @@ EXPECTED_BOOST_INCLUDES=( boost/algorithm/string/replace.hpp boost/algorithm/string/split.hpp boost/date_time/posix_time/posix_time.hpp - boost/filesystem.hpp - boost/filesystem/fstream.hpp boost/multi_index/hashed_index.hpp boost/multi_index/ordered_index.hpp boost/multi_index/sequenced_index.hpp @@ -64,6 +62,7 @@ EXPECTED_BOOST_INCLUDES=( boost/signals2/connection.hpp boost/signals2/optional_last_value.hpp boost/signals2/signal.hpp + boost/test/included/unit_test.hpp boost/test/unit_test.hpp ) diff --git a/test/lint/lint-spelling.ignore-words.txt b/test/lint/lint-spelling.ignore-words.txt index 9906b15e9a..afdb0692d8 100644 --- a/test/lint/lint-spelling.ignore-words.txt +++ b/test/lint/lint-spelling.ignore-words.txt @@ -1,6 +1,8 @@ asend +ba blockin cachable +creat fo fpr hights diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan index 3c5a15a0c7..26f3fdc7af 100644 --- a/test/sanitizer_suppressions/tsan +++ b/test/sanitizer_suppressions/tsan @@ -22,14 +22,13 @@ deadlock:sync_tests::potential_deadlock_detected race:src/qt/test/* deadlock:src/qt/test/* -# Race in src/test/main.cpp -# Can be removed once upgraded to boost test 1.74 in depends -race:validation_chainstatemanager_tests - # External libraries deadlock:libdb race:libzmq +# Race in headers only Boost Test +race:std::__1::ios_base::flags + # Intermittent issues # ------------------- # diff --git a/test/sanitizer_suppressions/ubsan b/test/sanitizer_suppressions/ubsan index 6e4ac80927..bdaee5d191 100644 --- a/test/sanitizer_suppressions/ubsan +++ b/test/sanitizer_suppressions/ubsan @@ -43,15 +43,10 @@ shift-base:test/fuzz/crypto_diff_fuzz_chacha20.cpp # contains files in which we expect unsigned integer overflows to occur. The # list is used to suppress -fsanitize=integer warnings when running our CI UBSan # job. -unsigned-integer-overflow:addrman.cpp unsigned-integer-overflow:arith_uint256.h -unsigned-integer-overflow:bitcoin-tx.cpp unsigned-integer-overflow:common/bloom.cpp -unsigned-integer-overflow:chain.cpp -unsigned-integer-overflow:chain.h unsigned-integer-overflow:coins.cpp unsigned-integer-overflow:compressor.cpp -unsigned-integer-overflow:core_write.cpp unsigned-integer-overflow:crypto/ unsigned-integer-overflow:hash.cpp unsigned-integer-overflow:policy/fees.cpp @@ -60,47 +55,19 @@ unsigned-integer-overflow:pubkey.h unsigned-integer-overflow:script/interpreter.cpp unsigned-integer-overflow:txmempool.cpp unsigned-integer-overflow:util/strencodings.cpp -unsigned-integer-overflow:validation.cpp -implicit-integer-sign-change:addrman.h -implicit-integer-sign-change:arith_uint256.cpp implicit-integer-sign-change:bech32.cpp -implicit-integer-sign-change:common/bloom.cpp -implicit-integer-sign-change:chain.cpp -implicit-integer-sign-change:chain.h -implicit-integer-sign-change:coins.h implicit-integer-sign-change:compat/stdin.cpp implicit-integer-sign-change:compressor.h implicit-integer-sign-change:crypto/ implicit-integer-sign-change:key.cpp -implicit-integer-sign-change:noui.cpp implicit-integer-sign-change:policy/fees.cpp implicit-integer-sign-change:prevector.h implicit-integer-sign-change:script/bitcoinconsensus.cpp implicit-integer-sign-change:script/interpreter.cpp implicit-integer-sign-change:serialize.h -implicit-integer-sign-change:test/arith_uint256_tests.cpp -implicit-integer-sign-change:test/coins_tests.cpp -implicit-integer-sign-change:test/pow_tests.cpp -implicit-integer-sign-change:test/prevector_tests.cpp -implicit-integer-sign-change:test/sighash_tests.cpp -implicit-integer-sign-change:test/skiplist_tests.cpp -implicit-integer-sign-change:test/streams_tests.cpp -implicit-integer-sign-change:test/transaction_tests.cpp implicit-integer-sign-change:txmempool.cpp -implicit-integer-sign-change:zmq/zmqpublishnotifier.cpp -implicit-signed-integer-truncation,implicit-integer-sign-change:chain.h -implicit-signed-integer-truncation,implicit-integer-sign-change:test/skiplist_tests.cpp implicit-signed-integer-truncation:addrman.cpp -implicit-signed-integer-truncation:addrman.h -implicit-signed-integer-truncation:chain.h implicit-signed-integer-truncation:crypto/ -implicit-signed-integer-truncation:node/miner.cpp -implicit-signed-integer-truncation:net.cpp -implicit-signed-integer-truncation:net_processing.cpp -implicit-signed-integer-truncation:streams.h -implicit-signed-integer-truncation:test/arith_uint256_tests.cpp -implicit-signed-integer-truncation:test/skiplist_tests.cpp -implicit-signed-integer-truncation:torcontrol.cpp implicit-unsigned-integer-truncation:crypto/ shift-base:arith_uint256.cpp shift-base:crypto/ diff --git a/test/util/data/tt-delin1-out.json b/test/util/data/tt-delin1-out.json index c5b9f6df01..6e053fe2b9 100644 --- a/test/util/data/tt-delin1-out.json +++ b/test/util/data/tt-delin1-out.json @@ -194,6 +194,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o)#xvg87vgr", "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o", "type": "pubkeyhash" @@ -204,6 +205,7 @@ "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb)#tsyprkms", "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", "address": "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb", "type": "pubkeyhash" diff --git a/test/util/data/tt-delout1-out.json b/test/util/data/tt-delout1-out.json index 3863416430..e61b9c79db 100644 --- a/test/util/data/tt-delout1-out.json +++ b/test/util/data/tt-delout1-out.json @@ -203,6 +203,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o)#xvg87vgr", "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o", "type": "pubkeyhash" diff --git a/test/util/data/tt-locktime317000-out.json b/test/util/data/tt-locktime317000-out.json index 62e785f7d0..873628e124 100644 --- a/test/util/data/tt-locktime317000-out.json +++ b/test/util/data/tt-locktime317000-out.json @@ -203,6 +203,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 8fd139bb39ced713f231c58a4d07bf6954d1c201 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o)#xvg87vgr", "hex": "76a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac", "address": "1E7SGgAZFCHDnVZLuRViX3gUmxpMfdvd2o", "type": "pubkeyhash" @@ -213,6 +214,7 @@ "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 6c772e9cf96371bba3da8cb733da70a2fcf20078 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb)#tsyprkms", "hex": "76a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac", "address": "1AtWkdmfmYkErU16d3KYykJUbEp9MAj9Sb", "type": "pubkeyhash" diff --git a/test/util/data/txcreate1.json b/test/util/data/txcreate1.json index 96d77ef273..c4a76f22a6 100644 --- a/test/util/data/txcreate1.json +++ b/test/util/data/txcreate1.json @@ -41,6 +41,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(13tuJJDR2RgArmgfv6JScSdreahzgc4T6o)#ztmwxg4c", "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac", "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "type": "pubkeyhash" @@ -51,6 +52,7 @@ "n": 1, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 f2d4db28cad6502226ee484ae24505c2885cb12d OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46)#vdmdu766", "hex": "76a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac", "address": "1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46", "type": "pubkeyhash" diff --git a/test/util/data/txcreate2.json b/test/util/data/txcreate2.json index ee9b9c3c17..95953cc90e 100644 --- a/test/util/data/txcreate2.json +++ b/test/util/data/txcreate2.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "", + "desc": "raw()#58lrscpx", "hex": "", "type": "nonstandard" } diff --git a/test/util/data/txcreatedata1.json b/test/util/data/txcreatedata1.json index 87fc7e9cf7..1454ffdab7 100644 --- a/test/util/data/txcreatedata1.json +++ b/test/util/data/txcreatedata1.json @@ -23,6 +23,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(13tuJJDR2RgArmgfv6JScSdreahzgc4T6o)#ztmwxg4c", "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac", "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "type": "pubkeyhash" @@ -33,6 +34,7 @@ "n": 1, "scriptPubKey": { "asm": "OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e", + "desc": "raw(6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e)#zf2avljj", "hex": "6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e", "type": "nulldata" } diff --git a/test/util/data/txcreatedata2.json b/test/util/data/txcreatedata2.json index d03b1c8244..ca20d2aa45 100644 --- a/test/util/data/txcreatedata2.json +++ b/test/util/data/txcreatedata2.json @@ -23,6 +23,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(13tuJJDR2RgArmgfv6JScSdreahzgc4T6o)#ztmwxg4c", "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac", "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "type": "pubkeyhash" @@ -33,6 +34,7 @@ "n": 1, "scriptPubKey": { "asm": "OP_RETURN 54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e", + "desc": "raw(6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e)#zf2avljj", "hex": "6a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e", "type": "nulldata" } diff --git a/test/util/data/txcreatedata_seq0.json b/test/util/data/txcreatedata_seq0.json index 8a123f1ba8..9838383c06 100644 --- a/test/util/data/txcreatedata_seq0.json +++ b/test/util/data/txcreatedata_seq0.json @@ -23,6 +23,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(13tuJJDR2RgArmgfv6JScSdreahzgc4T6o)#ztmwxg4c", "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac", "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "type": "pubkeyhash" diff --git a/test/util/data/txcreatedata_seq1.json b/test/util/data/txcreatedata_seq1.json index 006fd7259f..c729f8dcfb 100644 --- a/test/util/data/txcreatedata_seq1.json +++ b/test/util/data/txcreatedata_seq1.json @@ -32,6 +32,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 1fc11f39be1729bf973a7ab6a615ca4729d64574 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(13tuJJDR2RgArmgfv6JScSdreahzgc4T6o)#ztmwxg4c", "hex": "76a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac", "address": "13tuJJDR2RgArmgfv6JScSdreahzgc4T6o", "type": "pubkeyhash" diff --git a/test/util/data/txcreatemultisig1.json b/test/util/data/txcreatemultisig1.json index baa290c2b1..9632b20ece 100644 --- a/test/util/data/txcreatemultisig1.json +++ b/test/util/data/txcreatemultisig1.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "2 02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d 02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485 3 OP_CHECKMULTISIG", + "desc": "multi(2,02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397,021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d,02df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb485)#8s88p9pl", "hex": "522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae", "type": "multisig" } diff --git a/test/util/data/txcreatemultisig2.json b/test/util/data/txcreatemultisig2.json index 6685512587..021cf539a8 100644 --- a/test/util/data/txcreatemultisig2.json +++ b/test/util/data/txcreatemultisig2.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 1c6fbaf46d64221e80cbae182c33ddf81b9294ac OP_EQUAL", + "desc": "addr(34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms)#ngnz8933", "hex": "a9141c6fbaf46d64221e80cbae182c33ddf81b9294ac87", "address": "34HNh57oBCRKkxNyjTuWAJkTbuGh6jg2Ms", "type": "scripthash" diff --git a/test/util/data/txcreatemultisig3.json b/test/util/data/txcreatemultisig3.json index be96f4c704..3c20a88a91 100644 --- a/test/util/data/txcreatemultisig3.json +++ b/test/util/data/txcreatemultisig3.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "0 e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05", + "desc": "addr(bc1qu9dgdg330r6r84g5mw7wqshg04exv2uttmw2elfwx74h5tgntuzs44gyfg)#yvt39j9m", "hex": "0020e15a86a23178f433d514dbbce042e87d72662b8b5edcacfd2e37ab7a2d135f05", "address": "bc1qu9dgdg330r6r84g5mw7wqshg04exv2uttmw2elfwx74h5tgntuzs44gyfg", "type": "witness_v0_scripthash" diff --git a/test/util/data/txcreatemultisig4.json b/test/util/data/txcreatemultisig4.json index 08831ecdca..7ae18fd90a 100644 --- a/test/util/data/txcreatemultisig4.json +++ b/test/util/data/txcreatemultisig4.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 6edf12858999f0dae74f9c692e6694ee3621b2ac OP_EQUAL", + "desc": "addr(3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH)#466tx6fn", "hex": "a9146edf12858999f0dae74f9c692e6694ee3621b2ac87", "address": "3BoFUz1StqcNcgUTZE5cC1eFhuYFzj3fGH", "type": "scripthash" diff --git a/test/util/data/txcreatemultisig5.json b/test/util/data/txcreatemultisig5.json index 93048cf261..98a5c2d8d1 100644 --- a/test/util/data/txcreatemultisig5.json +++ b/test/util/data/txcreatemultisig5.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 a4051c02398868af83f28f083208fae99a769263 OP_EQUAL", + "desc": "addr(3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos)#juhnnegr", "hex": "a914a4051c02398868af83f28f083208fae99a76926387", "address": "3GeGs1eHUxPz5YyuFe9WPpXid2UsUb5Jos", "type": "scripthash" diff --git a/test/util/data/txcreateoutpubkey1.json b/test/util/data/txcreateoutpubkey1.json index 42b519bb21..3baf479991 100644 --- a/test/util/data/txcreateoutpubkey1.json +++ b/test/util/data/txcreateoutpubkey1.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397 OP_CHECKSIG", + "desc": "pk(02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397)#rk5v7uqw", "hex": "2102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397ac", "type": "pubkey" } diff --git a/test/util/data/txcreateoutpubkey2.json b/test/util/data/txcreateoutpubkey2.json index 52168a889b..78acf1658b 100644 --- a/test/util/data/txcreateoutpubkey2.json +++ b/test/util/data/txcreateoutpubkey2.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "0 a2516e770582864a6a56ed21a102044e388c62e3", + "desc": "addr(bc1q5fgkuac9s2ry56jka5s6zqsyfcugcchry5cwu0)#gm7zhxq2", "hex": "0014a2516e770582864a6a56ed21a102044e388c62e3", "address": "bc1q5fgkuac9s2ry56jka5s6zqsyfcugcchry5cwu0", "type": "witness_v0_keyhash" diff --git a/test/util/data/txcreateoutpubkey3.json b/test/util/data/txcreateoutpubkey3.json index fce210f8a3..632ed52ccf 100644 --- a/test/util/data/txcreateoutpubkey3.json +++ b/test/util/data/txcreateoutpubkey3.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 a5ab14c9804d0d8bf02f1aea4e82780733ad0a83 OP_EQUAL", + "desc": "addr(3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn)#zsln680u", "hex": "a914a5ab14c9804d0d8bf02f1aea4e82780733ad0a8387", "address": "3GnzN8FqgvYGYdhj8NW6UNxxVv3Uj1ApQn", "type": "scripthash" diff --git a/test/util/data/txcreatescript1.json b/test/util/data/txcreatescript1.json index af1c4c35e2..cdee9dbbfa 100644 --- a/test/util/data/txcreatescript1.json +++ b/test/util/data/txcreatescript1.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DROP", + "desc": "raw(75)#ppey0zqj", "hex": "75", "type": "nonstandard" } diff --git a/test/util/data/txcreatescript2.json b/test/util/data/txcreatescript2.json index 2cde70fdf7..1fbae62f4b 100644 --- a/test/util/data/txcreatescript2.json +++ b/test/util/data/txcreatescript2.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 71ed53322d470bb96657deb786b94f97dd46fb15 OP_EQUAL", + "desc": "addr(3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp)#5mx9waq3", "hex": "a91471ed53322d470bb96657deb786b94f97dd46fb1587", "address": "3C5QarEGh9feKbDJ3QbMf2YNjnMoiPDhNp", "type": "scripthash" diff --git a/test/util/data/txcreatescript3.json b/test/util/data/txcreatescript3.json index 7a282faf4f..502fe91692 100644 --- a/test/util/data/txcreatescript3.json +++ b/test/util/data/txcreatescript3.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "0 0bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6", + "desc": "addr(bc1qp0lfxhnscvsu0j36l36uurgv5tuck4pzuqytkvwqp3kh78cupttqyf705v)#s4fdh9tu", "hex": "00200bfe935e70c321c7ca3afc75ce0d0ca2f98b5422e008bb31c00c6d7f1f1c0ad6", "address": "bc1qp0lfxhnscvsu0j36l36uurgv5tuck4pzuqytkvwqp3kh78cupttqyf705v", "type": "witness_v0_scripthash" diff --git a/test/util/data/txcreatescript4.json b/test/util/data/txcreatescript4.json index 298b37bb4a..1ed89dfff2 100644 --- a/test/util/data/txcreatescript4.json +++ b/test/util/data/txcreatescript4.json @@ -14,6 +14,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_HASH160 6a2c482f4985f57e702f325816c90e3723ca81ae OP_EQUAL", + "desc": "addr(3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f)#fdleltnv", "hex": "a9146a2c482f4985f57e702f325816c90e3723ca81ae87", "address": "3BNQbeFeJJGMAyDxPwWPuqxPMrjsFLjk3f", "type": "scripthash" diff --git a/test/util/data/txcreatesignv1.json b/test/util/data/txcreatesignv1.json index ca5e003110..56ef9b195e 100644 --- a/test/util/data/txcreatesignv1.json +++ b/test/util/data/txcreatesignv1.json @@ -23,6 +23,7 @@ "n": 0, "scriptPubKey": { "asm": "OP_DUP OP_HASH160 5834479edbbe0539b31ffd3a8f8ebadc2165ed01 OP_EQUALVERIFY OP_CHECKSIG", + "desc": "addr(193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7)#nw04wh58", "hex": "76a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac", "address": "193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7", "type": "pubkeyhash" |