From 3e1c8a6a589e63591be1e028926eaf3966f6a90f Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 24 Apr 2019 10:08:26 -0400 Subject: [PATCH] Merge #16465: test: Test p2sh-witness and bech32 in wallet_import_rescan fa3c6575cac5e3841797980fe60b8368ae579dba lint: Add false positive to python dead code linter (MarcoFalke) fa25668e1c8982548f1c6f94780709c625811469 test: Test p2sh-witness and bech32 in wallet_import_rescan (MarcoFalke) fa79af298917d501cee26370fdf9d44d05133d15 test: Replace fragile "rng" with call to random() (MarcoFalke) fac3dcf7d052586548f2100a0d576618a85741f9 test: Generate one block for each send in wallet_import_rescan (MarcoFalke) Pull request description: This adds test coverage for segwit in the `wallet_import_rescan` test, among other cleanups. ACKs for top commit: jnewbery: ACK fa3c6575cac5e3841797980fe60b8368ae579dba Tree-SHA512: 877741763c62c1bf9d868864a1e3f0699857e8c028e9fcd65c7eeb73600c22cbe97b7b51093737743d9e87bcb991c1fe1086f673e18765aef0fcfe27951402f0 --- test/functional/wallet_import_rescan.py | 57 ++++++++++++++++--------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 550646fa7c..7015a61dcd 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -26,8 +26,10 @@ from test_framework.util import ( ) import collections +from decimal import Decimal import enum import itertools +import random Call = enum.Enum("Call", "single multiaddress multiscript") Data = enum.Enum("Data", "address pub priv") @@ -50,7 +52,7 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): assert_equal(response, None) elif self.call in (Call.multiaddress, Call.multiscript): - response = self.node.importmulti([{ + request = { "scriptPubKey": { "address": self.address["address"] } if self.call == Call.multiaddress else self.address["scriptPubKey"], @@ -59,13 +61,18 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): "keys": [self.key] if self.data == Data.priv else [], "label": self.label, "watchonly": self.data != Data.priv - }], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}) + } + response = self.node.importmulti( + requests=[request], + options={"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)}, + ) assert_equal(response, [{"success": True}]) - def check(self, txid=None, amount=None, confirmations=None): + def check(self, txid=None, amount=None, confirmation_height=None): """Verify that listtransactions/listreceivedbyaddress return expected values.""" txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True) + current_height = self.node.getblockcount() assert_equal(len(txs), self.expected_txs) addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address']) @@ -80,13 +87,13 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")): assert_equal(tx["category"], "receive") assert_equal(tx["label"], self.label) assert_equal(tx["txid"], txid) - assert_equal(tx["confirmations"], confirmations) + assert_equal(tx["confirmations"], 1 + current_height - confirmation_height) assert_equal("trusted" not in tx, True) address, = [ad for ad in addresses if txid in ad["txids"]] assert_equal(address["address"], self.address["address"]) assert_equal(address["amount"], self.expected_balance) - assert_equal(address["confirmations"], confirmations) + assert_equal(address["confirmations"], 1 + current_height - confirmation_height) # Verify the transaction is correctly marked watchonly depending on # whether the transaction pays to an imported public key or # imported private key. The test setup ensures that transaction @@ -114,6 +121,13 @@ IMPORT_NODES = [ImportNode(*fields) for fields in itertools.product((False, True # Rescans start at the earliest block up to 2 hours before the key timestamp. TIMESTAMP_WINDOW = 2 * 60 * 60 +AMOUNT_DUST = 0.00000546 + + +def get_rand_amount(): + r = random.uniform(AMOUNT_DUST, 1) + return Decimal(str(round(r, 8))) + class ImportRescanTest(BitcoinTestFramework): def set_test_params(self): @@ -125,13 +139,13 @@ class ImportRescanTest(BitcoinTestFramework): self.skip_if_no_wallet() def setup_network(self): - extra_args = [[] for _ in range(self.num_nodes)] + self.extra_args = [[] for _ in range(self.num_nodes)] for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: # txindex is enabled by default in Dash and needs to be disabled for import-rescan.py - extra_args[i] += ["-prune=1", "-txindex=0", "-reindex"] + self.extra_args[i] += ["-prune=1", "-txindex=0", "-reindex"] - self.add_nodes(self.num_nodes, extra_args=extra_args) + self.add_nodes(self.num_nodes, extra_args=self.extra_args) # Import keys with pruning disabled self.start_nodes(extra_args=[[]] * self.num_nodes) @@ -149,15 +163,18 @@ class ImportRescanTest(BitcoinTestFramework): variant.label = "label {} {}".format(i, variant) variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label)) variant.key = self.nodes[1].dumpprivkey(variant.address["address"]) - variant.initial_amount = 1 - (i + 1) / 64 + variant.initial_amount = get_rand_amount() variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount) + self.nodes[0].generate(1) # Generate one block for each send + variant.confirmation_height = self.nodes[0].getblockcount() + variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] - # Generate a block containing the initial transactions, then another - # block further in the future (past the rescan window). - self.nodes[0].generate(1) + # Generate a block further in the future (past the rescan window). assert_equal(self.nodes[0].getrawmempool(), []) - timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] - set_node_times(self.nodes, timestamp + TIMESTAMP_WINDOW + 1) + set_node_times( + self.nodes, + self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"] + TIMESTAMP_WINDOW + 1, + ) self.nodes[0].generate(1) self.sync_all() @@ -167,11 +184,11 @@ class ImportRescanTest(BitcoinTestFramework): self.log.info('Run import for variant {}'.format(variant)) expect_rescan = variant.rescan == Rescan.yes variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))] - variant.do_import(timestamp) + variant.do_import(variant.timestamp) if expect_rescan: variant.expected_balance = variant.initial_amount variant.expected_txs = 1 - variant.check(variant.initial_txid, variant.initial_amount, 2) + variant.check(variant.initial_txid, variant.initial_amount, variant.confirmation_height) else: variant.expected_balance = 0 variant.expected_txs = 0 @@ -179,11 +196,11 @@ class ImportRescanTest(BitcoinTestFramework): # Create new transactions sending to each address. for i, variant in enumerate(IMPORT_VARIANTS): - variant.sent_amount = 1 - (2 * i + 1) / 128 + variant.sent_amount = get_rand_amount() variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount) + self.nodes[0].generate(1) # Generate one block for each send + variant.confirmation_height = self.nodes[0].getblockcount() - # Generate a block containing the new transactions. - self.nodes[0].generate(1) assert_equal(self.nodes[0].getrawmempool(), []) self.sync_all() @@ -192,7 +209,7 @@ class ImportRescanTest(BitcoinTestFramework): self.log.info('Run check for variant {}'.format(variant)) variant.expected_balance += variant.sent_amount variant.expected_txs += 1 - variant.check(variant.sent_txid, variant.sent_amount, 1) + variant.check(variant.sent_txid, variant.sent_amount, variant.confirmation_height) for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: self.stop_node(i, expected_stderr='Warning: You are starting with governance validation disabled. This is expected because you are running a pruned node.')