diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/functional/feature_fee_estimation.py | 10 | ||||
-rwxr-xr-x | test/functional/feature_notifications.py | 10 | ||||
-rwxr-xr-x | test/functional/feature_rbf.py | 18 | ||||
-rwxr-xr-x | test/functional/feature_segwit.py | 4 | ||||
-rwxr-xr-x | test/functional/p2p_filter.py | 34 | ||||
-rwxr-xr-x | test/functional/rpc_addresses_deprecation.py | 56 | ||||
-rwxr-xr-x | test/functional/test_framework/script_util.py | 57 | ||||
-rw-r--r-- | test/functional/test_framework/util.py | 2 | ||||
-rw-r--r-- | test/functional/test_framework/wallet.py | 28 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 2 | ||||
-rwxr-xr-x | test/functional/wallet_basic.py | 26 | ||||
-rwxr-xr-x | test/functional/wallet_hd.py | 2 | ||||
-rwxr-xr-x | test/functional/wallet_transactiontime_rescan.py | 161 | ||||
-rw-r--r-- | test/lint/README.md | 6 | ||||
-rwxr-xr-x | test/lint/lint-locale-dependence.sh | 4 | ||||
-rwxr-xr-x | test/lint/lint-logs.sh | 2 |
16 files changed, 286 insertions, 136 deletions
diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index c4610f98bd..9c225dc687 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -132,9 +132,13 @@ def check_smart_estimates(node, fees_seen): delta = 1.0e-6 # account for rounding error last_feerate = float(max(fees_seen)) all_smart_estimates = [node.estimatesmartfee(i) for i in range(1, 26)] + mempoolMinFee = node.getmempoolinfo()['mempoolminfee'] + minRelaytxFee = node.getmempoolinfo()['minrelaytxfee'] for i, e in enumerate(all_smart_estimates): # estimate is for i+1 feerate = float(e["feerate"]) assert_greater_than(feerate, 0) + assert_greater_than_or_equal(feerate, float(mempoolMinFee)) + assert_greater_than_or_equal(feerate, float(minRelaytxFee)) if feerate + delta < min(fees_seen) or feerate - delta > max(fees_seen): raise AssertionError(f"Estimated fee ({feerate}) out of range ({min(fees_seen)},{max(fees_seen)})") @@ -275,6 +279,12 @@ class EstimateFeeTest(BitcoinTestFramework): self.log.info("Final estimates after emptying mempools") check_estimates(self.nodes[1], self.fees_per_kb) + # check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee + self.log.info("Test fee rate estimation after restarting node with high MempoolMinFee") + high_val = 3*self.nodes[1].estimatesmartfee(1)['feerate'] + self.restart_node(1, extra_args=[f'-minrelaytxfee={high_val}']) + check_estimates(self.nodes[1], self.fees_per_kb) + self.log.info("Testing that fee estimation is disabled in blocksonly.") self.restart_node(0, ["-blocksonly"]) assert_raises_rpc_error(-32603, "Fee estimation disabled", diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index 5ef3860867..4382022a7a 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -42,7 +42,6 @@ class NotificationsTest(BitcoinTestFramework): f"-alertnotify=echo > {os.path.join(self.alertnotify_dir, '%s')}", f"-blocknotify=echo > {os.path.join(self.blocknotify_dir, '%s')}", ], [ - "-rescan", f"-walletnotify=echo %h_%b > {os.path.join(self.walletnotify_dir, notify_outputname('%w', '%s'))}", ]] self.wallet_names = [self.default_wallet_name, self.wallet] @@ -91,16 +90,15 @@ class NotificationsTest(BitcoinTestFramework): # directory content should equal the generated transaction hashes tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count))) - self.stop_node(1) self.expect_wallet_notify(tx_details) self.log.info("test -walletnotify after rescan") - # restart node to rescan to force wallet notifications - self.start_node(1) - self.connect_nodes(0, 1) - + # rescan to force wallet notifications + self.nodes[1].rescanblockchain() self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) + self.connect_nodes(0, 1) + # directory content should equal the generated transaction hashes tx_details = list(map(lambda t: (t['txid'], t['blockheight'], t['blockhash']), self.nodes[1].listtransactions("*", block_count))) self.expect_wallet_notify(tx_details) diff --git a/test/functional/feature_rbf.py b/test/functional/feature_rbf.py index a6e9cd2ed1..d759a5aab5 100755 --- a/test/functional/feature_rbf.py +++ b/test/functional/feature_rbf.py @@ -19,7 +19,6 @@ from test_framework.script import CScript, OP_DROP from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_greater_than, assert_raises_rpc_error, ) from test_framework.script_util import ( @@ -96,23 +95,10 @@ class ReplaceByFeeTest(BitcoinTestFramework): def make_utxo(self, node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT): """Create a txout with a given amount and scriptPubKey - Assumes that MiniWallet has enough funds to cover the amount and the fixed fee - (from it's internal utxos, the one with the largest value is taken). - confirmed - txouts created will be confirmed in the blockchain; unconfirmed otherwise. """ - # MiniWallet only supports sweeping utxos to its own internal scriptPubKey, so in - # order to create an output with arbitrary amount/scriptPubKey, we have to add it - # manually after calling the create_self_transfer method. The MiniWallet output's - # nValue has to be adapted accordingly (amount and fee deduction). To keep things - # simple, we use a fixed fee of 1000 Satoshis here. - fee = 1000 - tx = self.wallet.create_self_transfer(from_node=node, fee_rate=0, mempool_valid=False)['tx'] - assert_greater_than(tx.vout[0].nValue, amount + fee) - tx.vout[0].nValue -= (amount + fee) # change output -> MiniWallet - tx.vout.append(CTxOut(amount, scriptPubKey)) # desired output -> to be returned - txid = self.wallet.sendrawtransaction(from_node=node, tx_hex=tx.serialize().hex()) + txid, n = self.wallet.send_to(from_node=node, scriptPubKey=scriptPubKey, amount=amount) # If requested, ensure txouts are confirmed. if confirmed: @@ -125,7 +111,7 @@ class ReplaceByFeeTest(BitcoinTestFramework): assert new_size < mempool_size mempool_size = new_size - return COutPoint(int(txid, 16), 1) + return COutPoint(int(txid, 16), n) def test_simple_doublespend(self): """Simple doublespend""" diff --git a/test/functional/feature_segwit.py b/test/functional/feature_segwit.py index 4054a9a903..25d1cb2bf1 100755 --- a/test/functional/feature_segwit.py +++ b/test/functional/feature_segwit.py @@ -236,12 +236,14 @@ class SegWitTest(BitcoinTestFramework): self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork") txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1) + raw_tx = self.nodes[0].getrawtransaction(txid, True) tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']}) assert_greater_than_or_equal(tmpl['sizelimit'], 3999577) # actual maximum size is lower due to minimum mandatory non-witness data assert_equal(tmpl['weightlimit'], 4000000) assert_equal(tmpl['sigoplimit'], 80000) assert_equal(tmpl['transactions'][0]['txid'], txid) - assert_equal(tmpl['transactions'][0]['sigops'], 8) + expected_sigops = 9 if 'txinwitness' in raw_tx["vin"][0] else 8 + assert_equal(tmpl['transactions'][0]['sigops'], expected_sigops) assert '!segwit' in tmpl['rules'] self.generate(self.nodes[0], 1) # Mine a block to clear the gbt cache diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index a040665fba..0d8c298bea 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -8,6 +8,7 @@ Test BIP 37 from test_framework.messages import ( CInv, + COIN, MAX_BLOOM_FILTER_SIZE, MAX_BLOOM_HASH_FUNCS, MSG_BLOCK, @@ -28,11 +29,15 @@ from test_framework.p2p import ( ) from test_framework.script import MAX_SCRIPT_ELEMENT_SIZE from test_framework.test_framework import BitcoinTestFramework +from test_framework.wallet import ( + MiniWallet, + random_p2wpkh, +) class P2PBloomFilter(P2PInterface): # This is a P2SH watch-only wallet - watch_script_pubkey = 'a914ffffffffffffffffffffffffffffffffffffffff87' + watch_script_pubkey = bytes.fromhex('a914ffffffffffffffffffffffffffffffffffffffff87') # The initial filter (n=10, fp=0.000001) with just the above scriptPubKey added watch_filter_init = msg_filterload( data= @@ -93,8 +98,9 @@ class FilterTest(BitcoinTestFramework): '-whitelist=noban@127.0.0.1', # immediate tx relay ]] - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() + def generatetoscriptpubkey(self, scriptpubkey): + """Helper to generate a single block to the given scriptPubKey.""" + return self.generatetodescriptor(self.nodes[0], 1, f'raw({scriptpubkey.hex()})')[0] def test_size_limits(self, filter_peer): self.log.info('Check that too large filter is rejected') @@ -130,8 +136,7 @@ class FilterTest(BitcoinTestFramework): filter_peer = P2PBloomFilter() self.log.debug("Create a tx relevant to the peer before connecting") - filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address'] - txid = self.nodes[0].sendtoaddress(filter_address, 90) + txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN) self.log.debug("Send a mempool msg after connecting and check that the tx is received") self.nodes[0].add_p2p_connection(filter_peer) @@ -142,8 +147,7 @@ class FilterTest(BitcoinTestFramework): def test_frelay_false(self, filter_peer): self.log.info("Check that a node with fRelay set to false does not receive invs until the filter is set") filter_peer.tx_received = False - filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address'] - self.nodes[0].sendtoaddress(filter_address, 90) + self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN) # Sync to make sure the reason filter_peer doesn't receive the tx is not p2p delays filter_peer.sync_with_ping() assert not filter_peer.tx_received @@ -156,45 +160,44 @@ class FilterTest(BitcoinTestFramework): filter_peer.send_and_ping(filter_peer.watch_filter_init) # If fRelay is not already True, sending filterload sets it to True assert self.nodes[0].getpeerinfo()[0]['relaytxes'] - filter_address = self.nodes[0].decodescript(filter_peer.watch_script_pubkey)['address'] self.log.info('Check that we receive merkleblock and tx if the filter matches a tx in a block') - block_hash = self.generatetoaddress(self.nodes[0], 1, filter_address)[0] + block_hash = self.generatetoscriptpubkey(filter_peer.watch_script_pubkey) txid = self.nodes[0].getblock(block_hash)['tx'][0] filter_peer.wait_for_merkleblock(block_hash) filter_peer.wait_for_tx(txid) self.log.info('Check that we only receive a merkleblock if the filter does not match a tx in a block') filter_peer.tx_received = False - block_hash = self.generatetoaddress(self.nodes[0], 1, self.nodes[0].getnewaddress())[0] + block_hash = self.generatetoscriptpubkey(random_p2wpkh()) filter_peer.wait_for_merkleblock(block_hash) assert not filter_peer.tx_received self.log.info('Check that we not receive a tx if the filter does not match a mempool tx') filter_peer.merkleblock_received = False filter_peer.tx_received = False - self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 90) + self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN) filter_peer.sync_send_with_ping() assert not filter_peer.merkleblock_received assert not filter_peer.tx_received self.log.info('Check that we receive a tx if the filter matches a mempool tx') filter_peer.merkleblock_received = False - txid = self.nodes[0].sendtoaddress(filter_address, 90) + txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=filter_peer.watch_script_pubkey, amount=9 * COIN) filter_peer.wait_for_tx(txid) assert not filter_peer.merkleblock_received self.log.info('Check that after deleting filter all txs get relayed again') filter_peer.send_and_ping(msg_filterclear()) for _ in range(5): - txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 7) + txid, _ = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=random_p2wpkh(), amount=7 * COIN) filter_peer.wait_for_tx(txid) self.log.info('Check that request for filtered blocks is ignored if no filter is set') filter_peer.merkleblock_received = False filter_peer.tx_received = False with self.nodes[0].assert_debug_log(expected_msgs=['received getdata']): - block_hash = self.generatetoaddress(self.nodes[0], 1, self.nodes[0].getnewaddress())[0] + block_hash = self.generatetoscriptpubkey(random_p2wpkh()) filter_peer.wait_for_inv([CInv(MSG_BLOCK, int(block_hash, 16))]) filter_peer.sync_with_ping() assert not filter_peer.merkleblock_received @@ -210,6 +213,9 @@ class FilterTest(BitcoinTestFramework): self.nodes[0].disconnect_p2ps() def run_test(self): + self.wallet = MiniWallet(self.nodes[0]) + self.wallet.rescan_utxos() + filter_peer = self.nodes[0].add_p2p_connection(P2PBloomFilter()) self.log.info('Test filter size limits') self.test_size_limits(filter_peer) diff --git a/test/functional/rpc_addresses_deprecation.py b/test/functional/rpc_addresses_deprecation.py deleted file mode 100755 index e566fb0aa7..0000000000 --- a/test/functional/rpc_addresses_deprecation.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2020 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 deprecation of reqSigs and addresses RPC fields.""" - -from test_framework.messages import ( - tx_from_hex, -) -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, -) - - -class AddressesDeprecationTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 2 - self.extra_args = [[], ["-deprecatedrpc=addresses"]] - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - - def run_test(self): - self.test_addresses_deprecation() - - def test_addresses_deprecation(self): - node = self.nodes[0] - coin = node.listunspent().pop() - - inputs = [{'txid': coin['txid'], 'vout': coin['vout']}] - outputs = {node.getnewaddress(): 0.99} - raw = node.createrawtransaction(inputs, outputs) - signed = node.signrawtransactionwithwallet(raw)['hex'] - - # This transaction is derived from test/util/data/txcreatemultisig1.json - tx = tx_from_hex(signed) - tx.vout[0].scriptPubKey = bytes.fromhex("522102a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff39721021ac43c7ff740014c3b33737ede99c967e4764553d1b2b83db77c83b8715fa72d2102df2089105c77f266fa11a9d33f05c735234075f2e8780824c6b709415f9fb48553ae") - tx_signed = node.signrawtransactionwithwallet(tx.serialize().hex())['hex'] - txid = node.sendrawtransaction(hexstring=tx_signed, maxfeerate=0) - - self.log.info("Test RPCResult scriptPubKey no longer returns the fields addresses or reqSigs by default") - hash = self.generateblock(node, output=node.getnewaddress(), transactions=[txid])['hash'] - # Ensure both nodes have the newly generated block on disk. - self.sync_blocks() - script_pub_key = node.getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey'] - assert 'addresses' not in script_pub_key and 'reqSigs' not in script_pub_key - - self.log.info("Test RPCResult scriptPubKey returns the addresses field with -deprecatedrpc=addresses") - script_pub_key = self.nodes[1].getblock(blockhash=hash, verbose=2)['tx'][-1]['vout'][0]['scriptPubKey'] - assert_equal(script_pub_key['addresses'], ['mvKDK6D54HU8wQumJBLHY95eq5iHFqXSBz', 'mv3rHCQSwKp2BLSuMHD8uCS32LW5xiNAA5', 'mirrsyhAQYzo5CwVhcaYJKwUJu1WJRCRJe']) - assert_equal(script_pub_key['reqSigs'], 2) - - -if __name__ == "__main__": - AddressesDeprecationTest().main() diff --git a/test/functional/test_framework/script_util.py b/test/functional/test_framework/script_util.py index 5d1d7ea45c..e0dfce4c2f 100755 --- a/test/functional/test_framework/script_util.py +++ b/test/functional/test_framework/script_util.py @@ -3,7 +3,17 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Useful Script constants and utils.""" -from test_framework.script import CScript, hash160, sha256, OP_0, OP_DUP, OP_HASH160, OP_CHECKSIG, OP_EQUAL, OP_EQUALVERIFY +from test_framework.script import ( + CScript, + hash160, + sha256, + OP_0, + OP_DUP, + OP_HASH160, + OP_CHECKSIG, + OP_EQUAL, + OP_EQUALVERIFY, +) # To prevent a "tx-size-small" policy rule error, a transaction has to have a # non-witness size of at least 82 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in @@ -25,28 +35,34 @@ from test_framework.script import CScript, hash160, sha256, OP_0, OP_DUP, OP_HAS DUMMY_P2WPKH_SCRIPT = CScript([b'a' * 21]) DUMMY_2_P2WPKH_SCRIPT = CScript([b'b' * 21]) -def keyhash_to_p2pkh_script(hash, main = False): + +def keyhash_to_p2pkh_script(hash): assert len(hash) == 20 return CScript([OP_DUP, OP_HASH160, hash, OP_EQUALVERIFY, OP_CHECKSIG]) -def scripthash_to_p2sh_script(hash, main = False): + +def scripthash_to_p2sh_script(hash): assert len(hash) == 20 return CScript([OP_HASH160, hash, OP_EQUAL]) -def key_to_p2pkh_script(key, main = False): + +def key_to_p2pkh_script(key): key = check_key(key) - return keyhash_to_p2pkh_script(hash160(key), main) + return keyhash_to_p2pkh_script(hash160(key)) -def script_to_p2sh_script(script, main = False): + +def script_to_p2sh_script(script): script = check_script(script) - return scripthash_to_p2sh_script(hash160(script), main) + return scripthash_to_p2sh_script(hash160(script)) + -def key_to_p2sh_p2wpkh_script(key, main = False): +def key_to_p2sh_p2wpkh_script(key): key = check_key(key) p2shscript = CScript([OP_0, hash160(key)]) - return script_to_p2sh_script(p2shscript, main) + return script_to_p2sh_script(p2shscript) + -def program_to_witness_script(version, program, main = False): +def program_to_witness_script(version, program): if isinstance(program, str): program = bytes.fromhex(program) assert 0 <= version <= 16 @@ -54,29 +70,34 @@ def program_to_witness_script(version, program, main = False): assert version > 0 or len(program) in [20, 32] return CScript([version, program]) -def script_to_p2wsh_script(script, main = False): + +def script_to_p2wsh_script(script): script = check_script(script) - return program_to_witness_script(0, sha256(script), main) + return program_to_witness_script(0, sha256(script)) + -def key_to_p2wpkh_script(key, main = False): +def key_to_p2wpkh_script(key): key = check_key(key) - return program_to_witness_script(0, hash160(key), main) + return program_to_witness_script(0, hash160(key)) + -def script_to_p2sh_p2wsh_script(script, main = False): +def script_to_p2sh_p2wsh_script(script): script = check_script(script) p2shscript = CScript([OP_0, sha256(script)]) - return script_to_p2sh_script(p2shscript, main) + return script_to_p2sh_script(p2shscript) + def check_key(key): if isinstance(key, str): - key = bytes.fromhex(key) # Assuming this is hex string + key = bytes.fromhex(key) # Assuming this is hex string if isinstance(key, bytes) and (len(key) == 33 or len(key) == 65): return key assert False + def check_script(script): if isinstance(script, str): - script = bytes.fromhex(script) # Assuming this is hex string + script = bytes.fromhex(script) # Assuming this is hex string if isinstance(script, bytes) or isinstance(script, CScript): return script assert False diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index ea5c641b4a..f2637df35b 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -366,7 +366,7 @@ def write_config(config_path, *, n, chain, extra_config="", disable_autoconnect= f.write("listenonion=0\n") # Increase peertimeout to avoid disconnects while using mocktime. # peertimeout is measured in wall clock time, so setting it to the - # duration of the longest test is sufficient. It can be overriden in + # duration of the longest test is sufficient. It can be overridden in # tests. f.write("peertimeout=999999\n") f.write("printtoconsole=0\n") diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index cea59c6d69..ef27cb3221 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -28,6 +28,7 @@ from test_framework.script import ( OP_NOP, SIGHASH_ALL, ) +from test_framework.script_util import key_to_p2wpkh_script from test_framework.util import ( assert_equal, assert_greater_than_or_equal, @@ -146,6 +147,25 @@ class MiniWallet: self.sendrawtransaction(from_node=kwargs['from_node'], tx_hex=tx['hex']) return tx + def send_to(self, *, from_node, scriptPubKey, amount, fee=1000): + """ + Create and send a tx with an output to a given scriptPubKey/amount, + plus a change output to our internal address. To keep things simple, a + fixed fee given in Satoshi is used. + + Note that this method fails if there is no single internal utxo + available that can cover the cost for the amount and the fixed fee + (the utxo with the largest value is taken). + + Returns a tuple (txid, n) referring to the created external utxo outpoint. + """ + tx = self.create_self_transfer(from_node=from_node, fee_rate=0, mempool_valid=False)['tx'] + assert_greater_than_or_equal(tx.vout[0].nValue, amount + fee) + tx.vout[0].nValue -= (amount + fee) # change output -> MiniWallet + tx.vout.append(CTxOut(amount, scriptPubKey)) # arbitrary output -> to be returned + txid = self.sendrawtransaction(from_node=from_node, tx_hex=tx.serialize().hex()) + return txid, 1 + def create_self_transfer(self, *, fee_rate=Decimal("0.003"), from_node, utxo_to_spend=None, mempool_valid=True, locktime=0, sequence=0): """Create and return a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed.""" self._utxos = sorted(self._utxos, key=lambda k: k['value']) @@ -188,6 +208,14 @@ class MiniWallet: return txid +def random_p2wpkh(): + """Generate a random P2WPKH scriptPubKey. Can be used when a random destination is needed, + but no compiled wallet is available (e.g. as replacement to the getnewaddress RPC).""" + key = ECKey() + key.generate() + return key_to_p2wpkh_script(key.get_pubkey().get_bytes()) + + def make_chain(node, address, privkeys, parent_txid, parent_value, n=0, parent_locking_script=None, fee=DEFAULT_FEE): """Build a transaction that spends parent_txid.vout[n] and produces one output with amount = parent_value with a fee deducted. diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 6f7f757a3b..bb84962b75 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -176,6 +176,7 @@ BASE_SCRIPTS = [ 'rpc_rawtransaction.py --legacy-wallet', 'rpc_rawtransaction.py --descriptors', 'wallet_groups.py --legacy-wallet', + 'wallet_transactiontime_rescan.py', 'p2p_addrv2_relay.py', 'wallet_groups.py --descriptors', 'p2p_compactblocks_hb.py', @@ -305,7 +306,6 @@ BASE_SCRIPTS = [ 'feature_presegwit_node_upgrade.py', 'feature_settings.py', 'rpc_getdescriptorinfo.py', - 'rpc_addresses_deprecation.py', 'rpc_help.py', 'feature_help.py', 'feature_shutdown.py', diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index f57f2a44bd..599e506f98 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -582,23 +582,17 @@ class WalletTest(BitcoinTestFramework): assert label in self.nodes[0].listlabels() self.nodes[0].rpc.ensure_ascii = True # restore to default - # maintenance tests - maintenance = [ - '-rescan', - '-reindex', - ] + # -reindex tests chainlimit = 6 - for m in maintenance: - self.log.info("Test " + m) - self.stop_nodes() - # set lower ancestor limit for later - self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)]) - self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)]) - self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)]) - if m == '-reindex': - # reindex will leave rpc warm up "early"; Wait for it to finish - self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) - assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) + self.log.info("Test -reindex") + self.stop_nodes() + # set lower ancestor limit for later + self.start_node(0, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) + self.start_node(1, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) + self.start_node(2, ['-reindex', "-limitancestorcount=" + str(chainlimit)]) + # reindex will leave rpc warm up "early"; Wait for it to finish + self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) + assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) # Exercise listsinceblock with the last two blocks coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index 74f584f2cd..974ce7f381 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -103,7 +103,7 @@ class WalletHDTest(BitcoinTestFramework): self.sync_all() # Needs rescan - self.restart_node(1, extra_args=self.extra_args[1] + ['-rescan']) + self.nodes[1].rescanblockchain() assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) # Try a RPC based rescan diff --git a/test/functional/wallet_transactiontime_rescan.py b/test/functional/wallet_transactiontime_rescan.py new file mode 100755 index 0000000000..78859e6131 --- /dev/null +++ b/test/functional/wallet_transactiontime_rescan.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +# Copyright (c) 2018-2019 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 transaction time during old block rescanning +""" + +import time + +from test_framework.blocktools import COINBASE_MATURITY +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal +) + + +class TransactionTimeRescanTest(BitcoinTestFramework): + def set_test_params(self): + self.setup_clean_chain = False + self.num_nodes = 3 + + def skip_test_if_missing_module(self): + self.skip_if_no_wallet() + + def run_test(self): + self.log.info('Prepare nodes and wallet') + + minernode = self.nodes[0] # node used to mine BTC and create transactions + usernode = self.nodes[1] # user node with correct time + restorenode = self.nodes[2] # node used to restore user wallet and check time determination in ComputeSmartTime (wallet.cpp) + + # time constant + cur_time = int(time.time()) + ten_days = 10 * 24 * 60 * 60 + + # synchronize nodes and time + self.sync_all() + minernode.setmocktime(cur_time) + usernode.setmocktime(cur_time) + restorenode.setmocktime(cur_time) + + # prepare miner wallet + minernode.createwallet(wallet_name='default') + miner_wallet = minernode.get_wallet_rpc('default') + m1 = miner_wallet.getnewaddress() + + # prepare the user wallet with 3 watch only addresses + wo1 = usernode.getnewaddress() + wo2 = usernode.getnewaddress() + wo3 = usernode.getnewaddress() + + usernode.createwallet(wallet_name='wo', disable_private_keys=True) + wo_wallet = usernode.get_wallet_rpc('wo') + + wo_wallet.importaddress(wo1) + wo_wallet.importaddress(wo2) + wo_wallet.importaddress(wo3) + + self.log.info('Start transactions') + + # check blockcount + assert_equal(minernode.getblockcount(), 200) + + # generate some btc to create transactions and check blockcount + initial_mine = COINBASE_MATURITY + 1 + minernode.generatetoaddress(initial_mine, m1) + assert_equal(minernode.getblockcount(), initial_mine + 200) + + # synchronize nodes and time + self.sync_all() + minernode.setmocktime(cur_time + ten_days) + usernode.setmocktime(cur_time + ten_days) + restorenode.setmocktime(cur_time + ten_days) + # send 10 btc to user's first watch-only address + self.log.info('Send 10 btc to user') + miner_wallet.sendtoaddress(wo1, 10) + + # generate blocks and check blockcount + minernode.generatetoaddress(COINBASE_MATURITY, m1) + assert_equal(minernode.getblockcount(), initial_mine + 300) + + # synchronize nodes and time + self.sync_all() + minernode.setmocktime(cur_time + ten_days + ten_days) + usernode.setmocktime(cur_time + ten_days + ten_days) + restorenode.setmocktime(cur_time + ten_days + ten_days) + # send 5 btc to our second watch-only address + self.log.info('Send 5 btc to user') + miner_wallet.sendtoaddress(wo2, 5) + + # generate blocks and check blockcount + minernode.generatetoaddress(COINBASE_MATURITY, m1) + assert_equal(minernode.getblockcount(), initial_mine + 400) + + # synchronize nodes and time + self.sync_all() + minernode.setmocktime(cur_time + ten_days + ten_days + ten_days) + usernode.setmocktime(cur_time + ten_days + ten_days + ten_days) + restorenode.setmocktime(cur_time + ten_days + ten_days + ten_days) + # send 1 btc to our third watch-only address + self.log.info('Send 1 btc to user') + miner_wallet.sendtoaddress(wo3, 1) + + # generate more blocks and check blockcount + minernode.generatetoaddress(COINBASE_MATURITY, m1) + assert_equal(minernode.getblockcount(), initial_mine + 500) + + self.log.info('Check user\'s final balance and transaction count') + assert_equal(wo_wallet.getbalance(), 16) + assert_equal(len(wo_wallet.listtransactions()), 3) + + self.log.info('Check transaction times') + for tx in wo_wallet.listtransactions(): + if tx['address'] == wo1: + assert_equal(tx['blocktime'], cur_time + ten_days) + assert_equal(tx['time'], cur_time + ten_days) + elif tx['address'] == wo2: + assert_equal(tx['blocktime'], cur_time + ten_days + ten_days) + assert_equal(tx['time'], cur_time + ten_days + ten_days) + elif tx['address'] == wo3: + assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days) + assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days) + + # restore user wallet without rescan + self.log.info('Restore user wallet on another node without rescan') + restorenode.createwallet(wallet_name='wo', disable_private_keys=True) + restorewo_wallet = restorenode.get_wallet_rpc('wo') + + restorewo_wallet.importaddress(wo1, rescan=False) + restorewo_wallet.importaddress(wo2, rescan=False) + restorewo_wallet.importaddress(wo3, rescan=False) + + # check user has 0 balance and no transactions + assert_equal(restorewo_wallet.getbalance(), 0) + assert_equal(len(restorewo_wallet.listtransactions()), 0) + + # proceed to rescan, first with an incomplete one, then with a full rescan + self.log.info('Rescan last history part') + restorewo_wallet.rescanblockchain(initial_mine + 350) + self.log.info('Rescan all history') + restorewo_wallet.rescanblockchain() + + self.log.info('Check user\'s final balance and transaction count after restoration') + assert_equal(restorewo_wallet.getbalance(), 16) + assert_equal(len(restorewo_wallet.listtransactions()), 3) + + self.log.info('Check transaction times after restoration') + for tx in restorewo_wallet.listtransactions(): + if tx['address'] == wo1: + assert_equal(tx['blocktime'], cur_time + ten_days) + assert_equal(tx['time'], cur_time + ten_days) + elif tx['address'] == wo2: + assert_equal(tx['blocktime'], cur_time + ten_days + ten_days) + assert_equal(tx['time'], cur_time + ten_days + ten_days) + elif tx['address'] == wo3: + assert_equal(tx['blocktime'], cur_time + ten_days + ten_days + ten_days) + assert_equal(tx['time'], cur_time + ten_days + ten_days + ten_days) + + +if __name__ == '__main__': + TransactionTimeRescanTest().main() diff --git a/test/lint/README.md b/test/lint/README.md index 7e06308347..c4d76eac94 100644 --- a/test/lint/README.md +++ b/test/lint/README.md @@ -27,10 +27,10 @@ Usage: test/lint/git-subtree-check.sh [-r] DIR [COMMIT] To do a full check with `-r`, make sure that you have fetched the upstream repository branch in which the subtree is maintained: * for `src/secp256k1`: https://github.com/bitcoin-core/secp256k1.git (branch master) -* for `src/leveldb`: https://github.com/bitcoin-core/leveldb.git (branch bitcoin-fork) -* for `src/univalue`: https://github.com/bitcoin-core/univalue.git (branch master) +* for `src/leveldb`: https://github.com/bitcoin-core/leveldb-subtree.git (branch bitcoin-fork) +* for `src/univalue`: https://github.com/bitcoin-core/univalue-subtree.git (branch master) * for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master) -* for `src/crc32c`: https://github.com/google/crc32c.git (branch master) +* for `src/crc32c`: https://github.com/bitcoin-core/crc32c-subtree.git (branch bitcoin-fork) To do so, add the upstream repository as remote: diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh index d6312270e7..fcc4883d0b 100755 --- a/test/lint/lint-locale-dependence.sh +++ b/test/lint/lint-locale-dependence.sh @@ -47,11 +47,11 @@ KNOWN_VIOLATIONS=( "src/test/dbwrapper_tests.cpp:.*snprintf" "src/test/fuzz/locale.cpp" "src/test/fuzz/parse_numbers.cpp:.*atoi" + "src/test/fuzz/string.cpp" "src/torcontrol.cpp:.*atoi" "src/torcontrol.cpp:.*strtol" "src/util/strencodings.cpp:.*atoi" - "src/util/strencodings.cpp:.*strtol" - "src/util/strencodings.cpp:.*strtoul" + "src/util/strencodings.cpp:.*strtoll" "src/util/strencodings.h:.*atoi" "src/util/system.cpp:.*atoi" ) diff --git a/test/lint/lint-logs.sh b/test/lint/lint-logs.sh index 2fbb4a38e7..d6c53e8ff3 100755 --- a/test/lint/lint-logs.sh +++ b/test/lint/lint-logs.sh @@ -7,7 +7,7 @@ # Check that all logs are terminated with '\n' # # Some logs are continued over multiple lines. They should be explicitly -# commented with \* Continued *\ +# commented with /* Continued */ # # There are some instances of LogPrintf() in comments. Those can be # ignored |