From fc2aa09cf382f024f461e103f2500e95ddb692e5 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 2 Jun 2017 14:30:36 -0400 Subject: [PATCH 01/37] [tests] Introduce TestNode TestNode is a class responsible for all state related to a bitcoind node under test. It stores local state, is responsible for tracking the bitcoind process and delegates unrecognised messages to the RPC connection. This commit changes start_nodes and stop_nodes to start and stop the bitcoind nodes in parallel, making test setup and teardown much faster. Github-Pull: #10711 Rebased-From: 7897338918dac072e788b8ab2919d4559f311bef --- test/functional/blockchain.py | 4 +- test/functional/bumpfee.py | 3 +- test/functional/fundrawtransaction.py | 3 +- test/functional/getblocktemplate_longpoll.py | 2 +- test/functional/keypool.py | 3 +- test/functional/multiwallet.py | 12 +- test/functional/rpcbind_test.py | 4 +- .../test_framework/test_framework.py | 115 ++++++--------- test/functional/test_framework/test_node.py | 134 ++++++++++++++++++ test/functional/test_framework/util.py | 4 +- test/functional/wallet-dump.py | 3 +- test/functional/wallet-encryption.py | 3 +- 12 files changed, 193 insertions(+), 97 deletions(-) create mode 100755 test/functional/test_framework/test_node.py diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index a7034e6bc..0812e1b0d 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -139,13 +139,13 @@ class BlockchainTest(BitcoinTestFramework): self.nodes[0].generate(6) assert_equal(self.nodes[0].getblockcount(), 206) self.log.debug('Node should not stop at this height') - assert_raises(subprocess.TimeoutExpired, lambda: self.bitcoind_processes[0].wait(timeout=3)) + assert_raises(subprocess.TimeoutExpired, lambda: self.nodes[0].process.wait(timeout=3)) try: self.nodes[0].generate(1) except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') - self.bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) self.nodes[0] = self.start_node(0, self.options.tmpdir) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 9237f0924..3c488f609 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -41,8 +41,7 @@ class BumpFeeTest(BitcoinTestFramework): self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) # Encrypt wallet for test_locked_wallet_fails test - self.nodes[1].encryptwallet(WALLET_PASSPHRASE) - self.bitcoind_processes[1].wait() + self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1]) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index e52e77391..f2f4efcf2 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -451,8 +451,7 @@ class RawTransactionsTest(BitcoinTestFramework): self.stop_node(0) self.stop_node(2) self.stop_node(3) - self.nodes[1].encryptwallet("test") - self.bitcoind_processes[1].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[1].node_encrypt_wallet("test") self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) # This test is not meant to test fee estimation and we'd like diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index bbe1dda5f..cca30e268 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -17,7 +17,7 @@ class LongpollThread(threading.Thread): self.longpollid = templat['longpollid'] # create a new connection to the node, we can't use the same # connection from two threads - self.node = get_rpc_proxy(node.url, 1, timeout=600) + self.node = get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir) def run(self): self.node.getblocktemplate({'longpollid':self.longpollid}) diff --git a/test/functional/keypool.py b/test/functional/keypool.py index e8be55991..3e7bb0ee0 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -17,8 +17,7 @@ class KeyPoolTest(BitcoinTestFramework): assert(addr_before_encrypting_data['hdmasterkeyid'] == wallet_info_old['hdmasterkeyid']) # Encrypt wallet and wait to terminate - nodes[0].encryptwallet('test') - self.bitcoind_processes[0].wait() + nodes[0].node_encrypt_wallet('test') # Restart node 0 nodes[0] = self.start_node(0, self.options.tmpdir) # Keep creating keys diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index 5679f4050..fc6e8e325 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -35,11 +35,15 @@ class MultiWalletTest(BitcoinTestFramework): self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) - w1 = self.nodes[0] / "wallet/w1" + w1 = self.nodes[0].get_wallet_rpc("w1") + w2 = self.nodes[0].get_wallet_rpc("w2") + w3 = self.nodes[0].get_wallet_rpc("w3") + wallet_bad = self.nodes[0].get_wallet_rpc("bad") + w1.generate(1) # accessing invalid wallet fails - assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", (self.nodes[0] / "wallet/bad").getwalletinfo) + assert_raises_jsonrpc(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo) # accessing wallet RPC without using wallet endpoint fails assert_raises_jsonrpc(-19, "Wallet file not specified", self.nodes[0].getwalletinfo) @@ -50,14 +54,12 @@ class MultiWalletTest(BitcoinTestFramework): w1_name = w1_info['walletname'] assert_equal(w1_name, "w1") - # check w1 wallet balance - w2 = self.nodes[0] / "wallet/w2" + # check w2 wallet balance w2_info = w2.getwalletinfo() assert_equal(w2_info['immature_balance'], 0) w2_name = w2_info['walletname'] assert_equal(w2_name, "w2") - w3 = self.nodes[0] / "wallet/w3" w3_name = w3.getwalletinfo()['walletname'] assert_equal(w3_name, "w3") diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index 951685aa7..20808207b 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -37,7 +37,7 @@ class RPCBindTest(BitcoinTestFramework): base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind='+addr for addr in addresses] self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to) - pid = self.bitcoind_processes[0].pid + pid = self.nodes[0].process.pid assert_equal(set(get_bind_addrs(pid)), set(expected)) self.stop_nodes() @@ -49,7 +49,7 @@ class RPCBindTest(BitcoinTestFramework): base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) # connect to node through non-loopback interface - node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0) + node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() self.stop_nodes() diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index e562d1193..7903bb004 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -5,15 +5,12 @@ """Base class for RPC testing.""" from collections import deque -import errno from enum import Enum -import http.client import logging import optparse import os import pdb import shutil -import subprocess import sys import tempfile import time @@ -21,6 +18,7 @@ import traceback from .authproxy import JSONRPCException from . import coverage +from .test_node import TestNode from .util import ( MAX_NODES, PortSeed, @@ -28,12 +26,9 @@ from .util import ( check_json_precision, connect_nodes_bi, disconnect_nodes, - get_rpc_proxy, initialize_datadir, - get_datadir_path, log_filename, p2p_port, - rpc_url, set_node_times, sync_blocks, sync_mempools, @@ -70,7 +65,6 @@ class BitcoinTestFramework(object): self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] - self.bitcoind_processes = {} self.mocktime = 0 def add_options(self, parser): @@ -213,64 +207,62 @@ class BitcoinTestFramework(object): def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): """Start a bitcoind and return RPC connection to it""" - datadir = os.path.join(dirname, "node" + str(i)) + if extra_args is None: + extra_args = [] if binary is None: binary = os.getenv("BITCOIND", "bitcoind") - args = [binary, "-datadir=" + datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(self.mocktime), "-uacomment=testnode%d" % i] - if extra_args is not None: - args.extend(extra_args) - self.bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr) - self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") - self._wait_for_bitcoind_start(self.bitcoind_processes[i], datadir, i, rpchost) - self.log.debug("initialize_chain: RPC successfully started") - proxy = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, timeout=timewait) + node = TestNode(i, dirname, extra_args, rpchost, timewait, binary, stderr, self.mocktime, coverage_dir=self.options.coveragedir) + node.start() + node.wait_for_rpc_connection() - if self.options.coveragedir: - coverage.write_all_rpc_commands(self.options.coveragedir, proxy) + if self.options.coveragedir is not None: + coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - return proxy + return node def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): """Start multiple bitcoinds, return RPC connections to them""" if extra_args is None: - extra_args = [None] * num_nodes + extra_args = [[]] * num_nodes if binary is None: binary = [None] * num_nodes assert_equal(len(extra_args), num_nodes) assert_equal(len(binary), num_nodes) - rpcs = [] + nodes = [] try: for i in range(num_nodes): - rpcs.append(self.start_node(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i])) + nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + nodes[i].start() + for node in nodes: + node.wait_for_rpc_connection() except: # If one node failed to start, stop the others - # TODO: abusing self.nodes in this way is a little hacky. - # Eventually we should do a better job of tracking nodes - self.nodes.extend(rpcs) self.stop_nodes() - self.nodes = [] raise - return rpcs + + if self.options.coveragedir is not None: + for node in nodes: + coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) + + return nodes def stop_node(self, i): """Stop a bitcoind test node""" - - self.log.debug("Stopping node %d" % i) - try: - self.nodes[i].stop() - except http.client.CannotSendRequest as e: - self.log.exception("Unable to stop node") - return_code = self.bitcoind_processes[i].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) - del self.bitcoind_processes[i] - assert_equal(return_code, 0) + self.nodes[i].stop_node() + while not self.nodes[i].is_node_stopped(): + time.sleep(0.1) def stop_nodes(self): """Stop multiple bitcoind test nodes""" + for node in self.nodes: + # Issue RPC to stop nodes + node.stop_node() - for i in range(len(self.nodes)): - self.stop_node(i) - assert not self.bitcoind_processes.values() # All connections must be gone now + for node in self.nodes: + # Wait for nodes to stop + while not node.is_node_stopped(): + time.sleep(0.1) def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: @@ -279,6 +271,8 @@ class BitcoinTestFramework(object): self.stop_node(i) except Exception as e: assert 'bitcoind exited' in str(e) # node must have shutdown + self.nodes[i].running = False + self.nodes[i].process = None if expected_msg is not None: log_stderr.seek(0) stderr = log_stderr.read().decode('utf-8') @@ -292,7 +286,7 @@ class BitcoinTestFramework(object): raise AssertionError(assert_msg) def wait_for_node_exit(self, i, timeout): - self.bitcoind_processes[i].wait(timeout) + self.nodes[i].process.wait(timeout) def split_network(self): """ @@ -389,18 +383,13 @@ class BitcoinTestFramework(object): args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] if i > 0: args.append("-connect=127.0.0.1:" + str(p2p_port(0))) - self.bitcoind_processes[i] = subprocess.Popen(args) - self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") - self._wait_for_bitcoind_start(self.bitcoind_processes[i], datadir, i) - self.log.debug("initialize_chain: RPC successfully started") + self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) + self.nodes[i].args = args + self.nodes[i].start() - self.nodes = [] - for i in range(MAX_NODES): - try: - self.nodes.append(get_rpc_proxy(rpc_url(get_datadir_path(cachedir, i), i), i)) - except: - self.log.exception("Error connecting to node %d" % i) - sys.exit(1) + # Wait for RPC connections to be ready + for node in self.nodes: + node.wait_for_rpc_connection() # Create a 200-block-long chain; each of the 4 first nodes # gets 25 mature blocks and 25 immature. @@ -444,30 +433,6 @@ class BitcoinTestFramework(object): for i in range(num_nodes): initialize_datadir(test_dir, i) - def _wait_for_bitcoind_start(self, process, datadir, i, rpchost=None): - """Wait for bitcoind to start. - - This means that RPC is accessible and fully initialized. - Raise an exception if bitcoind exits during initialization.""" - while True: - if process.poll() is not None: - raise Exception('bitcoind exited with status %i during initialization' % process.returncode) - try: - # Check if .cookie file to be created - rpc = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, coveragedir=self.options.coveragedir) - rpc.getblockcount() - break # break out of loop on success - except IOError as e: - if e.errno != errno.ECONNREFUSED: # Port not yet open? - raise # unknown IO error - except JSONRPCException as e: # Initialization phase - if e.error['code'] != -28: # RPC in warmup? - raise # unknown JSON RPC exception - except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting - if "No RPC credentials" not in str(e): - raise - time.sleep(0.25) - class ComparisonTestFramework(BitcoinTestFramework): """Test framework for doing p2p comparison testing diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py new file mode 100755 index 000000000..66f89d43f --- /dev/null +++ b/test/functional/test_framework/test_node.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Class for bitcoind node under test""" + +import errno +import http.client +import logging +import os +import subprocess +import time + +from .util import ( + assert_equal, + get_rpc_proxy, + rpc_url, +) +from .authproxy import JSONRPCException + +class TestNode(): + """A class for representing a bitcoind node under test. + + This class contains: + + - state about the node (whether it's running, etc) + - a Python subprocess.Popen object representing the running process + - an RPC connection to the node + + To make things easier for the test writer, a bit of magic is happening under the covers. + Any unrecognised messages will be dispatched to the RPC connection.""" + + def __init__(self, i, dirname, extra_args, rpchost, timewait, binary, stderr, mocktime, coverage_dir): + self.index = i + self.datadir = os.path.join(dirname, "node" + str(i)) + self.rpchost = rpchost + self.rpc_timeout = timewait + if binary is None: + self.binary = os.getenv("BITCOIND", "bitcoind") + else: + self.binary = binary + self.stderr = stderr + self.coverage_dir = coverage_dir + # Most callers will just need to add extra args to the standard list below. For those callers that need more flexibity, they can just set the args property directly. + self.extra_args = extra_args + self.args = [self.binary, "-datadir=" + self.datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i] + + self.running = False + self.process = None + self.rpc_connected = False + self.rpc = None + self.url = None + self.log = logging.getLogger('TestFramework.node%d' % i) + + def __getattr__(self, *args, **kwargs): + """Dispatches any unrecognised messages to the RPC connection.""" + assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection" + return self.rpc.__getattr__(*args, **kwargs) + + def start(self): + """Start the node.""" + self.process = subprocess.Popen(self.args + self.extra_args, stderr=self.stderr) + self.running = True + self.log.debug("bitcoind started, waiting for RPC to come up") + + def wait_for_rpc_connection(self): + """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" + + # Wait for up to 10 seconds for the RPC server to respond + for _ in range(40): + assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode + try: + self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) + self.rpc.getblockcount() + # If the call to getblockcount() succeeds then the RPC connection is up + self.rpc_connected = True + self.url = self.rpc.url + self.log.debug("RPC successfully started") + return + except IOError as e: + if e.errno != errno.ECONNREFUSED: # Port not yet open? + raise # unknown IO error + except JSONRPCException as e: # Initialization phase + if e.error['code'] != -28: # RPC in warmup? + raise # unknown JSON RPC exception + except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting + if "No RPC credentials" not in str(e): + raise + time.sleep(0.25) + raise AssertionError("Unable to connect to bitcoind") + + def get_wallet_rpc(self, wallet_name): + assert self.rpc_connected + assert self.rpc + wallet_path = "wallet/%s" % wallet_name + return self.rpc / wallet_path + + def stop_node(self): + """Stop the node.""" + if not self.running: + return + self.log.debug("Stopping node") + try: + self.stop() + except http.client.CannotSendRequest: + self.log.exception("Unable to stop node.") + + def is_node_stopped(self): + """Checks whether the node has stopped. + + Returns True if the node has stopped. False otherwise. + This method is responsible for freeing resources (self.process).""" + if not self.running: + return True + return_code = self.process.poll() + if return_code is not None: + # process has stopped. Assert that it didn't return an error code. + assert_equal(return_code, 0) + self.running = False + self.process = None + self.log.debug("Node stopped") + return True + return False + + def node_encrypt_wallet(self, passphrase): + """"Encrypts the wallet. + + This causes bitcoind to shutdown, so this method takes + care of cleaning up resources.""" + self.encryptwallet(passphrase) + while not self.is_node_stopped(): + time.sleep(0.1) + self.rpc = None + self.rpc_connected = False diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index acca72aa8..4098fd861 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -204,7 +204,7 @@ def rpc_port(n): return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES) def rpc_url(datadir, i, rpchost=None): - rpc_u, rpc_p = get_auth_cookie(datadir, i) + rpc_u, rpc_p = get_auth_cookie(datadir) host = '127.0.0.1' port = rpc_port(i) if rpchost: @@ -232,7 +232,7 @@ def initialize_datadir(dirname, n): def get_datadir_path(dirname, n): return os.path.join(dirname, "node" + str(n)) -def get_auth_cookie(datadir, n): +def get_auth_cookie(datadir): user = None password = None if os.path.isfile(os.path.join(datadir, "bitcoin.conf")): diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index 569cc46e6..61ad00330 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -94,8 +94,7 @@ class WalletDumpTest(BitcoinTestFramework): assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys #encrypt wallet, restart, unlock and dump - self.nodes[0].encryptwallet('test') - self.bitcoind_processes[0].wait() + self.nodes[0].node_encrypt_wallet('test') self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index ba72918fe..8fea4140d 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -30,8 +30,7 @@ class WalletEncryptionTest(BitcoinTestFramework): assert_equal(len(privkey), 52) # Encrypt the wallet - self.nodes[0].encryptwallet(passphrase) - self.bitcoind_processes[0].wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].node_encrypt_wallet(passphrase) self.nodes[0] = self.start_node(0, self.options.tmpdir) # Test that the wallet is encrypted From c276c1e1d1fb18771d9efabaf5a476d29c901d5d Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 18 Aug 2017 22:09:58 +0200 Subject: [PATCH 02/37] test: Increase initial RPC timeout to 60 seconds When running the tests locally with a parallelism of 4 on an otherwise busy system, RPC can take quite a wait to come up. Change the timeout to 60 seconds just to be safe. Github-Pull: #11091 Rebased-From: c1470a058f21bf98d83b9dc345c61626b87035cc --- test/functional/test_framework/test_node.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 66f89d43f..4b5dc9a79 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -65,9 +65,9 @@ class TestNode(): def wait_for_rpc_connection(self): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" - - # Wait for up to 10 seconds for the RPC server to respond - for _ in range(40): + timeout_s = 60 # Wait for up to 60 seconds for the RPC server to respond + poll_per_s = 4 # Poll at a rate of four times per second + for _ in range(timeout_s*poll_per_s): assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode try: self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) @@ -86,7 +86,7 @@ class TestNode(): except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting if "No RPC credentials" not in str(e): raise - time.sleep(0.25) + time.sleep(1.0 / poll_per_s) raise AssertionError("Unable to connect to bitcoind") def get_wallet_rpc(self, wallet_name): From 1d80d1e319b41e5187d5949b3c22c35df182ba3c Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 16 Aug 2017 15:46:48 -0400 Subject: [PATCH 03/37] [tests] fix timeout issues from TestNode Fixes a couple of bugs from the introduction of TestNode: - test scripts were no longer able to specify a custom timeout for starting a node. Therefore tests with nodes that take a long time to start up (eg pruning.py) would fail. - the test for whether a node has failed on start up was broken by changing 'assert x is None' to 'assert not x'. Since subprocess.poll() can return None (indicating the node is still running) or 0 (indicating the node exited with return code 0), this was a regression. Github-Pull: #11077 Rebased-From: 2b4ea520b717b3ca894adbac17796786667764d3 --- test/functional/dbcrash.py | 7 ++++--- test/functional/test_framework/test_node.py | 14 +++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index 8339305f5..a7fcc411c 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -64,7 +64,8 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args] def setup_network(self): - self.setup_nodes() + # Need a bit of extra time for the nodes to start up for this test + self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) # Leave them unconnected, we'll use submitblock directly in this test def restart_node(self, node_index, expected_tip): @@ -74,10 +75,10 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): after 60 seconds. Returns the utxo hash of the given node.""" time_start = time.time() - while time.time() - time_start < 60: + while time.time() - time_start < 120: try: # Any of these RPC calls could throw due to node crash - self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index]) + self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index], timewait=90) self.nodes[node_index].waitforblock(expected_tip) utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2'] return utxo_hash diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 4b5dc9a79..a803df5b4 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -34,7 +34,11 @@ class TestNode(): self.index = i self.datadir = os.path.join(dirname, "node" + str(i)) self.rpchost = rpchost - self.rpc_timeout = timewait + if timewait: + self.rpc_timeout = timewait + else: + # Wait for up to 60 seconds for the RPC server to respond + self.rpc_timeout = 60 if binary is None: self.binary = os.getenv("BITCOIND", "bitcoind") else: @@ -65,10 +69,10 @@ class TestNode(): def wait_for_rpc_connection(self): """Sets up an RPC connection to the bitcoind process. Returns False if unable to connect.""" - timeout_s = 60 # Wait for up to 60 seconds for the RPC server to respond - poll_per_s = 4 # Poll at a rate of four times per second - for _ in range(timeout_s*poll_per_s): - assert not self.process.poll(), "bitcoind exited with status %i during initialization" % self.process.returncode + # Poll at a rate of four times per second + poll_per_s = 4 + for _ in range(poll_per_s * self.rpc_timeout): + assert self.process.poll() is None, "bitcoind exited with status %i during initialization" % self.process.returncode try: self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) self.rpc.getblockcount() From 5398f205e3ba1f7542deeba420f9e198bcb635f5 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 16 Aug 2017 18:17:34 +0200 Subject: [PATCH 04/37] qa: Move wait_until to util Github-Pull: #11068 Rebased-From: 08ce33f8e95efa81b37ddc6b3350462c61bbfd51 --- test/functional/bip65-cltv-p2p.py | 4 +- test/functional/bipdersig-p2p.py | 4 +- test/functional/disconnect_ban.py | 16 ++++---- test/functional/example_test.py | 4 +- test/functional/mempool_persist.py | 5 +-- test/functional/p2p-compactblocks.py | 47 ++++++++-------------- test/functional/p2p-leaktests.py | 14 +++---- test/functional/sendheaders.py | 6 +-- test/functional/test_framework/comptool.py | 12 +++--- test/functional/test_framework/mininode.py | 33 ++++----------- test/functional/test_framework/util.py | 22 ++++++++++ 11 files changed, 78 insertions(+), 89 deletions(-) diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index 7e5e4cf68..65ae8de55 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -109,7 +109,7 @@ class BIP65Test(BitcoinTestFramework): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until(lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000003)') @@ -138,7 +138,7 @@ class BIP65Test(BitcoinTestFramework): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until (lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert node0.last_message["reject"].code in [REJECT_INVALID, REJECT_NONSTANDARD] assert_equal(node0.last_message["reject"].data, block.sha256) diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index 38a900954..977597089 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -98,7 +98,7 @@ class BIP66Test(BitcoinTestFramework): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until(lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: assert_equal(node0.last_message["reject"].code, REJECT_OBSOLETE) assert_equal(node0.last_message["reject"].reason, b'bad-version(0x00000002)') @@ -128,7 +128,7 @@ class BIP66Test(BitcoinTestFramework): node0.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - assert wait_until (lambda: "reject" in node0.last_message.keys()) + wait_until(lambda: "reject" in node0.last_message.keys(), lock=mininode_lock) with mininode_lock: # We can receive different reject messages depending on whether # bitcoind is running with multiple script check threads. If script diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index 89b68aeb2..19723226d 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -5,11 +5,13 @@ """Test node disconnect and ban behavior""" import time -from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, - assert_raises_jsonrpc, - connect_nodes_bi) +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + connect_nodes_bi, + wait_until, +) class DisconnectBanTest(BitcoinTestFramework): @@ -24,7 +26,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("setban: successfully ban single IP address") assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban("127.0.0.1", "add") - assert wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) + wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) @@ -90,7 +92,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("disconnectnode: successfully disconnect node by address") address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) - assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] self.log.info("disconnectnode: successfully reconnect node") @@ -101,7 +103,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("disconnectnode: successfully disconnect node by node id") id1 = self.nodes[0].getpeerinfo()[0]['id'] self.nodes[0].disconnectnode(nodeid=id1) - assert wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] if __name__ == '__main__': diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 7709524f2..a54b5278e 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -23,13 +23,13 @@ from test_framework.mininode import ( mininode_lock, msg_block, msg_getdata, - wait_until, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes, p2p_port, + wait_until, ) # NodeConnCB is a class containing callbacks to be executed when a P2P @@ -209,7 +209,7 @@ class ExampleTest(BitcoinTestFramework): # wait_until() will loop until a predicate condition is met. Use it to test properties of the # NodeConnCB objects. - assert wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5) + wait_until(lambda: sorted(blocks) == sorted(list(node2.block_receive_map.keys())), timeout=5, lock=mininode_lock) self.log.info("Check that each block was received only once") # The network thread uses a global lock on data access to the NodeConn objects when sending and receiving diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index e0889fd5e..807edeb7a 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -32,7 +32,6 @@ Test is as follows: """ import time -from test_framework.mininode import wait_until from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -69,7 +68,7 @@ class MempoolPersistTest(BitcoinTestFramework): self.nodes.append(self.start_node(1, self.options.tmpdir)) # Give bitcoind a second to reload the mempool time.sleep(1) - assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) + wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) assert_equal(len(self.nodes[1].getrawmempool()), 0) self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") @@ -84,7 +83,7 @@ class MempoolPersistTest(BitcoinTestFramework): self.stop_nodes() self.nodes = [] self.nodes.append(self.start_node(0, self.options.tmpdir)) - assert wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) + wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) if __name__ == '__main__': MempoolPersistTest().main() diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index ff76e49fb..c5c264765 100755 --- a/test/functional/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -70,7 +70,7 @@ class TestNode(NodeConnCB): def request_headers_and_sync(self, locator, hashstop=0): self.clear_block_announcement() self.get_headers(locator, hashstop) - assert wait_until(self.received_block_announcement, timeout=30) + wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock) self.clear_block_announcement() # Block until a block announcement for a particular block hash is @@ -78,7 +78,7 @@ class TestNode(NodeConnCB): def wait_for_block_announcement(self, block_hash, timeout=30): def received_hash(): return (block_hash in self.announced_blockhashes) - return wait_until(received_hash, timeout=timeout) + wait_until(received_hash, timeout=timeout, lock=mininode_lock) def send_await_disconnect(self, message, timeout=30): """Sends a message to the node and wait for disconnect. @@ -86,11 +86,7 @@ class TestNode(NodeConnCB): This is used when we want to send a message into the node that we expect will get us disconnected, eg an invalid block.""" self.send_message(message) - success = wait_until(lambda: not self.connected, timeout=timeout) - if not success: - logger.error("send_await_disconnect failed!") - raise AssertionError("send_await_disconnect failed!") - return success + wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock) class CompactBlocksTest(BitcoinTestFramework): def __init__(self): @@ -150,9 +146,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Make sure we get a SENDCMPCT message from our peer def received_sendcmpct(): return (len(test_node.last_sendcmpct) > 0) - got_message = wait_until(received_sendcmpct, timeout=30) - assert(received_sendcmpct()) - assert(got_message) + wait_until(received_sendcmpct, timeout=30, lock=mininode_lock) with mininode_lock: # Check that the first version received is the preferred one assert_equal(test_node.last_sendcmpct[0].version, preferred_version) @@ -167,7 +161,6 @@ class CompactBlocksTest(BitcoinTestFramework): block_hash = int(node.generate(1)[0], 16) peer.wait_for_block_announcement(block_hash, timeout=30) assert(peer.block_announced) - assert(got_message) with mininode_lock: assert predicate(peer), ( @@ -282,7 +275,7 @@ class CompactBlocksTest(BitcoinTestFramework): # Wait until we've seen the block announcement for the resulting tip tip = int(node.getbestblockhash(), 16) - assert(test_node.wait_for_block_announcement(tip)) + test_node.wait_for_block_announcement(tip) # Make sure we will receive a fast-announce compact block self.request_cb_announcements(test_node, node, version) @@ -297,8 +290,7 @@ class CompactBlocksTest(BitcoinTestFramework): block.rehash() # Wait until the block was announced (via compact blocks) - wait_until(test_node.received_block_announcement, timeout=30) - assert(test_node.received_block_announcement()) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) # Now fetch and check the compact block header_and_shortids = None @@ -314,8 +306,7 @@ class CompactBlocksTest(BitcoinTestFramework): inv = CInv(4, block_hash) # 4 == "CompactBlock" test_node.send_message(msg_getdata([inv])) - wait_until(test_node.received_block_announcement, timeout=30) - assert(test_node.received_block_announcement()) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) # Now fetch and check the compact block header_and_shortids = None @@ -386,13 +377,11 @@ class CompactBlocksTest(BitcoinTestFramework): if announce == "inv": test_node.send_message(msg_inv([CInv(2, block.sha256)])) - success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock) test_node.send_header_for_blocks([block]) else: test_node.send_header_for_blocks([block]) - success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "getdata" in test_node.last_message, timeout=30, lock=mininode_lock) assert_equal(len(test_node.last_message["getdata"].inv), 1) assert_equal(test_node.last_message["getdata"].inv[0].type, 4) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) @@ -571,8 +560,7 @@ class CompactBlocksTest(BitcoinTestFramework): assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) # We should receive a getdata request - success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10) - assert(success) + wait_until(lambda: "getdata" in test_node.last_message, timeout=10, lock=mininode_lock) assert_equal(len(test_node.last_message["getdata"].inv), 1) assert(test_node.last_message["getdata"].inv[0].type == 2 or test_node.last_message["getdata"].inv[0].type == 2|MSG_WITNESS_FLAG) assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256) @@ -599,8 +587,7 @@ class CompactBlocksTest(BitcoinTestFramework): num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request))) test_node.send_message(msg) - success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) - assert(success) + wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock) [tx.calc_sha256() for tx in block.vtx] with mininode_lock: @@ -639,22 +626,20 @@ class CompactBlocksTest(BitcoinTestFramework): for i in range(MAX_CMPCTBLOCK_DEPTH + 1): test_node.clear_block_announcement() new_blocks.append(node.generate(1)[0]) - wait_until(test_node.received_block_announcement, timeout=30) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) - success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() node.generate(1) - wait_until(test_node.received_block_announcement, timeout=30) + wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) test_node.clear_block_announcement() with mininode_lock: test_node.last_message.pop("block", None) test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) - success = wait_until(lambda: "block" in test_node.last_message, timeout=30) - assert(success) + wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock) with mininode_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) @@ -705,7 +690,7 @@ class CompactBlocksTest(BitcoinTestFramework): node.submitblock(ToHex(block)) for l in listeners: - wait_until(lambda: l.received_block_announcement(), timeout=30) + wait_until(lambda: l.received_block_announcement(), timeout=30, lock=mininode_lock) with mininode_lock: for l in listeners: assert "cmpctblock" in l.last_message diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index 5611c876a..f0d4d9a8b 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -119,11 +119,11 @@ class P2PLeakTest(BitcoinTestFramework): NetworkThread().start() # Start up network handling in another thread - assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10) - assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10) - assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10) - assert wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10) - assert wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10) + wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock) + wait_until(lambda: unsupported_service_bit5_node.ever_connected, timeout=10, lock=mininode_lock) + wait_until(lambda: unsupported_service_bit7_node.ever_connected, timeout=10, lock=mininode_lock) # Mine a block and make sure that it's not sent to the connected nodes self.nodes[0].generate(1) @@ -158,8 +158,8 @@ class P2PLeakTest(BitcoinTestFramework): allowed_service_bit5_node.add_connection(connections[5]) allowed_service_bit7_node.add_connection(connections[6]) - assert wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10) - assert wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10) + wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock) + wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index e47e07fb8..6451b097c 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -128,7 +128,7 @@ class TestNode(NodeConnCB): expect_headers = headers if headers != None else [] expect_inv = inv if inv != None else [] test_function = lambda: self.block_announced - assert(wait_until(test_function, timeout=60)) + wait_until(test_function, timeout=60, lock=mininode_lock) with mininode_lock: self.block_announced = False @@ -155,12 +155,12 @@ class TestNode(NodeConnCB): return test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list - assert(wait_until(test_function, timeout=timeout)) + wait_until(test_function, timeout=timeout, lock=mininode_lock) return def wait_for_block_announcement(self, block_hash, timeout=60): test_function = lambda: self.last_blockhash_announced == block_hash - assert(wait_until(test_function, timeout=timeout)) + wait_until(test_function, timeout=timeout, lock=mininode_lock) return def send_header_for_blocks(self, new_blocks): diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py index 9f062865a..bfbc0c3b0 100755 --- a/test/functional/test_framework/comptool.py +++ b/test/functional/test_framework/comptool.py @@ -19,7 +19,7 @@ TestNode behaves as follows: from .mininode import * from .blockstore import BlockStore, TxStore -from .util import p2p_port +from .util import p2p_port, wait_until import logging @@ -189,7 +189,7 @@ class TestManager(object): def wait_for_disconnections(self): def disconnected(): return all(node.closed for node in self.test_nodes) - return wait_until(disconnected, timeout=10) + wait_until(disconnected, timeout=10, lock=mininode_lock) def wait_for_verack(self): return all(node.wait_for_verack() for node in self.test_nodes) @@ -197,7 +197,7 @@ class TestManager(object): def wait_for_pings(self, counter): def received_pongs(): return all(node.received_ping_response(counter) for node in self.test_nodes) - return wait_until(received_pongs) + wait_until(received_pongs, lock=mininode_lock) # sync_blocks: Wait for all connections to request the blockhash given # then send get_headers to find out the tip of each node, and synchronize @@ -210,8 +210,7 @@ class TestManager(object): ) # --> error if not requested - if not wait_until(blocks_requested, attempts=20*num_blocks): - raise AssertionError("Not all nodes requested block") + wait_until(blocks_requested, attempts=20*num_blocks, lock=mininode_lock) # Send getheaders message [ c.cb.send_getheaders() for c in self.connections ] @@ -231,8 +230,7 @@ class TestManager(object): ) # --> error if not requested - if not wait_until(transaction_requested, attempts=20*num_events): - raise AssertionError("Not all nodes requested transaction") + wait_until(transaction_requested, attempts=20*num_events, lock=mininode_lock) # Get the mempool [ c.cb.send_mempool() for c in self.connections ] diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index a4d85501e..d0753276d 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -35,7 +35,7 @@ import time from threading import RLock, Thread from test_framework.siphash import siphash256 -from test_framework.util import hex_str_to_bytes, bytes_to_hex_str +from test_framework.util import hex_str_to_bytes, bytes_to_hex_str, wait_until BIP0031_VERSION = 60000 MY_VERSION = 70014 # past bip-31 for ping/pong @@ -1358,23 +1358,6 @@ class msg_reject(object): return "msg_reject: %s %d %s [%064x]" \ % (self.message, self.code, self.reason, self.data) -# Helper function -def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf')): - if attempts == float('inf') and timeout == float('inf'): - timeout = 60 - attempt = 0 - elapsed = 0 - - while attempt < attempts and elapsed < timeout: - with mininode_lock: - if predicate(): - return True - attempt += 1 - elapsed += 0.05 - time.sleep(0.05) - - return False - class msg_feefilter(object): command = b"feefilter" @@ -1591,21 +1574,21 @@ class NodeConnCB(object): def wait_for_disconnect(self, timeout=60): test_function = lambda: not self.connected - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) # Message receiving helper methods def wait_for_block(self, blockhash, timeout=60): test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_getdata(self, timeout=60): test_function = lambda: self.last_message.get("getdata") - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_getheaders(self, timeout=60): test_function = lambda: self.last_message.get("getheaders") - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_inv(self, expected_inv, timeout=60): """Waits for an INV message and checks that the first inv object in the message was as expected.""" @@ -1614,11 +1597,11 @@ class NodeConnCB(object): test_function = lambda: self.last_message.get("inv") and \ self.last_message["inv"].inv[0].type == expected_inv[0].type and \ self.last_message["inv"].inv[0].hash == expected_inv[0].hash - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) def wait_for_verack(self, timeout=60): test_function = lambda: self.message_count["verack"] - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) # Message sending helper functions @@ -1636,7 +1619,7 @@ class NodeConnCB(object): def sync_with_ping(self, timeout=60): self.send_message(msg_ping(nonce=self.ping_counter)) test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter - assert wait_until(test_function, timeout=timeout) + wait_until(test_function, timeout=timeout, lock=mininode_lock) self.ping_counter += 1 return True diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 4098fd861..a14cda07d 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -157,6 +157,28 @@ def str_to_b64str(string): def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) +def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None): + if attempts == float('inf') and timeout == float('inf'): + timeout = 60 + attempt = 0 + timeout += time.time() + + while attempt < attempts and time.time() < timeout: + if lock: + with lock: + if predicate(): + return + else: + if predicate(): + return + attempt += 1 + time.sleep(0.05) + + # Print the cause of the timeout + assert_greater_than(attempts, attempt) + assert_greater_than(timeout, time.time()) + raise RuntimeError('Unreachable') + # RPC/P2P connection constants and functions ############################################ From 016b9ada2111aaf41f3336c0179a1347355bc9e6 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 11 Jul 2017 13:01:44 -0400 Subject: [PATCH 05/37] [tests] add TestNodeCLI class for calling bitcoin-cli for a node Github-Pull: #10798 Rebased-From: b23549f6e677a8e22953568704eac7ea0c2c1289 --- test/functional/test_framework/test_node.py | 29 +++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 30 insertions(+) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index a803df5b4..7c1325e69 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -4,8 +4,10 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Class for bitcoind node under test""" +import decimal import errno import http.client +import json import logging import os import subprocess @@ -49,6 +51,8 @@ class TestNode(): self.extra_args = extra_args self.args = [self.binary, "-datadir=" + self.datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(mocktime), "-uacomment=testnode%d" % i] + self.cli = TestNodeCLI(os.getenv("BITCOINCLI", "bitcoin-cli"), self.datadir) + self.running = False self.process = None self.rpc_connected = False @@ -136,3 +140,28 @@ class TestNode(): time.sleep(0.1) self.rpc = None self.rpc_connected = False + +class TestNodeCLI(): + """Interface to bitcoin-cli for an individual node""" + + def __init__(self, binary, datadir): + self.binary = binary + self.datadir = datadir + + def __getattr__(self, command): + def dispatcher(*args, **kwargs): + return self.send_cli(command, *args, **kwargs) + return dispatcher + + def send_cli(self, command, *args, **kwargs): + """Run bitcoin-cli command. Deserializes returned string as python object.""" + + pos_args = [str(arg) for arg in args] + named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] + assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" + p_args = [self.binary, "-datadir=" + self.datadir] + if named_args: + p_args += ["-named"] + p_args += [command] + pos_args + named_args + cli_output = subprocess.check_output(p_args, universal_newlines=True) + return json.loads(cli_output, parse_float=decimal.Decimal) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 93f180555..01236b607 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -279,6 +279,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove #Set env vars if "BITCOIND" not in os.environ: os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext + os.environ["BITCOINCLI"] = build_dir + '/src/bitcoin-cli' + exeext tests_dir = src_dir + '/test/functional/' From 716066dbea0e448b78838a692c4627a9e32fcec2 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Tue, 11 Jul 2017 13:02:01 -0400 Subject: [PATCH 06/37] [tests] Add bitcoin_cli.py test script Github-Pull: #10798 Rebased-From: c6ec4358a797b7a11283238a0cf0b4531def9e92 --- test/functional/bitcoin_cli.py | 26 ++++++++++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 27 insertions(+) create mode 100755 test/functional/bitcoin_cli.py diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py new file mode 100755 index 000000000..103320209 --- /dev/null +++ b/test/functional/bitcoin_cli.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright (c) 2017 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 bitcoin-cli""" +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +class TestBitcoinCli(BitcoinTestFramework): + + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 1 + + def run_test(self): + """Main test logic""" + + self.log.info("Compare responses from getinfo RPC and `bitcoin-cli getinfo`") + cli_get_info = self.nodes[0].cli.getinfo() + rpc_get_info = self.nodes[0].getinfo() + + assert_equal(cli_get_info, rpc_get_info) + +if __name__ == '__main__': + TestBitcoinCli().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 01236b607..fae4f66d7 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -81,6 +81,7 @@ BASE_SCRIPTS= [ # vv Tests less than 30s vv 'keypool-topup.py', 'zmq_test.py', + 'bitcoin_cli.py', 'mempool_resurrect_test.py', 'txn_doublespend.py --mineblock', 'txn_clone.py', From 2a5d099e47c896a7a3bd0015ca179587257b7792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Tim=C3=B3n?= Date: Tue, 18 Jul 2017 02:19:21 +0200 Subject: [PATCH 07/37] RPC: gettxout: Slightly improve doc and tests Github-Pull: #10859 Rebased-From: 6d2d2eb49389d70a5db327e133c9c90748f82d5f --- src/rpc/blockchain.cpp | 7 ++++--- test/functional/wallet.py | 12 ++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 34bcdf9cc..720eb068b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -944,9 +944,10 @@ UniValue gettxout(const JSONRPCRequest& request) "gettxout \"txid\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" - "2. n (numeric, required) vout number\n" - "3. include_mempool (boolean, optional) Whether to include the mempool\n" + "1. \"txid\" (string, required) The transaction id\n" + "2. \"n\" (numeric, required) vout number\n" + "3. \"include_mempool\" (boolean, optional) Whether to include the mempool. Default: true." + " Note that an unspent output that is spent in the mempool won't appear.\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 3e3e8fcdd..a37c457bc 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -56,6 +56,15 @@ class WalletTest(BitcoinTestFramework): assert_equal(len(self.nodes[1].listunspent()), 1) assert_equal(len(self.nodes[2].listunspent()), 0) + self.log.info("test gettxout") + confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] + # First, outputs that are unspent both in the chain and in the + # mempool should appear with or without include_mempool + txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) + assert_equal(txout['value'], 50) + txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) + assert_equal(txout['value'], 50) + # Send 21 BTC from 0 to 2 using sendtoaddress call. # Locked memory should use at least 32 bytes to sign each transaction self.log.info("test getmemoryinfo") @@ -65,10 +74,9 @@ class WalletTest(BitcoinTestFramework): memory_after = self.nodes[0].getmemoryinfo() assert(memory_before['locked']['used'] + 64 <= memory_after['locked']['used']) - self.log.info("test gettxout") + self.log.info("test gettxout (second part)") # utxo spent in mempool should be visible if you exclude mempool # but invisible if you include mempool - confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) assert_equal(txout['value'], 50) txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) From 847c75ec6447f58b6c4f3732a10551f1faddbb0b Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Sat, 26 Aug 2017 01:20:33 +0300 Subject: [PATCH 08/37] Add getmininginfo functional test Github-Pull: #11150 Rebased-From: 4f2905b76b502a9de235dbe739e5fe504ef5bc22 --- test/functional/mining.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/test/functional/mining.py b/test/functional/mining.py index dbd4e29ec..f3d1f3e90 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -4,16 +4,18 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test mining RPCs +- getmininginfo - getblocktemplate proposal mode - submitblock""" -from binascii import b2a_hex import copy +from binascii import b2a_hex +from decimal import Decimal from test_framework.blocktools import create_coinbase -from test_framework.test_framework import BitcoinTestFramework from test_framework.mininode import CBlock -from test_framework.util import * +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_raises_jsonrpc def b2x(b): return b2a_hex(b).decode('ascii') @@ -33,6 +35,18 @@ class MiningTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] + + self.log.info('getmininginfo') + mining_info = node.getmininginfo() + assert_equal(mining_info['blocks'], 200) + assert_equal(mining_info['chain'], 'regtest') + assert_equal(mining_info['currentblocksize'], 0) + assert_equal(mining_info['currentblocktx'], 0) + assert_equal(mining_info['currentblockweight'], 0) + assert_equal(mining_info['difficulty'], Decimal('4.656542373906925E-10')) + assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334')) + assert_equal(mining_info['pooledtx'], 0) + # Mine a block to leave initial block download node.generate(1) tmpl = node.getblocktemplate() From 11a5992c90d4cc9a3823ea08dab2c078bcbf15d2 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Wed, 23 Aug 2017 15:49:01 -0400 Subject: [PATCH 09/37] [tests] fix - use rpc_timeout as rpc timeout Github-Pull: #11121 Rebased-From: be2a2ab6a67beef97e3c3cf42bd5eeea6c4e55cf --- test/functional/test_framework/test_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 7c1325e69..553c7c9d2 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -78,7 +78,7 @@ class TestNode(): for _ in range(poll_per_s * self.rpc_timeout): assert self.process.poll() is None, "bitcoind exited with status %i during initialization" % self.process.returncode try: - self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, coveragedir=self.coverage_dir) + self.rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir) self.rpc.getblockcount() # If the call to getblockcount() succeeds then the RPC connection is up self.rpc_connected = True From 4d3ba18386c7a09086d06c8b640c19343ff34188 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 9 Jun 2017 16:35:17 -0400 Subject: [PATCH 10/37] [tests] TestNode: separate add_node from start_node Separates the act of creating a TestNode object from starting the node. The test_framework now keeps track of its list of TestNodes, and test writers can call start_node() and stop_node() without having to update the self.nodes list. Github-Pull: #11121 Rebased-From: 36b626867087e9fae6d85f926248997ebff327b7 --- test/functional/abandonconflict.py | 6 +- test/functional/assumevalid.py | 9 +- test/functional/bip9-softforks.py | 1 + test/functional/blockchain.py | 2 +- test/functional/bumpfee.py | 11 +-- test/functional/create_cache.py | 1 - test/functional/dbcrash.py | 5 +- test/functional/disconnect_ban.py | 2 +- test/functional/forknotify.py | 13 +-- test/functional/fundrawtransaction.py | 4 +- test/functional/import-rescan.py | 3 +- test/functional/importmulti.py | 2 +- test/functional/keypool-topup.py | 4 +- test/functional/keypool.py | 2 +- test/functional/listtransactions.py | 4 - test/functional/maxuploadtarget.py | 2 +- test/functional/mempool_persist.py | 11 +-- test/functional/multiwallet.py | 8 +- test/functional/p2p-segwit.py | 2 +- test/functional/p2p-versionbits-warning.py | 4 +- test/functional/proxy_test.py | 3 +- test/functional/pruning.py | 24 +++-- test/functional/receivedby.py | 4 - test/functional/reindex.py | 2 +- test/functional/resendwallettransactions.py | 2 +- test/functional/rpcbind_test.py | 13 +-- test/functional/smartfees.py | 89 ++++++++++--------- .../test_framework/test_framework.py | 71 +++++++-------- test/functional/test_framework/test_node.py | 8 +- test/functional/wallet-dump.py | 5 +- test/functional/wallet-encryption.py | 2 +- test/functional/wallet-hd.py | 8 +- test/functional/wallet.py | 61 +++++++------ test/functional/walletbackup.py | 6 +- test/functional/zapwallettxes.py | 6 +- test/functional/zmq_test.py | 5 +- 36 files changed, 205 insertions(+), 200 deletions(-) diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py index c87c02492..1db04337a 100755 --- a/test/functional/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -74,7 +74,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Restart the node with a higher min relay fee so the parent tx is no longer in mempool # TODO: redo with eviction self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) # Verify txs no longer in either node's mempool assert_equal(len(self.nodes[0].getrawmempool()), 0) @@ -101,7 +101,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Verify that even with a low min relay fee, the tx is not reaccepted from wallet on startup once abandoned self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.00001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.00001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(self.nodes[0].getbalance(), balance) @@ -121,7 +121,7 @@ class AbandonConflictTest(BitcoinTestFramework): # Remove using high relay fee again self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-minrelaytxfee=0.0001"]) + self.start_node(0, extra_args=["-minrelaytxfee=0.0001"]) assert_equal(len(self.nodes[0].getrawmempool()), 0) newbalance = self.nodes[0].getbalance() assert_equal(newbalance, balance - Decimal("24.9996")) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index 9d17faac5..63e6a384a 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -60,10 +60,11 @@ class AssumeValidTest(BitcoinTestFramework): self.num_nodes = 3 def setup_network(self): + self.add_nodes(3, self.options.tmpdir) # Start node0. We don't start the other nodes yet since # we need to pre-mine a block with an invalid transaction # signature so we can pass in the block hash as assumevalid. - self.nodes = [self.start_node(0, self.options.tmpdir)] + self.start_node(0) def send_blocks_until_disconnected(self, node): """Keep sending blocks to the node until we're disconnected.""" @@ -162,15 +163,13 @@ class AssumeValidTest(BitcoinTestFramework): height += 1 # Start node1 and node2 with assumevalid so they accept a block with a bad signature. - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-assumevalid=" + hex(block102.sha256)])) + self.start_node(1, extra_args=["-assumevalid=" + hex(block102.sha256)]) node1 = BaseNode() # connects to node1 connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], node1)) node1.add_connection(connections[1]) node1.wait_for_verack() - self.nodes.append(self.start_node(2, self.options.tmpdir, - ["-assumevalid=" + hex(block102.sha256)])) + self.start_node(2, extra_args=["-assumevalid=" + hex(block102.sha256)]) node2 = BaseNode() # connects to node2 connections.append(NodeConn('127.0.0.1', p2p_port(2), self.nodes[2], node2)) node2.add_connection(connections[2]) diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py index f00232c9f..ad1648255 100755 --- a/test/functional/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -241,6 +241,7 @@ class BIP9SoftForksTest(ComparisonTestFramework): # Restart all self.test.clear_all_connections() self.stop_nodes() + self.nodes = [] shutil.rmtree(self.options.tmpdir + "/node0") self.setup_chain() self.setup_network() diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 0812e1b0d..a3a6cf2fb 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -146,7 +146,7 @@ class BlockchainTest(BitcoinTestFramework): pass # The node already shut down before response self.log.debug('Node should stop at this height...') self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 3c488f609..59c65f18e 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -34,21 +34,18 @@ class BumpFeeTest(BitcoinTestFramework): super().__init__() self.num_nodes = 2 self.setup_clean_chain = True + self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] + for i in range(self.num_nodes)] - def setup_network(self, split=False): - extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] - for i in range(self.num_nodes)] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) - + def run_test(self): # Encrypt wallet for test_locked_wallet_fails test self.nodes[1].node_encrypt_wallet(WALLET_PASSPHRASE) - self.nodes[1] = self.start_node(1, self.options.tmpdir, extra_args[1]) + self.start_node(1) self.nodes[1].walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() - def run_test(self): peer_node, rbf_node = self.nodes rbf_node_address = rbf_node.getnewaddress() diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 39c4c0f47..1a5754b3f 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -18,7 +18,6 @@ class CreateCache(BitcoinTestFramework): # Test network and test nodes are not required: self.num_nodes = 0 - self.nodes = [] def setup_network(self): pass diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index a7fcc411c..d39369105 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -65,7 +65,8 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test def restart_node(self, node_index, expected_tip): @@ -78,7 +79,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): while time.time() - time_start < 120: try: # Any of these RPC calls could throw due to node crash - self.nodes[node_index] = self.start_node(node_index, self.options.tmpdir, self.extra_args[node_index], timewait=90) + self.start_node(node_index) self.nodes[node_index].waitforblock(expected_tip) utxo_hash = self.nodes[node_index].gettxoutsetinfo()['hash_serialized_2'] return utxo_hash diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index 19723226d..cc8901c40 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -68,8 +68,8 @@ class DisconnectBanTest(BitcoinTestFramework): assert_equal(len(self.nodes[1].listbanned()), 3) self.stop_node(1) + self.start_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir) listAfterShutdown = self.nodes[1].listbanned() assert_equal("127.0.0.0/24", listAfterShutdown[0]['address']) assert_equal("127.0.0.0/32", listAfterShutdown[1]['address']) diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py index 3bcf0a679..3a2a92709 100755 --- a/test/functional/forknotify.py +++ b/test/functional/forknotify.py @@ -7,7 +7,6 @@ import os import time from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * class ForkNotifyTest(BitcoinTestFramework): @@ -17,18 +16,12 @@ class ForkNotifyTest(BitcoinTestFramework): self.setup_clean_chain = False def setup_network(self): - self.nodes = [] self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") with open(self.alert_filename, 'w', encoding='utf8'): pass # Just open then close to create zero-length file - self.nodes.append(self.start_node(0, self.options.tmpdir, - ["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""])) - # Node1 mines block.version=211 blocks - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-blockversion=211"])) - connect_nodes(self.nodes[1], 0) - - self.sync_all() + self.extra_args = [["-blockversion=2", "-alertnotify=echo %s >> \"" + self.alert_filename + "\""], + ["-blockversion=211"]] + super().setup_network() def run_test(self): # Mine 51 up-version blocks diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index f2f4efcf2..242b6eed1 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -449,11 +449,11 @@ class RawTransactionsTest(BitcoinTestFramework): ############################################################ # locked wallet test self.stop_node(0) + self.nodes[1].node_encrypt_wallet("test") self.stop_node(2) self.stop_node(3) - self.nodes[1].node_encrypt_wallet("test") - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) + self.start_nodes() # This test is not meant to test fee estimation and we'd like # to be sure all txs are sent at a consistent desired feerate for node in self.nodes: diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index 4fc507821..be52d5c84 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -121,7 +121,8 @@ class ImportRescanTest(BitcoinTestFramework): if import_node.prune: extra_args[i] += ["-prune=1"] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes() for i in range(1, self.num_nodes): connect_nodes(self.nodes[i], 0) diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index e83e85de1..6aae95549 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -429,7 +429,7 @@ class ImportMultiTest (BitcoinTestFramework): # restart nodes to check for proper serialization/deserialization of watch only address self.stop_nodes() - self.nodes = self.start_nodes(2, self.options.tmpdir) + self.start_nodes() address_assert = self.nodes[1].validateaddress(watchonly_address) assert_equal(address_assert['iswatchonly'], True) assert_equal(address_assert['ismine'], False) diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py index 0e0c0ea74..f14a449b5 100755 --- a/test/functional/keypool-topup.py +++ b/test/functional/keypool-topup.py @@ -35,7 +35,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): self.stop_node(1) shutil.copyfile(self.tmpdir + "/node1/regtest/wallet.dat", self.tmpdir + "/wallet.bak") - self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1]) + self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.log.info("Generate keys for wallet") @@ -61,7 +61,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): self.log.info("Verify keypool is restored and balance is correct") - self.nodes[1] = self.start_node(1, self.tmpdir, self.extra_args[1]) + self.start_node(1, self.extra_args[1]) connect_nodes_bi(self.nodes, 0, 1) self.sync_all() diff --git a/test/functional/keypool.py b/test/functional/keypool.py index 3e7bb0ee0..0f84b5c05 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -19,7 +19,7 @@ class KeyPoolTest(BitcoinTestFramework): # Encrypt wallet and wait to terminate nodes[0].node_encrypt_wallet('test') # Restart node 0 - nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) # Keep creating keys addr = nodes[0].getnewaddress() addr_data = nodes[0].validateaddress(addr) diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index f75a8e29c..9b9702841 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -20,11 +20,7 @@ class ListTransactionsTest(BitcoinTestFramework): super().__init__() self.num_nodes = 4 self.setup_clean_chain = False - - def setup_nodes(self): - #This test requires mocktime self.enable_mocktime() - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) def run_test(self): # Simple send, 0 to 1: diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py index 66e5bd29e..6bd6a9e34 100755 --- a/test/functional/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -147,7 +147,7 @@ class MaxUploadTest(BitcoinTestFramework): #stop and start node 0 with 1MB maxuploadtarget, whitelist 127.0.0.1 self.log.info("Restarting nodes with -whitelist=127.0.0.1") self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) + self.start_node(0, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000"]) #recreate/reconnect a test node test_nodes = [TestNode()] diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 807edeb7a..dc5a3263f 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -63,9 +63,8 @@ class MempoolPersistTest(BitcoinTestFramework): self.log.debug("Stop-start node0 and node1. Verify that node0 has the transactions in its mempool and node1 does not.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir)) - self.nodes.append(self.start_node(1, self.options.tmpdir)) + self.start_node(0) + self.start_node(1) # Give bitcoind a second to reload the mempool time.sleep(1) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) @@ -73,16 +72,14 @@ class MempoolPersistTest(BitcoinTestFramework): self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir, ["-persistmempool=0"])) + self.start_node(0, extra_args=["-persistmempool=0"]) # Give bitcoind a second to reload the mempool time.sleep(1) assert_equal(len(self.nodes[0].getrawmempool()), 0) self.log.debug("Stop-start node0. Verify that it has the transactions in its mempool.") self.stop_nodes() - self.nodes = [] - self.nodes.append(self.start_node(0, self.options.tmpdir)) + self.start_node(0) wait_until(lambda: len(self.nodes[0].getrawmempool()) == 5) if __name__ == '__main__': diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index fc6e8e325..7381a9fd5 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -23,17 +23,17 @@ class MultiWalletTest(BitcoinTestFramework): self.stop_node(0) # should not initialize if there are duplicate wallets - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') + self.assert_start_raises_init_error(0, ['-wallet=w1', '-wallet=w1'], 'Error loading wallet w1. Duplicate -wallet filename specified.') # should not initialize if wallet file is a directory os.mkdir(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w11')) - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') + self.assert_start_raises_init_error(0, ['-wallet=w11'], 'Error loading wallet w11. -wallet filename must be a regular file.') # should not initialize if wallet file is a symlink os.symlink(os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w1'), os.path.join(self.options.tmpdir, 'node0', 'regtest', 'w12')) - self.assert_start_raises_init_error(0, self.options.tmpdir, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') + self.assert_start_raises_init_error(0, ['-wallet=w12'], 'Error loading wallet w12. -wallet filename must be a regular file.') - self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) + self.start_node(0, self.extra_args[0]) w1 = self.nodes[0].get_wallet_rpc("w1") w2 = self.nodes[0].get_wallet_rpc("w2") diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 63dfbb8ae..9189f5ef2 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -1496,7 +1496,7 @@ class SegWitTest(BitcoinTestFramework): # Restart with the new binary self.stop_node(node_id) - self.nodes[node_id] = self.start_node(node_id, self.options.tmpdir) + self.start_node(node_id, extra_args=[]) connect_nodes(self.nodes[0], node_id) sync_blocks(self.nodes) diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index df7e8ce5c..a7aacf908 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -112,7 +112,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Empty out the alert file with open(self.alert_filename, 'w', encoding='utf8') as _: pass - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() # Connecting one block should be enough to generate an error. self.nodes[0].generate(1) @@ -123,7 +123,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.test_versionbits_in_alert_file() # Test framework expects the node to still be running... - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() if __name__ == '__main__': VersionBitsWarningTest().main() diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index ae6f843dd..7f5a3810f 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -89,7 +89,8 @@ class ProxyTest(BitcoinTestFramework): ] if self.have_ipv6: args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.start_nodes() def node_test(self, node, proxies, auth, test_onion=True): rv = [] diff --git a/test/functional/pruning.py b/test/functional/pruning.py index 0af91e065..fe406e89a 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -56,6 +56,10 @@ class PruneTest(BitcoinTestFramework): connect_nodes(self.nodes[0], 4) sync_blocks(self.nodes[0:5]) + def setup_nodes(self): + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=900) + self.start_nodes() + def create_big_chain(self): # Start by creating some coinbases we can spend later self.nodes[1].generate(200) @@ -98,7 +102,7 @@ class PruneTest(BitcoinTestFramework): # Node 2 stays connected, so it hears about the stale blocks and then reorg's when node0 reconnects # Stopping node 0 also clears its mempool, so it doesn't have node1's transactions to accidentally mine self.stop_node(0) - self.nodes[0]=self.start_node(0, self.options.tmpdir, self.full_node_default_args, timewait=900) + self.start_node(0, extra_args=self.full_node_default_args) # Mine 24 blocks in node 1 for i in range(24): if j == 0: @@ -126,7 +130,7 @@ class PruneTest(BitcoinTestFramework): # Reboot node 1 to clear its mempool (hopefully make the invalidate faster) # Lower the block max size so we don't keep mining all our big mempool transactions (from disconnected blocks) self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"]) height = self.nodes[1].getblockcount() self.log.info("Current block height: %d" % height) @@ -149,7 +153,7 @@ class PruneTest(BitcoinTestFramework): # Reboot node1 to clear those giant tx's from mempool self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, ["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"], timewait=900) + self.start_node(1, extra_args=["-maxreceivebuffer=20000","-blockmaxsize=5000", "-checkblocks=5", "-disablesafemode"]) self.log.info("Generating new longer chain of 300 more blocks") self.nodes[1].generate(300) @@ -227,13 +231,15 @@ class PruneTest(BitcoinTestFramework): def manual_test(self, node_number, use_timestamp): # at this point, node has 995 blocks and has not yet run in prune mode - node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, timewait=900) + self.start_node(node_number) + node = self.nodes[node_number] assert_equal(node.getblockcount(), 995) assert_raises_jsonrpc(-1, "not in prune mode", node.pruneblockchain, 500) - self.stop_node(node_number) # now re-start in manual pruning mode - node = self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=1"], timewait=900) + self.stop_node(node_number) + self.start_node(node_number, extra_args=["-prune=1"]) + node = self.nodes[node_number] assert_equal(node.getblockcount(), 995) def height(index): @@ -307,7 +313,7 @@ class PruneTest(BitcoinTestFramework): # stop node, start back up with auto-prune at 550MB, make sure still runs self.stop_node(node_number) - self.nodes[node_number] = self.start_node(node_number, self.options.tmpdir, ["-prune=550"], timewait=900) + self.start_node(node_number, extra_args=["-prune=550"]) self.log.info("Success") @@ -315,7 +321,7 @@ class PruneTest(BitcoinTestFramework): # check that the pruning node's wallet is still in good shape self.log.info("Stop and start pruning node to trigger wallet rescan") self.stop_node(2) - self.nodes[2] = self.start_node(2, self.options.tmpdir, ["-prune=550"]) + self.start_node(2, extra_args=["-prune=550"]) self.log.info("Success") # check that wallet loads successfully when restarting a pruned node after IBD. @@ -325,7 +331,7 @@ class PruneTest(BitcoinTestFramework): nds = [self.nodes[0], self.nodes[5]] sync_blocks(nds, wait=5, timeout=300) self.stop_node(5) #stop and start to trigger rescan - self.nodes[5] = self.start_node(5, self.options.tmpdir, ["-prune=550"]) + self.start_node(5, extra_args=["-prune=550"]) self.log.info("Success") def run_test(self): diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index 19d99c9c9..b16583416 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -28,11 +28,7 @@ class ReceivedByTest(BitcoinTestFramework): super().__init__() self.num_nodes = 4 self.setup_clean_chain = False - - def setup_nodes(self): - #This test requires mocktime self.enable_mocktime() - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir) def run_test(self): ''' diff --git a/test/functional/reindex.py b/test/functional/reindex.py index b446baa04..0d2a10659 100755 --- a/test/functional/reindex.py +++ b/test/functional/reindex.py @@ -25,7 +25,7 @@ class ReindexTest(BitcoinTestFramework): blockcount = self.nodes[0].getblockcount() self.stop_nodes() extra_args = [["-reindex-chainstate" if justchainstate else "-reindex", "-checkblockindex=1"]] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes(extra_args) while self.nodes[0].getblockcount() < blockcount: time.sleep(0.1) assert_equal(self.nodes[0].getblockcount(), blockcount) diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py index 5059aa106..db6f6eec4 100755 --- a/test/functional/resendwallettransactions.py +++ b/test/functional/resendwallettransactions.py @@ -20,7 +20,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): # Should return an empty array if there aren't unconfirmed wallet transactions. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0, extra_args=[]) assert_equal(self.nodes[0].resendwallettransactions(), []) # Should return an array with the unconfirmed wallet transaction. diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index 20808207b..e9d64af20 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -20,10 +20,7 @@ class RPCBindTest(BitcoinTestFramework): self.num_nodes = 1 def setup_network(self): - pass - - def setup_nodes(self): - pass + self.add_nodes(self.num_nodes, self.options.tmpdir, None) def run_bind_test(self, allow_ips, connect_to, addresses, expected): ''' @@ -31,12 +28,14 @@ class RPCBindTest(BitcoinTestFramework): then try to connect, and check if the set of bound addresses matches the expected set. ''' + self.log.info("Bind test for %s" % str(addresses)) expected = [(addr_to_hex(addr), port) for (addr, port) in expected] base_args = ['-disablewallet', '-nolisten'] if allow_ips: base_args += ['-rpcallowip=' + x for x in allow_ips] binds = ['-rpcbind='+addr for addr in addresses] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args + binds], connect_to) + self.nodes[0].rpchost = connect_to + self.start_node(0, base_args + binds) pid = self.nodes[0].process.pid assert_equal(set(get_bind_addrs(pid)), set(expected)) self.stop_nodes() @@ -46,8 +45,10 @@ class RPCBindTest(BitcoinTestFramework): Start a node with rpcallow IP, and request getnetworkinfo at a non-localhost IP. ''' + self.log.info("Allow IP test for %s:%d" % (rpchost, rpcport)) base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) + self.nodes[0].rpchost = None + self.start_nodes([base_args]) # connect to node through non-loopback interface node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir) node.getnetworkinfo() diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index bc42a319d..6eb665846 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -153,57 +153,16 @@ class EstimateFeeTest(BitcoinTestFramework): But first we need to use one node to create a lot of outputs which we will use to generate our transactions. """ - self.nodes = [] + self.add_nodes(3, self.options.tmpdir, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], + ["-blockmaxsize=17000", "-maxorphantx=1000"], + ["-blockmaxsize=8000", "-maxorphantx=1000"]]) # Use node0 to mine blocks for input splitting - self.nodes.append(self.start_node(0, self.options.tmpdir, ["-maxorphantx=1000", - "-whitelist=127.0.0.1"])) - - self.log.info("This test is time consuming, please be patient") - self.log.info("Splitting inputs so we can generate tx's") - self.txouts = [] - self.txouts2 = [] - # Split a coinbase into two transaction puzzle outputs - split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True) - - # Mine - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - - # Repeatedly split those 2 outputs, doubling twice for each rep - # Use txouts to monitor the available utxo, since these won't be tracked in wallet - reps = 0 - while (reps < 5): - #Double txouts to txouts2 - while (len(self.txouts)>0): - split_inputs(self.nodes[0], self.txouts, self.txouts2) - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - #Double txouts2 to txouts - while (len(self.txouts2)>0): - split_inputs(self.nodes[0], self.txouts2, self.txouts) - while (len(self.nodes[0].getrawmempool()) > 0): - self.nodes[0].generate(1) - reps += 1 - self.log.info("Finished splitting") - - # Now we can connect the other nodes, didn't want to connect them earlier - # so the estimates would not be affected by the splitting transactions # Node1 mines small blocks but that are bigger than the expected transaction rate. # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # (17k is room enough for 110 or so transactions) - self.nodes.append(self.start_node(1, self.options.tmpdir, - ["-blockmaxsize=17000", "-maxorphantx=1000"])) - connect_nodes(self.nodes[1], 0) - # Node2 is a stingy miner, that # produces too small blocks (room for only 55 or so transactions) - node2args = ["-blockmaxsize=8000", "-maxorphantx=1000"] - self.nodes.append(self.start_node(2, self.options.tmpdir, node2args)) - connect_nodes(self.nodes[0], 2) - connect_nodes(self.nodes[2], 1) - - self.sync_all() def transact_and_mine(self, numblocks, mining_node): min_fee = Decimal("0.00001") @@ -232,9 +191,51 @@ class EstimateFeeTest(BitcoinTestFramework): self.memutxo = newmem def run_test(self): + self.log.info("This test is time consuming, please be patient") + self.log.info("Splitting inputs so we can generate tx's") + # Make log handler available to helper functions global log log = self.log + + # Start node0 + self.start_node(0) + self.txouts = [] + self.txouts2 = [] + # Split a coinbase into two transaction puzzle outputs + split_inputs(self.nodes[0], self.nodes[0].listunspent(0), self.txouts, True) + + # Mine + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + + # Repeatedly split those 2 outputs, doubling twice for each rep + # Use txouts to monitor the available utxo, since these won't be tracked in wallet + reps = 0 + while (reps < 5): + #Double txouts to txouts2 + while (len(self.txouts)>0): + split_inputs(self.nodes[0], self.txouts, self.txouts2) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + #Double txouts2 to txouts + while (len(self.txouts2)>0): + split_inputs(self.nodes[0], self.txouts2, self.txouts) + while (len(self.nodes[0].getrawmempool()) > 0): + self.nodes[0].generate(1) + reps += 1 + self.log.info("Finished splitting") + + # Now we can connect the other nodes, didn't want to connect them earlier + # so the estimates would not be affected by the splitting transactions + self.start_node(1) + self.start_node(2) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[2], 1) + + self.sync_all() + self.fees_per_kb = [] self.memutxo = [] self.confutxo = self.txouts # Start with the set of confirmed txouts after splitting diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 7903bb004..a14ff9c29 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -91,7 +91,8 @@ class BitcoinTestFramework(object): extra_args = None if hasattr(self, "extra_args"): extra_args = self.extra_args - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.start_nodes() def run_test(self): raise NotImplementedError @@ -204,24 +205,8 @@ class BitcoinTestFramework(object): # Public helper methods. These can be accessed by the subclass test scripts. - def start_node(self, i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None, stderr=None): - """Start a bitcoind and return RPC connection to it""" - - if extra_args is None: - extra_args = [] - if binary is None: - binary = os.getenv("BITCOIND", "bitcoind") - node = TestNode(i, dirname, extra_args, rpchost, timewait, binary, stderr, self.mocktime, coverage_dir=self.options.coveragedir) - node.start() - node.wait_for_rpc_connection() - - if self.options.coveragedir is not None: - coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - - return node - - def start_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): - """Start multiple bitcoinds, return RPC connections to them""" + def add_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + """Instantiate TestNode objects""" if extra_args is None: extra_args = [[]] * num_nodes @@ -229,12 +214,30 @@ class BitcoinTestFramework(object): binary = [None] * num_nodes assert_equal(len(extra_args), num_nodes) assert_equal(len(binary), num_nodes) - nodes = [] + for i in range(num_nodes): + self.nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + + def start_node(self, i, extra_args=None, stderr=None): + """Start a bitcoind""" + + node = self.nodes[i] + + node.start(extra_args, stderr) + node.wait_for_rpc_connection() + + if self.options.coveragedir is not None: + coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) + + def start_nodes(self, extra_args=None): + """Start multiple bitcoinds""" + + if extra_args is None: + extra_args = [None] * self.num_nodes + assert_equal(len(extra_args), self.num_nodes) try: - for i in range(num_nodes): - nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) - nodes[i].start() - for node in nodes: + for i, node in enumerate(self.nodes): + node.start(extra_args[i]) + for node in self.nodes: node.wait_for_rpc_connection() except: # If one node failed to start, stop the others @@ -242,11 +245,9 @@ class BitcoinTestFramework(object): raise if self.options.coveragedir is not None: - for node in nodes: + for node in self.nodes: coverage.write_all_rpc_commands(self.options.coveragedir, node.rpc) - return nodes - def stop_node(self, i): """Stop a bitcoind test node""" self.nodes[i].stop_node() @@ -264,10 +265,10 @@ class BitcoinTestFramework(object): while not node.is_node_stopped(): time.sleep(0.1) - def assert_start_raises_init_error(self, i, dirname, extra_args=None, expected_msg=None): + def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: try: - self.start_node(i, dirname, extra_args, stderr=log_stderr) + self.start_node(i, extra_args, stderr=log_stderr) self.stop_node(i) except Exception as e: assert 'bitcoind exited' in str(e) # node must have shutdown @@ -385,7 +386,7 @@ class BitcoinTestFramework(object): args.append("-connect=127.0.0.1:" + str(p2p_port(0))) self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) self.nodes[i].args = args - self.nodes[i].start() + self.start_node(i) # Wait for RPC connections to be ready for node in self.nodes: @@ -455,13 +456,13 @@ class ComparisonTestFramework(BitcoinTestFramework): help="bitcoind binary to use for reference nodes (if any)") def setup_network(self): - extra_args = [['-whitelist=127.0.0.1']]*self.num_nodes + extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes if hasattr(self, "extra_args"): extra_args = self.extra_args - self.nodes = self.start_nodes( - self.num_nodes, self.options.tmpdir, extra_args, - binary=[self.options.testbinary] + - [self.options.refbinary] * (self.num_nodes - 1)) + self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args, + binary=[self.options.testbinary] + + [self.options.refbinary] * (self.num_nodes - 1)) + self.start_nodes() class SkipTest(Exception): """This exception is raised to skip a test""" diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 553c7c9d2..efb3ac9d1 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -65,9 +65,13 @@ class TestNode(): assert self.rpc_connected and self.rpc is not None, "Error: no RPC connection" return self.rpc.__getattr__(*args, **kwargs) - def start(self): + def start(self, extra_args=None, stderr=None): """Start the node.""" - self.process = subprocess.Popen(self.args + self.extra_args, stderr=self.stderr) + if extra_args is None: + extra_args = self.extra_args + if stderr is None: + stderr = self.stderr + self.process = subprocess.Popen(self.args + extra_args, stderr=stderr) self.running = True self.log.debug("bitcoind started, waiting for RPC to come up") diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index 61ad00330..a588e2386 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -68,7 +68,8 @@ class WalletDumpTest(BitcoinTestFramework): # longer than the default 30 seconds due to an expensive # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in # the test often takes even longer. - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.start_nodes() def run_test (self): tmpdir = self.options.tmpdir @@ -95,7 +96,7 @@ class WalletDumpTest(BitcoinTestFramework): #encrypt wallet, restart, unlock and dump self.nodes[0].node_encrypt_wallet('test') - self.nodes[0] = self.start_node(0, self.options.tmpdir, self.extra_args[0]) + self.start_node(0) self.nodes[0].walletpassphrase('test', 10) # Should be a no-op: self.nodes[0].keypoolrefill() diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index 8fea4140d..2f38e6fee 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -31,7 +31,7 @@ class WalletEncryptionTest(BitcoinTestFramework): # Encrypt the wallet self.nodes[0].node_encrypt_wallet(passphrase) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) # Test that the wallet is encrypted assert_raises_jsonrpc(-13, "Please enter the wallet passphrase with walletpassphrase first", self.nodes[0].dumpprivkey, address) diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index 821575ed1..13b9dd9a9 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -25,8 +25,8 @@ class WalletHDTest(BitcoinTestFramework): # Make sure can't switch off usehd after wallet creation self.stop_node(1) - self.assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet') - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1]) + self.assert_start_raises_init_error(1, ['-usehd=0'], 'already existing HD wallet') + self.start_node(1) connect_nodes_bi(self.nodes, 0, 1) # Make sure we use hd, keep masterkeyid @@ -76,7 +76,7 @@ class WalletHDTest(BitcoinTestFramework): shutil.rmtree(tmpdir + "/node1/regtest/blocks") shutil.rmtree(tmpdir + "/node1/regtest/chainstate") shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat") - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1]) + self.start_node(1) # Assert that derivation is deterministic hd_add_2 = None @@ -91,7 +91,7 @@ class WalletHDTest(BitcoinTestFramework): # Needs rescan self.stop_node(1) - self.nodes[1] = self.start_node(1, self.options.tmpdir, self.extra_args[1] + ['-rescan']) + self.start_node(1, extra_args=self.extra_args[1] + ['-rescan']) assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1) # send a tx and make sure its using the internal chain for the changeoutput diff --git a/test/functional/wallet.py b/test/functional/wallet.py index a37c457bc..178961014 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -21,11 +21,14 @@ class WalletTest(BitcoinTestFramework): self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): - self.nodes = self.start_nodes(3, self.options.tmpdir, self.extra_args[:3]) + self.add_nodes(4, self.options.tmpdir, self.extra_args) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) def run_test(self): @@ -42,9 +45,9 @@ class WalletTest(BitcoinTestFramework): assert_equal(walletinfo['immature_balance'], 50) assert_equal(walletinfo['balance'], 0) - self.sync_all() + self.sync_all([self.nodes[0:3]]) self.nodes[1].generate(101) - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 50) assert_equal(self.nodes[1].getbalance(), 50) @@ -96,7 +99,7 @@ class WalletTest(BitcoinTestFramework): # Have node0 mine a block, thus it will collect its own fee. self.nodes[0].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # Exercise locking of unspent outputs unspent_0 = self.nodes[2].listunspent()[0] @@ -109,7 +112,7 @@ class WalletTest(BitcoinTestFramework): # Have node1 generate 100 blocks (so node0 can recover the fee) self.nodes[1].generate(100) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # node0 should end up with 100 btc in block rewards plus fees, but # minus the 21 plus fees sent to node2 @@ -138,7 +141,7 @@ class WalletTest(BitcoinTestFramework): # Have node1 mine a block to confirm transactions: self.nodes[1].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[0].getbalance(), 0) assert_equal(self.nodes[2].getbalance(), 94) @@ -150,14 +153,14 @@ class WalletTest(BitcoinTestFramework): self.nodes[2].settxfee(fee_per_byte * 1000) txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('84'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), Decimal('10')) # Send 10 BTC with subtract fee from amount txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) @@ -165,7 +168,7 @@ class WalletTest(BitcoinTestFramework): # Sendmany 10 BTC txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", []) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_0_bal += Decimal('10') node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) assert_equal(self.nodes[0].getbalance(), node_0_bal) @@ -173,7 +176,7 @@ class WalletTest(BitcoinTestFramework): # Sendmany 10 BTC with subtract fee from amount txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address]) self.nodes[2].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal -= Decimal('10') assert_equal(self.nodes[2].getbalance(), node_2_bal) node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid))) @@ -184,9 +187,9 @@ class WalletTest(BitcoinTestFramework): # EXPECT: nodes[3] should have those transactions in its mempool. txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) - sync_mempools(self.nodes) + sync_mempools(self.nodes[0:2]) - self.nodes.append(self.start_node(3, self.options.tmpdir, self.extra_args[3])) + self.start_node(3) connect_nodes_bi(self.nodes, 0, 3) sync_blocks(self.nodes) @@ -230,22 +233,24 @@ class WalletTest(BitcoinTestFramework): #do some -walletbroadcast tests self.stop_nodes() - self.nodes = self.start_nodes(3, self.options.tmpdir, [["-walletbroadcast=0"],["-walletbroadcast=0"],["-walletbroadcast=0"]]) + self.start_node(0, ["-walletbroadcast=0"]) + self.start_node(1, ["-walletbroadcast=0"]) + self.start_node(2, ["-walletbroadcast=0"]) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) self.nodes[1].generate(1) #mine a block, tx should not be in there - self.sync_all() + self.sync_all([self.nodes[0:3]]) assert_equal(self.nodes[2].getbalance(), node_2_bal) #should not be changed because tx was not broadcasted #now broadcast from another node, mine a block, sync, and check the balance self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex']) self.nodes[1].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) node_2_bal += 2 txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted) assert_equal(self.nodes[2].getbalance(), node_2_bal) @@ -255,14 +260,16 @@ class WalletTest(BitcoinTestFramework): #restart the nodes with -walletbroadcast=1 self.stop_nodes() - self.nodes = self.start_nodes(3, self.options.tmpdir) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes_bi(self.nodes,0,1) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - sync_blocks(self.nodes) + sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) - sync_blocks(self.nodes) + sync_blocks(self.nodes[0:3]) node_2_bal += 2 #tx should be added to balance because after restarting the nodes tx should be broadcastet @@ -293,7 +300,7 @@ class WalletTest(BitcoinTestFramework): address_to_import = self.nodes[2].getnewaddress() txid = self.nodes[0].sendtoaddress(address_to_import, 1) self.nodes[0].generate(1) - self.sync_all() + self.sync_all([self.nodes[0:3]]) # 2. Import address from node2 to node1 self.nodes[1].importaddress(address_to_import) @@ -319,15 +326,15 @@ class WalletTest(BitcoinTestFramework): cbAddr = self.nodes[1].getnewaddress() blkHash = self.nodes[0].generatetoaddress(1, cbAddr)[0] cbTxId = self.nodes[0].getblock(blkHash)['tx'][0] - self.sync_all() + self.sync_all([self.nodes[0:3]]) # Check that the txid and balance is found by node1 self.nodes[1].gettransaction(cbTxId) # check if wallet or blockchain maintenance changes the balance - self.sync_all() + self.sync_all([self.nodes[0:3]]) blocks = self.nodes[0].generate(2) - self.sync_all() + self.sync_all([self.nodes[0:3]]) balance_nodes = [self.nodes[i].getbalance() for i in range(3)] block_count = self.nodes[0].getblockcount() @@ -358,7 +365,9 @@ class WalletTest(BitcoinTestFramework): self.log.info("check " + m) self.stop_nodes() # set lower ancestor limit for later - self.nodes = self.start_nodes(3, self.options.tmpdir, [[m, "-limitancestorcount="+str(chainlimit)]] * 3) + self.start_node(0, [m, "-limitancestorcount="+str(chainlimit)]) + self.start_node(1, [m, "-limitancestorcount="+str(chainlimit)]) + self.start_node(2, [m, "-limitancestorcount="+str(chainlimit)]) while m == '-reindex' and [block_count] * 3 != [self.nodes[i].getblockcount() for i in range(3)]: # reindex will leave rpc warm up "early"; Wait for it to finish time.sleep(0.1) @@ -406,7 +415,7 @@ class WalletTest(BitcoinTestFramework): # Try with walletrejectlongchains # Double chain limit but require combining inputs, so we pass SelectCoinsMinConf self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)]) + self.start_node(0, extra_args=["-walletrejectlongchains", "-limitancestorcount="+str(2*chainlimit)]) # wait for loadmempool timeout = 10 diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index ff51cba4b..688cd6d0c 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -78,9 +78,9 @@ class WalletBackupTest(BitcoinTestFramework): # As above, this mirrors the original bash test. def start_three(self): - self.nodes[0] = self.start_node(0, self.options.tmpdir) - self.nodes[1] = self.start_node(1, self.options.tmpdir) - self.nodes[2] = self.start_node(2, self.options.tmpdir) + self.start_node(0) + self.start_node(1) + self.start_node(2) connect_nodes(self.nodes[0], 3) connect_nodes(self.nodes[1], 3) connect_nodes(self.nodes[2], 3) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index af867d7a5..1005a4b95 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -48,7 +48,7 @@ class ZapWalletTXesTest (BitcoinTestFramework): # Stop-start node0. Both confirmed and unconfirmed transactions remain in the wallet. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir) + self.start_node(0) assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) @@ -56,7 +56,7 @@ class ZapWalletTXesTest (BitcoinTestFramework): # Stop node0 and restart with zapwallettxes and persistmempool. The unconfirmed # transaction is zapped from the wallet, but is re-added when the mempool is reloaded. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-persistmempool=1", "-zapwallettxes=2"]) + self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) @@ -64,7 +64,7 @@ class ZapWalletTXesTest (BitcoinTestFramework): # Stop node0 and restart with zapwallettxes, but not persistmempool. # The unconfirmed transaction is zapped and is no longer in the wallet. self.stop_node(0) - self.nodes[0] = self.start_node(0, self.options.tmpdir, ["-zapwallettxes=2"]) + self.start_node(0, ["-zapwallettxes=2"]) # tx1 is still be available because it was confirmed assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 26c946d21..603b7a1b9 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -41,8 +41,9 @@ class ZMQTest (BitcoinTestFramework): self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) - extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] - self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] + self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.start_nodes() def run_test(self): try: From bb5e7cb308b58a1c16db1275dfca1a31e2bba71f Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 24 Aug 2017 11:37:25 -0400 Subject: [PATCH 11/37] [tests] Avoid passing around member variables in test_framework Github-Pull: #11121 Rebased-From: 6cf094a0229d051ab8a15189c8a0bc6011919e72 --- test/functional/assumevalid.py | 2 +- test/functional/dbcrash.py | 2 +- test/functional/import-rescan.py | 2 +- test/functional/proxy_test.py | 2 +- test/functional/pruning.py | 2 +- test/functional/rpcbind_test.py | 2 +- test/functional/smartfees.py | 6 +-- .../test_framework/test_framework.py | 48 +++++++++---------- test/functional/wallet-dump.py | 2 +- test/functional/wallet.py | 2 +- test/functional/zmq_test.py | 2 +- 11 files changed, 36 insertions(+), 36 deletions(-) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index 63e6a384a..ec485281d 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -60,7 +60,7 @@ class AssumeValidTest(BitcoinTestFramework): self.num_nodes = 3 def setup_network(self): - self.add_nodes(3, self.options.tmpdir) + self.add_nodes(3) # Start node0. We don't start the other nodes yet since # we need to pre-mine a block with an invalid transaction # signature so we can pass in the block hash as assumevalid. diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index d39369105..b0c6d39c4 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -65,7 +65,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=90) + self.add_nodes(self.num_nodes, timewait=90) self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index be52d5c84..e85086fbc 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -121,7 +121,7 @@ class ImportRescanTest(BitcoinTestFramework): if import_node.prune: extra_args[i] += ["-prune=1"] - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, extra_args) self.start_nodes() for i in range(1, self.num_nodes): connect_nodes(self.nodes[i], 0) diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index 7f5a3810f..adbbda278 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -89,7 +89,7 @@ class ProxyTest(BitcoinTestFramework): ] if self.have_ipv6: args[3] = ['-listen', '-proxy=[%s]:%i' % (self.conf3.addr),'-proxyrandomize=0', '-noonion'] - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args=args) + self.add_nodes(self.num_nodes, extra_args=args) self.start_nodes() def node_test(self, node, proxies, auth, test_onion=True): diff --git a/test/functional/pruning.py b/test/functional/pruning.py index fe406e89a..969042876 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -57,7 +57,7 @@ class PruneTest(BitcoinTestFramework): sync_blocks(self.nodes[0:5]) def setup_nodes(self): - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=900) + self.add_nodes(self.num_nodes, self.extra_args, timewait=900) self.start_nodes() def create_big_chain(self): diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index e9d64af20..a7661421f 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -20,7 +20,7 @@ class RPCBindTest(BitcoinTestFramework): self.num_nodes = 1 def setup_network(self): - self.add_nodes(self.num_nodes, self.options.tmpdir, None) + self.add_nodes(self.num_nodes, None) def run_bind_test(self, allow_ips, connect_to, addresses, expected): ''' diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index 6eb665846..caf359265 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -153,9 +153,9 @@ class EstimateFeeTest(BitcoinTestFramework): But first we need to use one node to create a lot of outputs which we will use to generate our transactions. """ - self.add_nodes(3, self.options.tmpdir, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], - ["-blockmaxsize=17000", "-maxorphantx=1000"], - ["-blockmaxsize=8000", "-maxorphantx=1000"]]) + self.add_nodes(3, extra_args=[["-maxorphantx=1000", "-whitelist=127.0.0.1"], + ["-blockmaxsize=17000", "-maxorphantx=1000"], + ["-blockmaxsize=8000", "-maxorphantx=1000"]]) # Use node0 to mine blocks for input splitting # Node1 mines small blocks but that are bigger than the expected transaction rate. # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index a14ff9c29..5e3644a91 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -73,9 +73,9 @@ class BitcoinTestFramework(object): def setup_chain(self): self.log.info("Initializing test directory " + self.options.tmpdir) if self.setup_clean_chain: - self._initialize_chain_clean(self.options.tmpdir, self.num_nodes) + self._initialize_chain_clean() else: - self._initialize_chain(self.options.tmpdir, self.num_nodes, self.options.cachedir) + self._initialize_chain() def setup_network(self): self.setup_nodes() @@ -91,7 +91,7 @@ class BitcoinTestFramework(object): extra_args = None if hasattr(self, "extra_args"): extra_args = self.extra_args - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args) + self.add_nodes(self.num_nodes, extra_args) self.start_nodes() def run_test(self): @@ -205,7 +205,7 @@ class BitcoinTestFramework(object): # Public helper methods. These can be accessed by the subclass test scripts. - def add_nodes(self, num_nodes, dirname, extra_args=None, rpchost=None, timewait=None, binary=None): + def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None): """Instantiate TestNode objects""" if extra_args is None: @@ -215,7 +215,7 @@ class BitcoinTestFramework(object): assert_equal(len(extra_args), num_nodes) assert_equal(len(binary), num_nodes) for i in range(num_nodes): - self.nodes.append(TestNode(i, dirname, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) + self.nodes.append(TestNode(i, self.options.tmpdir, extra_args[i], rpchost, timewait=timewait, binary=binary[i], stderr=None, mocktime=self.mocktime, coverage_dir=self.options.coveragedir)) def start_node(self, i, extra_args=None, stderr=None): """Start a bitcoind""" @@ -357,16 +357,16 @@ class BitcoinTestFramework(object): rpc_handler.setLevel(logging.DEBUG) rpc_logger.addHandler(rpc_handler) - def _initialize_chain(self, test_dir, num_nodes, cachedir): + def _initialize_chain(self): """Initialize a pre-mined blockchain for use by the test. Create a cache of a 200-block-long chain (with wallet) for MAX_NODES Afterward, create num_nodes copies from the cache.""" - assert num_nodes <= MAX_NODES + assert self.num_nodes <= MAX_NODES create_cache = False for i in range(MAX_NODES): - if not os.path.isdir(os.path.join(cachedir, 'node' + str(i))): + if not os.path.isdir(os.path.join(self.options.cachedir, 'node' + str(i))): create_cache = True break @@ -375,16 +375,16 @@ class BitcoinTestFramework(object): # find and delete old cache directories if any exist for i in range(MAX_NODES): - if os.path.isdir(os.path.join(cachedir, "node" + str(i))): - shutil.rmtree(os.path.join(cachedir, "node" + str(i))) + if os.path.isdir(os.path.join(self.options.cachedir, "node" + str(i))): + shutil.rmtree(os.path.join(self.options.cachedir, "node" + str(i))) # Create cache directories, run bitcoinds: for i in range(MAX_NODES): - datadir = initialize_datadir(cachedir, i) + datadir = initialize_datadir(self.options.cachedir, i) args = [os.getenv("BITCOIND", "bitcoind"), "-server", "-keypool=1", "-datadir=" + datadir, "-discover=0"] if i > 0: args.append("-connect=127.0.0.1:" + str(p2p_port(0))) - self.nodes.append(TestNode(i, cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) + self.nodes.append(TestNode(i, self.options.cachedir, extra_args=[], rpchost=None, timewait=None, binary=None, stderr=None, mocktime=self.mocktime, coverage_dir=None)) self.nodes[i].args = args self.start_node(i) @@ -415,24 +415,24 @@ class BitcoinTestFramework(object): self.nodes = [] self.disable_mocktime() for i in range(MAX_NODES): - os.remove(log_filename(cachedir, i, "debug.log")) - os.remove(log_filename(cachedir, i, "db.log")) - os.remove(log_filename(cachedir, i, "peers.dat")) - os.remove(log_filename(cachedir, i, "fee_estimates.dat")) + os.remove(log_filename(self.options.cachedir, i, "debug.log")) + os.remove(log_filename(self.options.cachedir, i, "db.log")) + os.remove(log_filename(self.options.cachedir, i, "peers.dat")) + os.remove(log_filename(self.options.cachedir, i, "fee_estimates.dat")) - for i in range(num_nodes): - from_dir = os.path.join(cachedir, "node" + str(i)) - to_dir = os.path.join(test_dir, "node" + str(i)) + for i in range(self.num_nodes): + from_dir = os.path.join(self.options.cachedir, "node" + str(i)) + to_dir = os.path.join(self.options.tmpdir, "node" + str(i)) shutil.copytree(from_dir, to_dir) - initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf + initialize_datadir(self.options.tmpdir, i) # Overwrite port/rpcport in bitcoin.conf - def _initialize_chain_clean(self, test_dir, num_nodes): + def _initialize_chain_clean(self): """Initialize empty blockchain for use by the test. Create an empty blockchain and num_nodes wallets. Useful if a test case wants complete control over initialization.""" - for i in range(num_nodes): - initialize_datadir(test_dir, i) + for i in range(self.num_nodes): + initialize_datadir(self.options.tmpdir, i) class ComparisonTestFramework(BitcoinTestFramework): """Test framework for doing p2p comparison testing @@ -459,7 +459,7 @@ class ComparisonTestFramework(BitcoinTestFramework): extra_args = [['-whitelist=127.0.0.1']] * self.num_nodes if hasattr(self, "extra_args"): extra_args = self.extra_args - self.add_nodes(self.num_nodes, self.options.tmpdir, extra_args, + self.add_nodes(self.num_nodes, extra_args, binary=[self.options.testbinary] + [self.options.refbinary] * (self.num_nodes - 1)) self.start_nodes() diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index a588e2386..e0381b980 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -68,7 +68,7 @@ class WalletDumpTest(BitcoinTestFramework): # longer than the default 30 seconds due to an expensive # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in # the test often takes even longer. - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) + self.add_nodes(self.num_nodes, self.extra_args, timewait=60) self.start_nodes() def run_test (self): diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 178961014..7190de94b 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -21,7 +21,7 @@ class WalletTest(BitcoinTestFramework): self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): - self.add_nodes(4, self.options.tmpdir, self.extra_args) + self.add_nodes(4, self.extra_args) self.start_node(0) self.start_node(1) self.start_node(2) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 603b7a1b9..b5a22ea07 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -42,7 +42,7 @@ class ZMQTest (BitcoinTestFramework): ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] - self.add_nodes(self.num_nodes, self.options.tmpdir, self.extra_args) + self.add_nodes(self.num_nodes, self.extra_args) self.start_nodes() def run_test(self): From 801d2ae9247be5870344c8b4ed5c372ab8930408 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 9 Jun 2017 18:21:21 -0400 Subject: [PATCH 12/37] [tests] don't override __init__() in individual tests Almost all test scripts currently need to override the __init__() method. When they do that they need to call into super().__init__() as the base class does some generic initialization. This commit makes the base class __init__() call into set_test_params() method. Individual test cases can override set_test_params() to setup their test parameters. Github-Pull: #11121 Rebased-From: 5448a1471d6fc638a2220ea5a2f3782172efe14c --- test/functional/README.md | 6 +- test/functional/abandonconflict.py | 4 +- test/functional/assumevalid.py | 3 +- test/functional/bip65-cltv-p2p.py | 4 +- test/functional/bip68-112-113-p2p.py | 4 +- test/functional/bip68-sequence.py | 4 +- test/functional/bip9-softforks.py | 5 +- test/functional/bipdersig-p2p.py | 4 +- test/functional/blockchain.py | 6 +- test/functional/bumpfee.py | 3 +- test/functional/create_cache.py | 6 +- test/functional/dbcrash.py | 3 +- test/functional/decodescript.py | 4 +- test/functional/disablewallet.py | 5 +- test/functional/disconnect_ban.py | 5 +- test/functional/example_test.py | 10 +-- test/functional/forknotify.py | 5 +- test/functional/fundrawtransaction.py | 6 +- test/functional/getblocktemplate_longpoll.py | 5 -- test/functional/getchaintips.py | 6 -- test/functional/httpbasics.py | 4 +- test/functional/import-rescan.py | 3 +- test/functional/importmulti.py | 3 +- test/functional/importprunedfunds.py | 5 +- test/functional/invalidateblock.py | 4 +- test/functional/invalidblockrequest.py | 4 +- test/functional/invalidtxrequest.py | 4 +- test/functional/keypool-topup.py | 3 +- test/functional/keypool.py | 7 +- test/functional/listsinceblock.py | 5 +- test/functional/listtransactions.py | 5 +- test/functional/maxuploadtarget.py | 3 +- test/functional/mempool_limit.py | 4 +- test/functional/mempool_packages.py | 4 +- test/functional/mempool_persist.py | 6 +- test/functional/mempool_reorg.py | 4 +- test/functional/mempool_resurrect_test.py | 6 +- test/functional/mempool_spendcoinbase.py | 5 +- test/functional/merkle_blocks.py | 5 +- test/functional/mining.py | 4 +- test/functional/multi_rpc.py | 5 +- test/functional/multiwallet.py | 4 +- test/functional/net.py | 4 +- test/functional/nulldummy.py | 3 +- test/functional/p2p-acceptblock.py | 3 +- test/functional/p2p-compactblocks.py | 3 +- test/functional/p2p-feefilter.py | 5 +- test/functional/p2p-fullblocktest.py | 5 +- test/functional/p2p-leaktests.py | 3 +- test/functional/p2p-mempool.py | 4 +- test/functional/p2p-segwit.py | 7 +- test/functional/p2p-timeouts.py | 3 +- test/functional/p2p-versionbits-warning.py | 3 +- test/functional/preciousblock.py | 3 +- test/functional/prioritise_transaction.py | 4 +- test/functional/proxy_test.py | 6 -- test/functional/pruning.py | 4 +- test/functional/rawtransactions.py | 4 +- test/functional/receivedby.py | 6 +- test/functional/reindex.py | 3 +- test/functional/replace-by-fee.py | 4 +- test/functional/resendwallettransactions.py | 6 +- test/functional/rest.py | 3 +- test/functional/rpcbind_test.py | 5 +- test/functional/rpcnamedargs.py | 9 +- test/functional/segwit.py | 4 +- test/functional/sendheaders.py | 3 +- test/functional/signmessages.py | 4 +- test/functional/signrawtransactions.py | 3 +- test/functional/smartfees.py | 5 +- .../test_framework/test_framework.py | 89 +++++++++++-------- test/functional/txn_clone.py | 6 -- test/functional/txn_doublespend.py | 5 -- test/functional/uptime.py | 4 +- test/functional/wallet-accounts.py | 4 +- test/functional/wallet-dump.py | 5 +- test/functional/wallet-encryption.py | 4 +- test/functional/wallet-hd.py | 5 +- test/functional/wallet.py | 18 ++-- test/functional/walletbackup.py | 5 +- test/functional/zapwallettxes.py | 4 +- test/functional/zmq_test.py | 4 +- 82 files changed, 145 insertions(+), 322 deletions(-) diff --git a/test/functional/README.md b/test/functional/README.md index 44efda33d..2558bd017 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -24,8 +24,8 @@ don't have test cases for. - Use a module-level docstring to describe what the test is testing, and how it is testing it. - When subclassing the BitcoinTestFramwork, place overrides for the - `__init__()`, and `setup_xxxx()` methods at the top of the subclass, then - locally-defined helper methods, then the `run_test()` method. + `set_test_params()`, `add_options()` and `setup_xxxx()` methods at the top of + the subclass, then locally-defined helper methods, then the `run_test()` method. #### General test-writing advice @@ -36,7 +36,7 @@ don't have test cases for. - Avoid stop-starting the nodes multiple times during the test if possible. A stop-start takes several seconds, so doing it several times blows up the runtime of the test. -- Set the `self.setup_clean_chain` variable in `__init__()` to control whether +- Set the `self.setup_clean_chain` variable in `set_test_params()` to control whether or not to use the cached data directories. The cached data directories contain a 200-block pre-mined blockchain and wallets for four nodes. Each node has 25 mature blocks (25x50=1250 BTC) in its wallet. diff --git a/test/functional/abandonconflict.py b/test/functional/abandonconflict.py index 1db04337a..e8dbc8646 100755 --- a/test/functional/abandonconflict.py +++ b/test/functional/abandonconflict.py @@ -14,10 +14,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class AbandonConflictTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-minrelaytxfee=0.00001"], []] def run_test(self): diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index ec485281d..beaf8c705 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -54,8 +54,7 @@ class BaseNode(NodeConnCB): self.send_message(headers_message) class AssumeValidTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index 65ae8de55..2cd6df6e3 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -60,9 +60,7 @@ def create_transaction(node, coinbase, to_address, amount): return tx class BIP65Test(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] self.setup_clean_chain = True diff --git a/test/functional/bip68-112-113-p2p.py b/test/functional/bip68-112-113-p2p.py index 5a322e8c0..7e6a4f440 100755 --- a/test/functional/bip68-112-113-p2p.py +++ b/test/functional/bip68-112-113-p2p.py @@ -92,9 +92,9 @@ def all_rlt_txs(txarray): return txs class BIP68_112_113Test(ComparisonTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1', '-blockversion=4']] def run_test(self): diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py index 87a50692f..39012adf9 100755 --- a/test/functional/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -17,10 +17,8 @@ SEQUENCE_LOCKTIME_MASK = 0x0000ffff NOT_FINAL_ERROR = "64: non-BIP68-final" class BIP68Test(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [[], ["-acceptnonstdtxn=0"]] def run_test(self): diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py index ad1648255..904789301 100755 --- a/test/functional/bip9-softforks.py +++ b/test/functional/bip9-softforks.py @@ -28,11 +28,10 @@ from test_framework.comptool import TestInstance, TestManager from test_framework.script import CScript, OP_1NEGATE, OP_CHECKSEQUENCEVERIFY, OP_DROP class BIP9SoftForksTest(ComparisonTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-whitelist=127.0.0.1']] + self.setup_clean_chain = True def run_test(self): self.test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index 977597089..c620d3e15 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -48,9 +48,7 @@ def create_transaction(node, coinbase, to_address, amount): return tx class BIP66Test(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-promiscuousmempoolflags=1', '-whitelist=127.0.0.1']] self.setup_clean_chain = True diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index a3a6cf2fb..5d04de994 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -30,12 +30,8 @@ from test_framework.util import ( assert_is_hash_string, ) - class BlockchainTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-stopatheight=207']] diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py index 59c65f18e..ede0df29d 100755 --- a/test/functional/bumpfee.py +++ b/test/functional/bumpfee.py @@ -30,8 +30,7 @@ WALLET_PASSPHRASE_TIMEOUT = 3600 class BumpFeeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True self.extra_args = [["-prematurewitness", "-walletprematurewitness", "-walletrbf={}".format(i)] diff --git a/test/functional/create_cache.py b/test/functional/create_cache.py index 1a5754b3f..7d4d1a529 100755 --- a/test/functional/create_cache.py +++ b/test/functional/create_cache.py @@ -12,11 +12,9 @@ tests are being run in parallel. from test_framework.test_framework import BitcoinTestFramework class CreateCache(BitcoinTestFramework): + # Test network and test nodes are not required: - def __init__(self): - super().__init__() - - # Test network and test nodes are not required: + def set_test_params(self): self.num_nodes = 0 def setup_network(self): diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index b0c6d39c4..71424f641 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -43,8 +43,7 @@ except AttributeError: pass class ChainstateWriteCrashTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = False diff --git a/test/functional/decodescript.py b/test/functional/decodescript.py index 21a9f1223..6611da883 100755 --- a/test/functional/decodescript.py +++ b/test/functional/decodescript.py @@ -10,9 +10,7 @@ from test_framework.mininode import * from io import BytesIO class DecodeScriptTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/disablewallet.py b/test/functional/disablewallet.py index d34451341..c1d37963b 100755 --- a/test/functional/disablewallet.py +++ b/test/functional/disablewallet.py @@ -11,11 +11,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * - class DisableWalletTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-disablewallet"]] diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py index cc8901c40..a6445b9b3 100755 --- a/test/functional/disconnect_ban.py +++ b/test/functional/disconnect_ban.py @@ -14,11 +14,8 @@ from test_framework.util import ( ) class DisconnectBanTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def run_test(self): self.log.info("Test setban and listbanned RPCs") diff --git a/test/functional/example_test.py b/test/functional/example_test.py index a54b5278e..de8934f74 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -73,15 +73,11 @@ def custom_function(): class ExampleTest(BitcoinTestFramework): # Each functional test is a subclass of the BitcoinTestFramework class. - # Override the __init__(), add_options(), setup_chain(), setup_network() + # Override the set_test_params(), add_options(), setup_chain(), setup_network() # and setup_nodes() methods to customize the test setup as required. - def __init__(self): - """Initialize the test - - Call super().__init__() first, and then override any test parameters - for your individual test.""" - super().__init__() + def set_test_params(self): + """Override any test parameters for your individual test.""" self.setup_clean_chain = True self.num_nodes = 3 # Use self.extra_args to change command-line arguments for the nodes diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py index 3a2a92709..afcad1f9c 100755 --- a/test/functional/forknotify.py +++ b/test/functional/forknotify.py @@ -9,11 +9,8 @@ import time from test_framework.test_framework import BitcoinTestFramework class ForkNotifyTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def setup_network(self): self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt") diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 242b6eed1..dec3d41bf 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -14,13 +14,9 @@ def get_unspent(listunspent, amount): return utx raise AssertionError('Could not find unspent with amount={}'.format(amount)) - class RawTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 def setup_network(self, split=False): self.setup_nodes() diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index cca30e268..85d256024 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -23,11 +23,6 @@ class LongpollThread(threading.Thread): self.node.getblocktemplate({'longpollid':self.longpollid}) class GetBlockTemplateLPTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def run_test(self): self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) diff --git a/test/functional/getchaintips.py b/test/functional/getchaintips.py index 15f96c565..00fc23c6b 100755 --- a/test/functional/getchaintips.py +++ b/test/functional/getchaintips.py @@ -14,13 +14,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal class GetChainTipsTest (BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def run_test (self): - tips = self.nodes[0].getchaintips () assert_equal (len (tips), 1) assert_equal (tips[0]['branchlen'], 0) diff --git a/test/functional/httpbasics.py b/test/functional/httpbasics.py index 4b32e8d9c..c7682cb49 100755 --- a/test/functional/httpbasics.py +++ b/test/functional/httpbasics.py @@ -11,10 +11,8 @@ import http.client import urllib.parse class HTTPBasicsTest (BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False def setup_network(self): self.setup_nodes() diff --git a/test/functional/import-rescan.py b/test/functional/import-rescan.py index e85086fbc..02d742812 100755 --- a/test/functional/import-rescan.py +++ b/test/functional/import-rescan.py @@ -111,8 +111,7 @@ TIMESTAMP_WINDOW = 2 * 60 * 60 class ImportRescanTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 + len(IMPORT_NODES) def setup_network(self): diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py index 6aae95549..4c519f40d 100755 --- a/test/functional/importmulti.py +++ b/test/functional/importmulti.py @@ -7,8 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class ImportMultiTest (BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/importprunedfunds.py b/test/functional/importprunedfunds.py index 94753fe43..df90e9ec1 100755 --- a/test/functional/importprunedfunds.py +++ b/test/functional/importprunedfunds.py @@ -6,11 +6,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * - class ImportPrunedFundsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/invalidateblock.py b/test/functional/invalidateblock.py index c499d57b9..dd3daf1e0 100755 --- a/test/functional/invalidateblock.py +++ b/test/functional/invalidateblock.py @@ -8,9 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class InvalidateTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/invalidblockrequest.py b/test/functional/invalidblockrequest.py index eabc0db8d..9f44b4492 100755 --- a/test/functional/invalidblockrequest.py +++ b/test/functional/invalidblockrequest.py @@ -23,9 +23,9 @@ class InvalidBlockRequestTest(ComparisonTestFramework): ''' Can either run this test as 1 node with expected answers, or two and compare them. Change the "outcome" variable from each TestInstance object to only do the comparison. ''' - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True def run_test(self): test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/invalidtxrequest.py b/test/functional/invalidtxrequest.py index a9ac231f0..a22bd8f8c 100755 --- a/test/functional/invalidtxrequest.py +++ b/test/functional/invalidtxrequest.py @@ -19,9 +19,9 @@ class InvalidTxRequestTest(ComparisonTestFramework): ''' Can either run this test as 1 node with expected answers, or two and compare them. Change the "outcome" variable from each TestInstance object to only do the comparison. ''' - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True def run_test(self): test = TestManager(self, self.options.tmpdir) diff --git a/test/functional/keypool-topup.py b/test/functional/keypool-topup.py index f14a449b5..8302e3ef6 100755 --- a/test/functional/keypool-topup.py +++ b/test/functional/keypool-topup.py @@ -20,8 +20,7 @@ from test_framework.util import ( ) class KeypoolRestoreTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=100', '-keypoolmin=20']] diff --git a/test/functional/keypool.py b/test/functional/keypool.py index 0f84b5c05..b823ca63b 100755 --- a/test/functional/keypool.py +++ b/test/functional/keypool.py @@ -8,6 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class KeyPoolTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 def run_test(self): nodes = self.nodes @@ -78,10 +80,5 @@ class KeyPoolTest(BitcoinTestFramework): assert_equal(wi['keypoolsize_hd_internal'], 100) assert_equal(wi['keypoolsize'], 100) - def __init__(self): - super().__init__() - self.setup_clean_chain = False - self.num_nodes = 1 - if __name__ == '__main__': KeyPoolTest().main() diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index ce2d556ef..ed1315e80 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -8,11 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal class ListSinceBlockTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 def run_test(self): self.nodes[2].generate(101) diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index 9b9702841..5ee85a0da 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -16,10 +16,7 @@ def txFromHex(hexstring): return tx class ListTransactionsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False + def set_test_params(self): self.enable_mocktime() def run_test(self): diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py index 6bd6a9e34..1f402798e 100755 --- a/test/functional/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -31,8 +31,7 @@ class TestNode(NodeConnCB): class MaxUploadTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-maxuploadtarget=800", "-blockmaxsize=999000"]] diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 2777291dd..e24dc5a46 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -8,9 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class MempoolLimitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-maxmempool=5", "-spendzeroconfchange=0"]] diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index e22549381..2dedadf8c 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -12,10 +12,8 @@ MAX_ANCESTORS = 25 MAX_DESCENDANTS = 25 class MempoolPackagesTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-maxorphantx=1000"], ["-maxorphantx=1000", "-limitancestorcount=5"]] # Build a transaction that spends parent_txid:vout diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index dc5a3263f..01f65b137 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -36,12 +36,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class MempoolPersistTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - # We need 3 nodes for this test. Node1 does not have a persistent mempool. + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False self.extra_args = [[], ["-persistmempool=0"], []] def run_test(self): diff --git a/test/functional/mempool_reorg.py b/test/functional/mempool_reorg.py index 937bf4bab..7dfddd323 100755 --- a/test/functional/mempool_reorg.py +++ b/test/functional/mempool_reorg.py @@ -13,10 +13,8 @@ from test_framework.util import * # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False self.extra_args = [["-checkmempool"]] * 2 alert_filename = None # Set by setup_network diff --git a/test/functional/mempool_resurrect_test.py b/test/functional/mempool_resurrect_test.py index a2f6228df..1263c9306 100755 --- a/test/functional/mempool_resurrect_test.py +++ b/test/functional/mempool_resurrect_test.py @@ -9,12 +9,8 @@ from test_framework.util import * # Create one-input, one-output, no-fee transaction: class MempoolCoinbaseTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False - # Just need one node for this test self.extra_args = [["-checkmempool"]] def run_test(self): diff --git a/test/functional/mempool_spendcoinbase.py b/test/functional/mempool_spendcoinbase.py index 277ea45ad..58ccd3e37 100755 --- a/test/functional/mempool_spendcoinbase.py +++ b/test/functional/mempool_spendcoinbase.py @@ -17,11 +17,8 @@ from test_framework.util import * # Create one-input, one-output, no-fee transaction: class MempoolSpendCoinbaseTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False self.extra_args = [["-checkmempool"]] def run_test(self): diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py index bcc65c840..2125c6e17 100755 --- a/test/functional/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -8,11 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class MerkleBlockTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing self.extra_args = [[], [], [], ["-txindex"]] diff --git a/test/functional/mining.py b/test/functional/mining.py index f3d1f3e90..93f983889 100755 --- a/test/functional/mining.py +++ b/test/functional/mining.py @@ -27,9 +27,7 @@ def assert_template(node, block, expect, rehash=True): assert_equal(rsp, expect) class MiningTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = False diff --git a/test/functional/multi_rpc.py b/test/functional/multi_rpc.py index a30e15ace..a2b346f27 100755 --- a/test/functional/multi_rpc.py +++ b/test/functional/multi_rpc.py @@ -12,10 +12,7 @@ import http.client import urllib.parse class HTTPBasicsTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 2 def setup_chain(self): diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index 7381a9fd5..e5453e9aa 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -12,9 +12,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_jsonrpc class MultiWalletTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] diff --git a/test/functional/net.py b/test/functional/net.py index 3ba3764cf..37ea6824d 100755 --- a/test/functional/net.py +++ b/test/functional/net.py @@ -17,10 +17,8 @@ from test_framework.util import ( p2p_port, ) - class NetTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/nulldummy.py b/test/functional/nulldummy.py index 9717add27..60d0d876d 100755 --- a/test/functional/nulldummy.py +++ b/test/functional/nulldummy.py @@ -37,8 +37,7 @@ def trueDummy(tx): class NULLDUMMYTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True self.extra_args = [['-whitelist=127.0.0.1', '-walletprematurewitness']] diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index 322cb767d..293bc0553 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -60,8 +60,7 @@ class AcceptBlockTest(BitcoinTestFramework): default=os.getenv("BITCOIND", "bitcoind"), help="bitcoind binary to test") - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [[], ["-whitelist=127.0.0.1"]] diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index c5c264765..9c91c0045 100755 --- a/test/functional/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -89,8 +89,7 @@ class TestNode(NodeConnCB): wait_until(lambda: not self.connected, timeout=timeout, lock=mininode_lock) class CompactBlocksTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True # Node0 = pre-segwit, node1 = segwit-aware self.num_nodes = 2 diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py index dbccb633a..8c92365ce 100755 --- a/test/functional/p2p-feefilter.py +++ b/test/functional/p2p-feefilter.py @@ -37,11 +37,8 @@ class TestNode(NodeConnCB): self.txinvs = [] class FeeFilterTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 - self.setup_clean_chain = False def run_test(self): node1 = self.nodes[1] diff --git a/test/functional/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py index e7fe7372c..cb7bbaf7e 100755 --- a/test/functional/p2p-fullblocktest.py +++ b/test/functional/p2p-fullblocktest.py @@ -49,12 +49,11 @@ class CBrokenBlock(CBlock): return r class FullBlockTest(ComparisonTestFramework): - # Can either run this test as 1 node with expected answers, or two and compare them. # Change the "outcome" variable from each TestInstance object to only do the comparison. - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 + self.setup_clean_chain = True self.block_heights = {} self.coinbase_key = CECKey() self.coinbase_key.set_secretbytes(b"horsebattery") diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index f0d4d9a8b..f27086c97 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -92,8 +92,7 @@ class CNodeNoVerackIdle(CLazyNode): conn.send_message(msg_getaddr()) class P2PLeakTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 self.extra_args = [['-banscore='+str(banscore)]] diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py index 34ef249ee..40fcde260 100755 --- a/test/functional/p2p-mempool.py +++ b/test/functional/p2p-mempool.py @@ -13,9 +13,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class P2PMempoolTests(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-peerbloomfilters=0"]] diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 9189f5ef2..8c2d2f027 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -33,8 +33,7 @@ def get_virtual_size(witness_block): return vsize class TestNode(NodeConnCB): - def __init__(self): - super().__init__() + def set_test_params(self): self.getdataset = set() def on_getdata(self, conn, message): @@ -109,9 +108,7 @@ def sign_P2PK_witness_input(script, txTo, inIdx, hashtype, value, key): class SegWitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [["-whitelist=127.0.0.1"], ["-whitelist=127.0.0.1", "-acceptnonstdtxn=0"], ["-whitelist=127.0.0.1", "-vbparams=segwit:0:0"]] diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py index c3b29c215..51d4769ef 100755 --- a/test/functional/p2p-timeouts.py +++ b/test/functional/p2p-timeouts.py @@ -33,8 +33,7 @@ class TestNode(NodeConnCB): pass class TimeoutsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index a7aacf908..5dfac6dd1 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -28,8 +28,7 @@ class TestNode(NodeConnCB): pass class VersionBitsWarningTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/preciousblock.py b/test/functional/preciousblock.py index 04b41e76b..40d7bb14e 100755 --- a/test/functional/preciousblock.py +++ b/test/functional/preciousblock.py @@ -35,8 +35,7 @@ def node_sync_via_rpc(nodes): unidirectional_node_sync_via_rpc(node_src, node_dest) class PreciousTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/prioritise_transaction.py b/test/functional/prioritise_transaction.py index 4fc03d254..7ad368acd 100755 --- a/test/functional/prioritise_transaction.py +++ b/test/functional/prioritise_transaction.py @@ -9,9 +9,7 @@ from test_framework.util import * from test_framework.mininode import COIN, MAX_BLOCK_BASE_SIZE class PrioritiseTransactionTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [["-printpriority=1"], ["-printpriority=1"]] diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index adbbda278..26cb645da 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -41,13 +41,7 @@ from test_framework.netutil import test_ipv6_local RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports - class ProxyTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def setup_nodes(self): self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports diff --git a/test/functional/pruning.py b/test/functional/pruning.py index 969042876..a4afbd46d 100755 --- a/test/functional/pruning.py +++ b/test/functional/pruning.py @@ -26,9 +26,7 @@ def calc_usage(blockdir): return sum(os.path.getsize(blockdir+f) for f in os.listdir(blockdir) if os.path.isfile(blockdir+f)) / (1024. * 1024.) class PruneTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 6 diff --git a/test/functional/rawtransactions.py b/test/functional/rawtransactions.py index 6272fc69b..51dda09ac 100755 --- a/test/functional/rawtransactions.py +++ b/test/functional/rawtransactions.py @@ -17,9 +17,7 @@ from test_framework.util import * # Create one-input, one-output, no-fee transaction: class RawTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index b16583416..48eb1c51b 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -23,11 +23,7 @@ def get_sub_array_from_array(object_array, to_match): return [] class ReceivedByTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False + def set_test_params(self): self.enable_mocktime() def run_test(self): diff --git a/test/functional/reindex.py b/test/functional/reindex.py index 0d2a10659..1f684a1af 100755 --- a/test/functional/reindex.py +++ b/test/functional/reindex.py @@ -15,8 +15,7 @@ import time class ReindexTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index bc6765498..220e88968 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -61,10 +61,8 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): class ReplaceByFeeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 1 - self.setup_clean_chain = False self.extra_args= [["-maxorphantx=1000", "-whitelist=127.0.0.1", "-limitancestorcount=50", diff --git a/test/functional/resendwallettransactions.py b/test/functional/resendwallettransactions.py index db6f6eec4..d6ba59139 100755 --- a/test/functional/resendwallettransactions.py +++ b/test/functional/resendwallettransactions.py @@ -8,11 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, assert_raises_jsonrpc class ResendWalletTransactionsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.extra_args = [['--walletbroadcast=false']] + def set_test_params(self): self.num_nodes = 1 + self.extra_args = [['--walletbroadcast=false']] def run_test(self): # Should raise RPC_WALLET_ERROR (-4) if walletbroadcast is disabled. diff --git a/test/functional/rest.py b/test/functional/rest.py index a69dbb501..437111a4d 100755 --- a/test/functional/rest.py +++ b/test/functional/rest.py @@ -43,8 +43,7 @@ def http_post_call(host, port, path, requestdata = '', response_object = 0): class RESTTest (BitcoinTestFramework): FORMAT_SEPARATOR = "." - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 diff --git a/test/functional/rpcbind_test.py b/test/functional/rpcbind_test.py index a7661421f..0cf64beeb 100755 --- a/test/functional/rpcbind_test.py +++ b/test/functional/rpcbind_test.py @@ -11,11 +11,8 @@ from test_framework.test_framework import BitcoinTestFramework, SkipTest from test_framework.util import * from test_framework.netutil import * - class RPCBindTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/rpcnamedargs.py b/test/functional/rpcnamedargs.py index 3b286000a..da61cc66e 100755 --- a/test/functional/rpcnamedargs.py +++ b/test/functional/rpcnamedargs.py @@ -10,15 +10,8 @@ from test_framework.util import ( assert_raises_jsonrpc, ) - class NamedArgumentTest(BitcoinTestFramework): - """ - Test named arguments on RPC calls. - """ - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 def run_test(self): diff --git a/test/functional/segwit.py b/test/functional/segwit.py index 51eaa34a5..c08fbd3e7 100755 --- a/test/functional/segwit.py +++ b/test/functional/segwit.py @@ -75,9 +75,7 @@ def find_unspent(node, min_value): return utxo class SegWitTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [["-walletprematurewitness", "-rpcserialversion=0"], diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index 6451b097c..fe577dc20 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -174,8 +174,7 @@ class TestNode(NodeConnCB): self.send_message(getblocks_message) class SendHeadersTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py index 42f6a9daa..5fdfeceb7 100755 --- a/test/functional/signmessages.py +++ b/test/functional/signmessages.py @@ -7,9 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework class SignMessagesTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/signrawtransactions.py b/test/functional/signrawtransactions.py index 415727268..b47ef9395 100755 --- a/test/functional/signrawtransactions.py +++ b/test/functional/signrawtransactions.py @@ -9,8 +9,7 @@ from test_framework.util import * class SignRawTransactionsTest(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/smartfees.py b/test/functional/smartfees.py index caf359265..76632fc57 100755 --- a/test/functional/smartfees.py +++ b/test/functional/smartfees.py @@ -141,11 +141,8 @@ def check_estimates(node, fees_seen, max_invalid, print_estimates = True): class EstimateFeeTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 3 - self.setup_clean_chain = False def setup_network(self): """ diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 5e3644a91..d860bc559 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -48,58 +48,30 @@ BITCOIND_PROC_WAIT_TIMEOUT = 60 class BitcoinTestFramework(object): """Base class for a bitcoin test script. - Individual bitcoin test scripts should subclass this class and override the following methods: + Individual bitcoin test scripts should subclass this class and override the run_test() method. - - __init__() + Individual tests can also override the following methods to customize the test setup: + + - set_test_params() - add_options() - setup_chain() - setup_network() - - run_test() + - setup_nodes() - The main() method should not be overridden. + The __init__() and main() methods should not be overridden. This class also contains various public and private helper methods.""" - # Methods to override in subclass test scripts. def __init__(self): + """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] self.mocktime = 0 - - def add_options(self, parser): - pass - - def setup_chain(self): - self.log.info("Initializing test directory " + self.options.tmpdir) - if self.setup_clean_chain: - self._initialize_chain_clean() - else: - self._initialize_chain() - - def setup_network(self): - self.setup_nodes() - - # Connect the nodes as a "chain". This allows us - # to split the network between nodes 1 and 2 to get - # two halves that can work on competing chains. - for i in range(self.num_nodes - 1): - connect_nodes_bi(self.nodes, i, i + 1) - self.sync_all() - - def setup_nodes(self): - extra_args = None - if hasattr(self, "extra_args"): - extra_args = self.extra_args - self.add_nodes(self.num_nodes, extra_args) - self.start_nodes() - - def run_test(self): - raise NotImplementedError - - # Main function. This should not be overridden by the subclass test scripts. + self.set_test_params() def main(self): + """Main function. This should not be overridden by the subclass test scripts.""" parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true", @@ -203,6 +175,46 @@ class BitcoinTestFramework(object): logging.shutdown() sys.exit(TEST_EXIT_FAILED) + # Methods to override in subclass test scripts. + def set_test_params(self): + """Override this method to change default values for number of nodes, topology, etc""" + pass + + def add_options(self, parser): + """Override this method to add command-line options to the test""" + pass + + def setup_chain(self): + """Override this method to customize blockchain setup""" + self.log.info("Initializing test directory " + self.options.tmpdir) + if self.setup_clean_chain: + self._initialize_chain_clean() + else: + self._initialize_chain() + + def setup_network(self): + """Override this method to customize test network topology""" + self.setup_nodes() + + # Connect the nodes as a "chain". This allows us + # to split the network between nodes 1 and 2 to get + # two halves that can work on competing chains. + for i in range(self.num_nodes - 1): + connect_nodes_bi(self.nodes, i, i + 1) + self.sync_all() + + def setup_nodes(self): + """Override this method to customize test node setup""" + extra_args = None + if hasattr(self, "extra_args"): + extra_args = self.extra_args + self.add_nodes(self.num_nodes, extra_args) + self.start_nodes() + + def run_test(self): + """Override this method to define test logic""" + raise NotImplementedError + # Public helper methods. These can be accessed by the subclass test scripts. def add_nodes(self, num_nodes, extra_args=None, rpchost=None, timewait=None, binary=None): @@ -442,8 +454,7 @@ class ComparisonTestFramework(BitcoinTestFramework): - 2 binaries: 1 test binary, 1 ref binary - n>2 binaries: 1 test binary, n-1 ref binaries""" - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 self.setup_clean_chain = True diff --git a/test/functional/txn_clone.py b/test/functional/txn_clone.py index 9b81af96c..fc133050b 100755 --- a/test/functional/txn_clone.py +++ b/test/functional/txn_clone.py @@ -8,12 +8,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class TxnMallTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/txn_doublespend.py b/test/functional/txn_doublespend.py index 1bd3b3271..ff24fac25 100755 --- a/test/functional/txn_doublespend.py +++ b/test/functional/txn_doublespend.py @@ -9,11 +9,6 @@ from test_framework.util import * class TxnMallTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - self.num_nodes = 4 - self.setup_clean_chain = False - def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/uptime.py b/test/functional/uptime.py index b20d6f5cb..78236b239 100755 --- a/test/functional/uptime.py +++ b/test/functional/uptime.py @@ -13,9 +13,7 @@ from test_framework.test_framework import BitcoinTestFramework class UptimeTest(BitcoinTestFramework): - def __init__(self): - super().__init__() - + def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True diff --git a/test/functional/wallet-accounts.py b/test/functional/wallet-accounts.py index 158aa9ae8..40726d2a7 100755 --- a/test/functional/wallet-accounts.py +++ b/test/functional/wallet-accounts.py @@ -17,9 +17,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal class WalletAccountsTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [[]] diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py index e0381b980..39b7164d6 100755 --- a/test/functional/wallet-dump.py +++ b/test/functional/wallet-dump.py @@ -56,10 +56,7 @@ def read_dump(file_name, addrs, hd_master_addr_old): class WalletDumpTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() - self.setup_clean_chain = False + def set_test_params(self): self.num_nodes = 1 self.extra_args = [["-keypool=90"]] diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index 2f38e6fee..f63bb2ea5 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -13,9 +13,7 @@ from test_framework.util import ( ) class WalletEncryptionTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py index 13b9dd9a9..68b5e5b8d 100755 --- a/test/functional/wallet-hd.py +++ b/test/functional/wallet-hd.py @@ -11,11 +11,8 @@ from test_framework.util import ( ) import shutil - class WalletHDTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.extra_args = [['-usehd=0'], ['-usehd=1', '-keypool=0']] diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 7190de94b..79727f9be 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -7,17 +7,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class WalletTest(BitcoinTestFramework): - - def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): - """Return curr_balance after asserting the fee was in range""" - fee = balance_with_fee - curr_balance - assert_fee_amount(fee, tx_size, fee_per_byte * 1000) - return curr_balance - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] def setup_network(self): @@ -30,8 +21,13 @@ class WalletTest(BitcoinTestFramework): connect_nodes_bi(self.nodes,0,2) self.sync_all([self.nodes[0:3]]) - def run_test(self): + def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): + """Return curr_balance after asserting the fee was in range""" + fee = balance_with_fee - curr_balance + assert_fee_amount(fee, tx_size, fee_per_byte * 1000) + return curr_balance + def run_test(self): # Check that there's no UTXO on none of the nodes assert_equal(len(self.nodes[0].listunspent()), 0) assert_equal(len(self.nodes[1].listunspent()), 0) diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index 688cd6d0c..36714164a 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -37,11 +37,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class WalletBackupTest(BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True - self.num_nodes = 4 # nodes 1, 2,3 are spenders, let's give them a keypool=100 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index 1005a4b95..c001517a6 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -20,9 +20,7 @@ from test_framework.util import (assert_equal, ) class ZapWalletTXesTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index b5a22ea07..3f2668ee8 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -13,9 +13,7 @@ from test_framework.util import (assert_equal, ) class ZMQTest (BitcoinTestFramework): - - def __init__(self): - super().__init__() + def set_test_params(self): self.num_nodes = 2 def setup_nodes(self): From 82bf6fc6d48a232cc0ceb54b136d86914f49013c Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 24 Aug 2017 11:11:56 -0400 Subject: [PATCH 13/37] [tests] Functional tests must explicitly set num_nodes Github-Pull: #11121 Rebased-From: 7148b74dc39110f53c665b94fa9d994c6ad6dc1c --- test/functional/example_test.py | 4 +++- test/functional/fundrawtransaction.py | 1 + test/functional/getblocktemplate_longpoll.py | 3 +++ test/functional/getchaintips.py | 3 +++ test/functional/listsinceblock.py | 1 + test/functional/listtransactions.py | 1 + test/functional/merkle_blocks.py | 1 + test/functional/p2p-segwit.py | 1 + test/functional/proxy_test.py | 3 +++ test/functional/receivedby.py | 1 + test/functional/test_framework/test_framework.py | 12 ++++++------ test/functional/txn_clone.py | 3 +++ test/functional/txn_doublespend.py | 2 ++ test/functional/wallet.py | 1 + test/functional/walletbackup.py | 1 + 15 files changed, 31 insertions(+), 7 deletions(-) diff --git a/test/functional/example_test.py b/test/functional/example_test.py index de8934f74..936aceb89 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -77,7 +77,9 @@ class ExampleTest(BitcoinTestFramework): # and setup_nodes() methods to customize the test setup as required. def set_test_params(self): - """Override any test parameters for your individual test.""" + """Override test parameters for your individual test. + + This method must be overridden and num_nodes must be exlicitly set.""" self.setup_clean_chain = True self.num_nodes = 3 # Use self.extra_args to change command-line arguments for the nodes diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index dec3d41bf..3326b58c4 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -16,6 +16,7 @@ def get_unspent(listunspent, amount): class RawTransactionsTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True def setup_network(self, split=False): diff --git a/test/functional/getblocktemplate_longpoll.py b/test/functional/getblocktemplate_longpoll.py index 85d256024..89768bd2f 100755 --- a/test/functional/getblocktemplate_longpoll.py +++ b/test/functional/getblocktemplate_longpoll.py @@ -23,6 +23,9 @@ class LongpollThread(threading.Thread): self.node.getblocktemplate({'longpollid':self.longpollid}) class GetBlockTemplateLPTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + def run_test(self): self.log.info("Warning: this test will take about 70 seconds in the best case. Be patient.") self.nodes[0].generate(10) diff --git a/test/functional/getchaintips.py b/test/functional/getchaintips.py index 00fc23c6b..21b67bfc6 100755 --- a/test/functional/getchaintips.py +++ b/test/functional/getchaintips.py @@ -14,6 +14,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal class GetChainTipsTest (BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def run_test (self): tips = self.nodes[0].getchaintips () assert_equal (len (tips), 1) diff --git a/test/functional/listsinceblock.py b/test/functional/listsinceblock.py index ed1315e80..6f428388e 100755 --- a/test/functional/listsinceblock.py +++ b/test/functional/listsinceblock.py @@ -9,6 +9,7 @@ from test_framework.util import assert_equal class ListSinceBlockTest (BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True def run_test(self): diff --git a/test/functional/listtransactions.py b/test/functional/listtransactions.py index 5ee85a0da..e4522cc3b 100755 --- a/test/functional/listtransactions.py +++ b/test/functional/listtransactions.py @@ -17,6 +17,7 @@ def txFromHex(hexstring): class ListTransactionsTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 2 self.enable_mocktime() def run_test(self): diff --git a/test/functional/merkle_blocks.py b/test/functional/merkle_blocks.py index 2125c6e17..a58334b2a 100755 --- a/test/functional/merkle_blocks.py +++ b/test/functional/merkle_blocks.py @@ -9,6 +9,7 @@ from test_framework.util import * class MerkleBlockTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True # Nodes 0/1 are "wallet" nodes, Nodes 2/3 are used for testing self.extra_args = [[], [], [], ["-txindex"]] diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 8c2d2f027..9bb72c819 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -34,6 +34,7 @@ def get_virtual_size(witness_block): class TestNode(NodeConnCB): def set_test_params(self): + self.num_nodes = 3 self.getdataset = set() def on_getdata(self, conn, message): diff --git a/test/functional/proxy_test.py b/test/functional/proxy_test.py index 26cb645da..81b99d1bf 100755 --- a/test/functional/proxy_test.py +++ b/test/functional/proxy_test.py @@ -42,6 +42,9 @@ from test_framework.netutil import test_ipv6_local RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports class ProxyTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def setup_nodes(self): self.have_ipv6 = test_ipv6_local() # Create two proxies on different ports diff --git a/test/functional/receivedby.py b/test/functional/receivedby.py index 48eb1c51b..db6fc86b8 100755 --- a/test/functional/receivedby.py +++ b/test/functional/receivedby.py @@ -24,6 +24,7 @@ def get_sub_array_from_array(object_array, to_match): class ReceivedByTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 2 self.enable_mocktime() def run_test(self): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index d860bc559..103651f17 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -48,11 +48,10 @@ BITCOIND_PROC_WAIT_TIMEOUT = 60 class BitcoinTestFramework(object): """Base class for a bitcoin test script. - Individual bitcoin test scripts should subclass this class and override the run_test() method. + Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods. Individual tests can also override the following methods to customize the test setup: - - set_test_params() - add_options() - setup_chain() - setup_network() @@ -64,12 +63,13 @@ class BitcoinTestFramework(object): def __init__(self): """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" - self.num_nodes = 4 self.setup_clean_chain = False self.nodes = [] self.mocktime = 0 self.set_test_params() + assert hasattr(self, "num_nodes"), "Test must set self.num_nodes in set_test_params()" + def main(self): """Main function. This should not be overridden by the subclass test scripts.""" @@ -177,8 +177,8 @@ class BitcoinTestFramework(object): # Methods to override in subclass test scripts. def set_test_params(self): - """Override this method to change default values for number of nodes, topology, etc""" - pass + """Tests must this method to change default values for number of nodes, topology, etc""" + raise NotImplementedError def add_options(self, parser): """Override this method to add command-line options to the test""" @@ -212,7 +212,7 @@ class BitcoinTestFramework(object): self.start_nodes() def run_test(self): - """Override this method to define test logic""" + """Tests must override this method to define test logic""" raise NotImplementedError # Public helper methods. These can be accessed by the subclass test scripts. diff --git a/test/functional/txn_clone.py b/test/functional/txn_clone.py index fc133050b..740bb2d4c 100755 --- a/test/functional/txn_clone.py +++ b/test/functional/txn_clone.py @@ -8,6 +8,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class TxnMallTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 + def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") diff --git a/test/functional/txn_doublespend.py b/test/functional/txn_doublespend.py index ff24fac25..69629ef95 100755 --- a/test/functional/txn_doublespend.py +++ b/test/functional/txn_doublespend.py @@ -8,6 +8,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * class TxnMallTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 4 def add_options(self, parser): parser.add_option("--mineblock", dest="mine_block", default=False, action="store_true", diff --git a/test/functional/wallet.py b/test/functional/wallet.py index 79727f9be..de3aa8a87 100755 --- a/test/functional/wallet.py +++ b/test/functional/wallet.py @@ -8,6 +8,7 @@ from test_framework.util import * class WalletTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True self.extra_args = [['-usehd={:d}'.format(i%2==0)] for i in range(4)] diff --git a/test/functional/walletbackup.py b/test/functional/walletbackup.py index 36714164a..15ea26afa 100755 --- a/test/functional/walletbackup.py +++ b/test/functional/walletbackup.py @@ -38,6 +38,7 @@ from test_framework.util import * class WalletBackupTest(BitcoinTestFramework): def set_test_params(self): + self.num_nodes = 4 self.setup_clean_chain = True # nodes 1, 2,3 are spenders, let's give them a keypool=100 self.extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] From cef03198dcdca63d88bf8f50edcc79fa6b268261 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 1 Sep 2017 14:24:30 -0400 Subject: [PATCH 14/37] [tests] fixups from set_test_params() Github-Pull: #11215 Rebased-From: 3918d93f3cd2305dc12cb964aebba0fc1f8720b4 --- test/functional/bitcoin_cli.py | 3 +-- test/functional/example_test.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/functional/bitcoin_cli.py b/test/functional/bitcoin_cli.py index 103320209..7acfede3f 100755 --- a/test/functional/bitcoin_cli.py +++ b/test/functional/bitcoin_cli.py @@ -8,8 +8,7 @@ from test_framework.util import assert_equal class TestBitcoinCli(BitcoinTestFramework): - def __init__(self): - super().__init__() + def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 936aceb89..228e15059 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -85,7 +85,7 @@ class ExampleTest(BitcoinTestFramework): # Use self.extra_args to change command-line arguments for the nodes self.extra_args = [[], ["-logips"], []] - # self.log.info("I've finished __init__") # Oops! Can't run self.log before run_test() + # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() # Use add_options() to add specific command-line options for your test. # In practice this is not used very much, since the tests are mostly written From 44241765e3c8caa9248949cbe0fbc1c3072319c0 Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Tue, 5 Sep 2017 19:55:37 +0300 Subject: [PATCH 15/37] Improve signmessages functional test This patch improves branch coverage of the test, making sure a message can not be verified with the wrong address or signature. Github-Pull: #11241 Rebased-From: b3d6fc654770e3b4d2f82e8d77e531df9e522982 --- test/functional/signmessages.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/test/functional/signmessages.py b/test/functional/signmessages.py index 5fdfeceb7..52ba6a5ad 100755 --- a/test/functional/signmessages.py +++ b/test/functional/signmessages.py @@ -5,6 +5,7 @@ """Test RPC commands for signing and verifying messages.""" from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal class SignMessagesTest(BitcoinTestFramework): def set_test_params(self): @@ -14,20 +15,24 @@ class SignMessagesTest(BitcoinTestFramework): def run_test(self): message = 'This is just a test message' - # Test the signing with a privkey - privKey = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' + self.log.info('test signing with priv_key') + priv_key = 'cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N' address = 'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB' - signature = self.nodes[0].signmessagewithprivkey(privKey, message) - - # Verify the message + expected_signature = 'INbVnW4e6PeRmsv2Qgu8NuopvrVjkcxob+sX8OcZG0SALhWybUjzMLPdAsXI46YZGb0KQTRii+wWIQzRpG/U+S0=' + signature = self.nodes[0].signmessagewithprivkey(priv_key, message) + assert_equal(expected_signature, signature) assert(self.nodes[0].verifymessage(address, signature, message)) - # Test the signing with an address with wallet + self.log.info('test signing with an address with wallet') address = self.nodes[0].getnewaddress() signature = self.nodes[0].signmessage(address, message) - - # Verify the message assert(self.nodes[0].verifymessage(address, signature, message)) + self.log.info('test verifying with another address should not work') + other_address = self.nodes[0].getnewaddress() + other_signature = self.nodes[0].signmessage(other_address, message) + assert(not self.nodes[0].verifymessage(other_address, signature, message)) + assert(not self.nodes[0].verifymessage(address, other_signature, message)) + if __name__ == '__main__': SignMessagesTest().main() From f0b67954f06e71eb2f4df0125b7075d8b36e0c6f Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Tue, 5 Sep 2017 15:02:17 +1200 Subject: [PATCH 16/37] Remove redundant testutil files Github-Pull: #11234 Rebased-From: d1138e36208dac87a27f415f39c70377636e93f1 --- src/Makefile.qttest.include | 6 ++---- src/Makefile.test.include | 2 -- src/qt/test/rpcnestedtests.cpp | 1 - src/test/test_bitcoin.cpp | 4 +--- src/test/testutil.cpp | 15 --------------- src/test/testutil.h | 15 --------------- 6 files changed, 3 insertions(+), 40 deletions(-) delete mode 100644 src/test/testutil.cpp delete mode 100644 src/test/testutil.h diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 02f30bc95..ea2ed1747 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -25,12 +25,10 @@ TEST_QT_H = \ qt/test/wallettests.h TEST_BITCOIN_CPP = \ - test/test_bitcoin.cpp \ - test/testutil.cpp + test/test_bitcoin.cpp TEST_BITCOIN_H = \ - test/test_bitcoin.h \ - test/testutil.h + test/test_bitcoin.h qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 6415b3d2e..01ab0134f 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -74,8 +74,6 @@ BITCOIN_TESTS =\ test/test_bitcoin.cpp \ test/test_bitcoin.h \ test/test_bitcoin_main.cpp \ - test/testutil.cpp \ - test/testutil.h \ test/timedata_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index e2abfb374..c1f71a6b4 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -11,7 +11,6 @@ #include "rpc/register.h" #include "rpc/server.h" #include "rpcconsole.h" -#include "test/testutil.h" #include "test/test_bitcoin.h" #include "univalue.h" #include "util.h" diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 94ec7c03f..194f62ca1 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -22,8 +22,6 @@ #include "rpc/register.h" #include "script/sigcache.h" -#include "test/testutil.h" - #include uint256 insecure_rand_seed = GetRandHash(); @@ -61,7 +59,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha RegisterAllCoreRPCCommands(tableRPC); ClearDatadirCache(); - pathTemp = GetTempPath() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); + pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin_%lu_%i", (unsigned long)GetTime(), (int)(InsecureRandRange(100000))); fs::create_directories(pathTemp); gArgs.ForceSetArg("-datadir", pathTemp.string()); diff --git a/src/test/testutil.cpp b/src/test/testutil.cpp deleted file mode 100644 index 591d0bf30..000000000 --- a/src/test/testutil.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009-2016 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "testutil.h" - -#ifdef WIN32 -#include -#endif - -#include "fs.h" - -fs::path GetTempPath() { - return fs::temp_directory_path(); -} diff --git a/src/test/testutil.h b/src/test/testutil.h deleted file mode 100644 index cbe784d64..000000000 --- a/src/test/testutil.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009-2016 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/** - * Utility functions shared by unit tests - */ -#ifndef BITCOIN_TEST_TESTUTIL_H -#define BITCOIN_TEST_TESTUTIL_H - -#include "fs.h" - -fs::path GetTempPath(); - -#endif // BITCOIN_TEST_TESTUTIL_H From f3f78917769b9bc65c133a160dba7df18a33b27d Mon Sep 17 00:00:00 2001 From: MeshCollider Date: Thu, 31 Aug 2017 11:15:48 +1200 Subject: [PATCH 17/37] Stop test_bitcoin-qt touching ~/.bitcoin Github-Pull: #11210 Rebased-From: dea086f498097d19a2c9acbfc753c9c2d68dbb03 --- src/qt/test/rpcnestedtests.cpp | 7 ------- src/qt/test/test_main.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/qt/test/rpcnestedtests.cpp b/src/qt/test/rpcnestedtests.cpp index c1f71a6b4..98a660519 100644 --- a/src/qt/test/rpcnestedtests.cpp +++ b/src/qt/test/rpcnestedtests.cpp @@ -36,11 +36,6 @@ void RPCNestedTests::rpcNestedTests() // do some test setup // could be moved to a more generic place when we add more tests on QT level tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]); - ClearDatadirCache(); - std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000))); - QDir dir(QString::fromStdString(path)); - dir.mkpath("."); - gArgs.ForceSetArg("-datadir", path); //mempool.setSanityCheck(1.0); TestingSetup test; @@ -135,6 +130,4 @@ void RPCNestedTests::rpcNestedTests() QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using , QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using , #endif - - fs::remove_all(fs::path(path)); } diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 1b28a285f..b5790e4e2 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -53,6 +53,10 @@ int main(int argc, char *argv[]) SetupNetworking(); SelectParams(CBaseChainParams::MAIN); noui_connect(); + ClearDatadirCache(); + fs::path pathTemp = fs::temp_directory_path() / strprintf("test_bitcoin-qt_%lu_%i", (unsigned long)GetTime(), (int)GetRand(100000)); + fs::create_directories(pathTemp); + gArgs.ForceSetArg("-datadir", pathTemp.string()); bool fInvalid = false; @@ -97,5 +101,7 @@ int main(int argc, char *argv[]) } #endif + fs::remove_all(pathTemp); + return fInvalid; } From eeb24a3a0157c41a0aae1d5561cf490abe378585 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 16 Aug 2017 08:52:24 -0700 Subject: [PATCH 18/37] [qa] TestNode: Add wait_until_stopped helper method Github-Pull: #11067 Rebased-From: faa8d9581affde35a8242c63fca8a52004d4f943 --- test/functional/blockchain.py | 4 +-- test/functional/fundrawtransaction.py | 2 +- .../test_framework/test_framework.py | 8 ++--- test/functional/test_framework/test_node.py | 30 +++++++++++-------- test/functional/wallet-encryption.py | 2 +- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py index 5d04de994..50be9262e 100755 --- a/test/functional/blockchain.py +++ b/test/functional/blockchain.py @@ -21,7 +21,7 @@ from decimal import Decimal import http.client import subprocess -from test_framework.test_framework import (BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT) +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises, @@ -141,7 +141,7 @@ class BlockchainTest(BitcoinTestFramework): except (ConnectionError, http.client.BadStatusLine): pass # The node already shut down before response self.log.debug('Node should stop at this height...') - self.nodes[0].process.wait(timeout=BITCOIND_PROC_WAIT_TIMEOUT) + self.nodes[0].wait_until_stopped() self.start_node(0) assert_equal(self.nodes[0].getblockcount(), 207) diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py index 3326b58c4..42d95dd52 100755 --- a/test/functional/fundrawtransaction.py +++ b/test/functional/fundrawtransaction.py @@ -4,7 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test the fundrawtransaction RPC.""" -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 103651f17..a53eb5179 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -43,8 +43,6 @@ TEST_EXIT_PASSED = 0 TEST_EXIT_FAILED = 1 TEST_EXIT_SKIPPED = 77 -BITCOIND_PROC_WAIT_TIMEOUT = 60 - class BitcoinTestFramework(object): """Base class for a bitcoin test script. @@ -263,8 +261,7 @@ class BitcoinTestFramework(object): def stop_node(self, i): """Stop a bitcoind test node""" self.nodes[i].stop_node() - while not self.nodes[i].is_node_stopped(): - time.sleep(0.1) + self.nodes[i].wait_until_stopped() def stop_nodes(self): """Stop multiple bitcoind test nodes""" @@ -274,8 +271,7 @@ class BitcoinTestFramework(object): for node in self.nodes: # Wait for nodes to stop - while not node.is_node_stopped(): - time.sleep(0.1) + node.wait_until_stopped() def assert_start_raises_init_error(self, i, extra_args=None, expected_msg=None): with tempfile.SpooledTemporaryFile(max_size=2**16) as log_stderr: diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index efb3ac9d1..f58a372a1 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -17,9 +17,12 @@ from .util import ( assert_equal, get_rpc_proxy, rpc_url, + wait_until, ) from .authproxy import JSONRPCException +BITCOIND_PROC_WAIT_TIMEOUT = 60 + class TestNode(): """A class for representing a bitcoind node under test. @@ -125,14 +128,20 @@ class TestNode(): if not self.running: return True return_code = self.process.poll() - if return_code is not None: - # process has stopped. Assert that it didn't return an error code. - assert_equal(return_code, 0) - self.running = False - self.process = None - self.log.debug("Node stopped") - return True - return False + if return_code is None: + return False + + # process has stopped. Assert that it didn't return an error code. + assert_equal(return_code, 0) + self.running = False + self.process = None + self.rpc_connected = False + self.rpc = None + self.log.debug("Node stopped") + return True + + def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): + wait_until(self.is_node_stopped, timeout=timeout) def node_encrypt_wallet(self, passphrase): """"Encrypts the wallet. @@ -140,10 +149,7 @@ class TestNode(): This causes bitcoind to shutdown, so this method takes care of cleaning up resources.""" self.encryptwallet(passphrase) - while not self.is_node_stopped(): - time.sleep(0.1) - self.rpc = None - self.rpc_connected = False + self.wait_until_stopped() class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" diff --git a/test/functional/wallet-encryption.py b/test/functional/wallet-encryption.py index f63bb2ea5..ce1e7744e 100755 --- a/test/functional/wallet-encryption.py +++ b/test/functional/wallet-encryption.py @@ -6,7 +6,7 @@ import time -from test_framework.test_framework import BitcoinTestFramework, BITCOIND_PROC_WAIT_TIMEOUT +from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_jsonrpc, From 812c87004311732da2fc8840a483be80c7a443ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:52:25 +0100 Subject: [PATCH 19/37] [test] Improve assert_raises_jsonrpc docstring Github-Pull: #11125 Rebased-From: e1274947d4574bb83a020d0e178f0e5db7fc6282 --- test/functional/test_framework/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index a14cda07d..a5bc495df 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -62,13 +62,13 @@ def assert_raises_jsonrpc(code, message, fun, *args, **kwds): Calls function `fun` with arguments `args` and `kwds`. Catches a JSONRPCException and verifies that the error code and message are as expected. Throws AssertionError if - no JSONRPCException was returned or if the error code/message are not as expected. + no JSONRPCException was raised or if the error code/message are not as expected. Args: code (int), optional: the error code returned by the RPC call (defined in src/rpc/protocol.h). Set to None if checking the error code is not required. message (string), optional: [a substring of] the error string returned by the - RPC call. Set to None if checking the error string is not required + RPC call. Set to None if checking the error string is not required. fun (function): the function to call. This should be the name of an RPC. args*: positional arguments for the function. kwds**: named arguments for the function. From e0bfd28de28efb1ffa84e89d76c144824dae987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 17:07:21 +0100 Subject: [PATCH 20/37] [test] Add support for custom arguments to TestNodeCLI Github-Pull: #11125 Rebased-From: 5c18a84b9a49e3f9dacf0502dbf7d5d755f38da6 --- test/functional/test_framework/test_node.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index f58a372a1..363025740 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -155,8 +155,16 @@ class TestNodeCLI(): """Interface to bitcoin-cli for an individual node""" def __init__(self, binary, datadir): + self.args = [] self.binary = binary self.datadir = datadir + self.input = None + + def __call__(self, *args, input=None): + # TestNodeCLI is callable with bitcoin-cli command-line args + self.args = [str(arg) for arg in args] + self.input = input + return self def __getattr__(self, command): def dispatcher(*args, **kwargs): @@ -169,9 +177,9 @@ class TestNodeCLI(): pos_args = [str(arg) for arg in args] named_args = [str(key) + "=" + str(value) for (key, value) in kwargs.items()] assert not (pos_args and named_args), "Cannot use positional arguments and named arguments in the same bitcoin-cli call" - p_args = [self.binary, "-datadir=" + self.datadir] + p_args = [self.binary, "-datadir=" + self.datadir] + self.args if named_args: p_args += ["-named"] p_args += [command] + pos_args + named_args - cli_output = subprocess.check_output(p_args, universal_newlines=True) + cli_output = subprocess.check_output(p_args, input=self.input, universal_newlines=True) return json.loads(cli_output, parse_float=decimal.Decimal) From e38211f5e8900ee9027c671d7c655958e4dbe8e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:35:57 +0100 Subject: [PATCH 21/37] [test] Add assert_raises_process_error to assert process errors Github-Pull: #11125 Rebased-From: 232e3e8471edb346c09f906c996b2f350cabc72a --- test/functional/test_framework/util.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index a5bc495df..b2d8199d1 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -12,6 +12,7 @@ import logging import os import random import re +from subprocess import CalledProcessError import time from . import coverage @@ -57,6 +58,30 @@ def assert_raises_message(exc, message, fun, *args, **kwds): else: raise AssertionError("No exception raised") +def assert_raises_process_error(returncode, output, fun, *args, **kwds): + """Execute a process and asserts the process return code and output. + + Calls function `fun` with arguments `args` and `kwds`. Catches a CalledProcessError + and verifies that the return code and output are as expected. Throws AssertionError if + no CalledProcessError was raised or if the return code and output are not as expected. + + Args: + returncode (int): the process return code. + output (string): [a substring of] the process output. + fun (function): the function to call. This should execute a process. + args*: positional arguments for the function. + kwds**: named arguments for the function. + """ + try: + fun(*args, **kwds) + except CalledProcessError as e: + if returncode != e.returncode: + raise AssertionError("Unexpected returncode %i" % e.returncode) + if output not in e.output: + raise AssertionError("Expected substring not found:" + e.output) + else: + raise AssertionError("No exception raised") + def assert_raises_jsonrpc(code, message, fun, *args, **kwds): """Run an RPC and verify that a specific JSONRPC exception code and message is raised. From 2b97b36e5d37c6935dce112f90213f4f49cd88ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Wed, 6 Sep 2017 16:36:13 +0100 Subject: [PATCH 22/37] [test] Replace check_output with low level version Github-Pull: #11125 Rebased-From: ce379b47b92d6c04250c21719bb1abfb41c586ad --- test/functional/test_framework/test_node.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 363025740..12dab57a0 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -181,5 +181,10 @@ class TestNodeCLI(): if named_args: p_args += ["-named"] p_args += [command] + pos_args + named_args - cli_output = subprocess.check_output(p_args, input=self.input, universal_newlines=True) - return json.loads(cli_output, parse_float=decimal.Decimal) + process = subprocess.Popen(p_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) + cli_stdout, cli_stderr = process.communicate(input=self.input) + returncode = process.poll() + if returncode: + # Ignore cli_stdout, raise with cli_stderr + raise subprocess.CalledProcessError(returncode, self.binary, output=cli_stderr) + return json.loads(cli_stdout, parse_float=decimal.Decimal) From d8dd8e7356b4109cfde48d2667ea4da29c849cf8 Mon Sep 17 00:00:00 2001 From: John Newbery Date: Mon, 4 Sep 2017 11:45:01 -0400 Subject: [PATCH 23/37] [tests] fixup dbcrash interaction with add_nodes() Github-Pull: #11230 Rebased-From: 8fdb6f9126fe1e13b60de11fd34c204247679ef4 --- test/functional/dbcrash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/dbcrash.py b/test/functional/dbcrash.py index 71424f641..24b9765b4 100755 --- a/test/functional/dbcrash.py +++ b/test/functional/dbcrash.py @@ -64,7 +64,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): def setup_network(self): # Need a bit of extra time for the nodes to start up for this test - self.add_nodes(self.num_nodes, timewait=90) + self.add_nodes(self.num_nodes, extra_args=self.extra_args, timewait=90) self.start_nodes() # Leave them unconnected, we'll use submitblock directly in this test From b6468d3c420f73627956fc94c9743d26d75af8b0 Mon Sep 17 00:00:00 2001 From: Cristian Mircea Messel Date: Wed, 13 Sep 2017 00:41:14 +0300 Subject: [PATCH 24/37] Add listwallets RPC test to multiwallet.py Github-Pull: #11310 Rebased-From: fb1f3258225a7052f4fc9e3f2accc3811c53e221 --- test/functional/multiwallet.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/multiwallet.py b/test/functional/multiwallet.py index e5453e9aa..b4e15a332 100755 --- a/test/functional/multiwallet.py +++ b/test/functional/multiwallet.py @@ -18,6 +18,8 @@ class MultiWalletTest(BitcoinTestFramework): self.extra_args = [['-wallet=w1', '-wallet=w2', '-wallet=w3']] def run_test(self): + assert_equal(set(self.nodes[0].listwallets()), {"w1", "w2", "w3"}) + self.stop_node(0) # should not initialize if there are duplicate wallets From 2e1ac70df97be758a2a9869104a81cb454008174 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 12 Sep 2017 17:20:26 +0200 Subject: [PATCH 25/37] [qa] zapwallettxes: Wait up to 3s for mempool reload Github-Pull: #11308 Rebased-From: fadd0c16b6bd62e9d663d906755320ae089e02d3 --- test/functional/zapwallettxes.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/functional/zapwallettxes.py b/test/functional/zapwallettxes.py index c001517a6..83b11035c 100755 --- a/test/functional/zapwallettxes.py +++ b/test/functional/zapwallettxes.py @@ -15,9 +15,11 @@ been zapped. """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import (assert_equal, - assert_raises_jsonrpc, - ) +from test_framework.util import ( + assert_equal, + assert_raises_jsonrpc, + wait_until, +) class ZapWalletTXesTest (BitcoinTestFramework): def set_test_params(self): @@ -56,6 +58,8 @@ class ZapWalletTXesTest (BitcoinTestFramework): self.stop_node(0) self.start_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) + wait_until(lambda: self.nodes[0].getmempoolinfo()['size'] == 1, timeout=3) + assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) From f1ced0d7761d1316c6b522b2b426e79833e4cbae Mon Sep 17 00:00:00 2001 From: John Newbery Date: Thu, 17 Aug 2017 11:35:45 -0400 Subject: [PATCH 26/37] [tests] Make p2p-leaktests.py more robust Github-Pull: #11078 Rebased-From: 0063d2c3dce9d9c1678197d2c65ee878793d1ef9 --- test/functional/p2p-leaktests.py | 9 +++++++-- test/functional/test_framework/mininode.py | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index f27086c97..1dc8f72cd 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -139,6 +139,9 @@ class P2PLeakTest(BitcoinTestFramework): [conn.disconnect_node() for conn in connections] + # Wait until all connections are closed + wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 0) + # Make sure no unexpected messages came in assert(no_version_bannode.unexpected_msg == False) assert(no_version_idlenode.unexpected_msg == False) @@ -157,8 +160,10 @@ class P2PLeakTest(BitcoinTestFramework): allowed_service_bit5_node.add_connection(connections[5]) allowed_service_bit7_node.add_connection(connections[6]) - wait_until(lambda: allowed_service_bit5_node.message_count["verack"], timeout=10, lock=mininode_lock) - wait_until(lambda: allowed_service_bit7_node.message_count["verack"], timeout=10, lock=mininode_lock) + NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it + + wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock) + wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock) if __name__ == '__main__': P2PLeakTest().main() diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index d0753276d..592453023 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1837,6 +1837,7 @@ class NetworkThread(Thread): disconnected.append(obj) [ obj.handle_close() for obj in disconnected ] asyncore.loop(0.1, use_poll=True, map=mininode_socket_map, count=1) + logger.debug("Network thread closing") # An exception we can raise if we detect a potential disconnect From f9cf7b589f430b2d7c52e477b6d62f29d748c38e Mon Sep 17 00:00:00 2001 From: John Newbery Date: Fri, 15 Sep 2017 14:36:12 -0400 Subject: [PATCH 27/37] [tests] Check connectivity before sending in assumevalid.py assumevalid.py would try to send over a closed P2P connection in a loop, hitting the following failure many times: TestFramework.mininode (ERROR): Cannot send message. No connection to node! The test still passes, but this is a lot of noise in the test log. Just check that the connection is open before trying to send. Github-Pull: #11345 Rebased-From: e9e9391083721ca9733cc00a1907384f83b6435e --- test/functional/assumevalid.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index beaf8c705..65685c48b 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -68,6 +68,8 @@ class AssumeValidTest(BitcoinTestFramework): def send_blocks_until_disconnected(self, node): """Keep sending blocks to the node until we're disconnected.""" for i in range(len(self.blocks)): + if not node.connection: + break try: node.send_message(msg_block(self.blocks[i])) except IOError as e: From 794a80eee335a10d239aed7fdbdd013bce45161d Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Fri, 18 Aug 2017 14:40:29 -0700 Subject: [PATCH 28/37] [script] Unit tests for script/standard functions Github-Pull: #11116 Rebased-From: d7afe2d1577eb3f6775301c81b94a191e0db99d9 --- src/Makefile.test.include | 1 + src/test/multisig_tests.cpp | 91 ------- src/test/script_standard_tests.cpp | 385 +++++++++++++++++++++++++++++ 3 files changed, 386 insertions(+), 91 deletions(-) create mode 100644 src/test/script_standard_tests.cpp diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 01ab0134f..3a932f460 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -65,6 +65,7 @@ BITCOIN_TESTS =\ test/scheduler_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ + test/script_standard_tests.cpp \ test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ test/sighash_tests.cpp \ diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index 5e89ef60d..de7f3b48f 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -16,8 +16,6 @@ #include -typedef std::vector valtype; - BOOST_FIXTURE_TEST_SUITE(multisig_tests, BasicTestingSetup) CScript @@ -173,95 +171,6 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard) BOOST_CHECK(!::IsStandard(malformed[i], whichType)); } -BOOST_AUTO_TEST_CASE(multisig_Solver1) -{ - // Tests Solver() that returns lists of keys that are - // required to satisfy a ScriptPubKey - // - // Also tests IsMine() and ExtractDestination() - // - // Note: ExtractDestination for the multisignature transactions - // always returns false for this release, even if you have - // one key that would satisfy an (a|b) or 2-of-3 keys needed - // to spend an escrow transaction. - // - CBasicKeyStore keystore, emptykeystore, partialkeystore; - CKey key[3]; - CTxDestination keyaddr[3]; - for (int i = 0; i < 3; i++) - { - key[i].MakeNewKey(true); - keystore.AddKey(key[i]); - keyaddr[i] = key[i].GetPubKey().GetID(); - } - partialkeystore.AddKey(key[0]); - - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 1); - CTxDestination addr; - BOOST_CHECK(ExtractDestination(s, addr)); - BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_DUP << OP_HASH160 << ToByteVector(key[0].GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 1); - CTxDestination addr; - BOOST_CHECK(ExtractDestination(s, addr)); - BOOST_CHECK(addr == keyaddr[0]); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4U); - CTxDestination addr; - BOOST_CHECK(!ExtractDestination(s, addr)); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_1 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK_EQUAL(solutions.size(), 4U); - std::vector addrs; - int nRequired; - BOOST_CHECK(ExtractDestinations(s, whichType, addrs, nRequired)); - BOOST_CHECK(addrs[0] == keyaddr[0]); - BOOST_CHECK(addrs[1] == keyaddr[1]); - BOOST_CHECK(nRequired == 1); - BOOST_CHECK(IsMine(keystore, s)); - BOOST_CHECK(!IsMine(emptykeystore, s)); - BOOST_CHECK(!IsMine(partialkeystore, s)); - } - { - std::vector solutions; - txnouttype whichType; - CScript s; - s << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << ToByteVector(key[2].GetPubKey()) << OP_3 << OP_CHECKMULTISIG; - BOOST_CHECK(Solver(s, whichType, solutions)); - BOOST_CHECK(solutions.size() == 5); - } -} - BOOST_AUTO_TEST_CASE(multisig_Sign) { // Test SignSignature() (and therefore the version of Solver() that signs transactions) diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp new file mode 100644 index 000000000..e6a63ad54 --- /dev/null +++ b/src/test/script_standard_tests.cpp @@ -0,0 +1,385 @@ +// Copyright (c) 2017 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "key.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/standard.h" +#include "test/test_bitcoin.h" + +#include + + +BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(script_standard_Solver_success) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript s; + txnouttype whichType; + std::vector > solutions; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0])); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript))); + + // TX_MULTISIG + s.clear(); + s << OP_1 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(solutions.size(), 4); + BOOST_CHECK(solutions[0] == std::vector({1})); + BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); + BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); + BOOST_CHECK(solutions[3] == std::vector({2})); + + s.clear(); + s << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + ToByteVector(pubkeys[2]) << + OP_3 << OP_CHECKMULTISIG; + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(solutions.size(), 5); + BOOST_CHECK(solutions[0] == std::vector({2})); + BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0])); + BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1])); + BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2])); + BOOST_CHECK(solutions[4] == std::vector({3})); + + // TX_NULL_DATA + solutions.clear(); + s.clear(); + s << OP_RETURN << + std::vector({0}) << + std::vector({75}) << + std::vector({255}); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA); + BOOST_CHECK_EQUAL(solutions.size(), 0); + + // TX_WITNESS_V0_KEYHASH + solutions.clear(); + s.clear(); + s << OP_0 << ToByteVector(pubkeys[0].GetID()); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID())); + + // TX_WITNESS_V0_SCRIPTHASH + uint256 scriptHash; + CSHA256().Write(&redeemScript[0], redeemScript.size()).Finalize(scriptHash.begin()); + + solutions.clear(); + s.clear(); + s << OP_0 << ToByteVector(scriptHash); + BOOST_CHECK(Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH); + BOOST_CHECK_EQUAL(solutions.size(), 1); + BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); + + // TX_NONSTANDARD + solutions.clear(); + s.clear(); + s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; + BOOST_CHECK(!Solver(s, whichType, solutions)); + BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD); +} + +BOOST_AUTO_TEST_CASE(script_standard_Solver_failure) +{ + CKey key; + CPubKey pubkey; + key.MakeNewKey(true); + pubkey = key.GetPubKey(); + + CScript s; + txnouttype whichType; + std::vector > solutions; + + // TX_PUBKEY with incorrectly sized pubkey + s.clear(); + s << std::vector(30, 0x01) << OP_CHECKSIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_PUBKEYHASH with incorrectly sized key hash + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_SCRIPTHASH with incorrectly sized script hash + s.clear(); + s << OP_HASH160 << std::vector(21, 0x01) << OP_EQUAL; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG 0/2 + s.clear(); + s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG 2/1 + s.clear(); + s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG n = 2 with 1 pubkey + s.clear(); + s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_MULTISIG n = 1 with 0 pubkeys + s.clear(); + s << OP_1 << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_NULL_DATA with other opcodes + s.clear(); + s << OP_RETURN << std::vector({75}) << OP_ADD; + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_WITNESS with unknown version + s.clear(); + s << OP_1 << ToByteVector(pubkey); + BOOST_CHECK(!Solver(s, whichType, solutions)); + + // TX_WITNESS with incorrect program size + s.clear(); + s << OP_0 << std::vector(19, 0x01); + BOOST_CHECK(!Solver(s, whichType, solutions)); +} + +BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) +{ + CKey key; + CPubKey pubkey; + key.MakeNewKey(true); + pubkey = key.GetPubKey(); + + CScript s; + CTxDestination address; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkey) << OP_CHECKSIG; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == pubkey.GetID()); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == pubkey.GetID()); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(ExtractDestination(s, address)); + BOOST_CHECK(boost::get(&address) && + *boost::get(&address) == CScriptID(redeemScript)); + + // TX_MULTISIG + s.clear(); + s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG; + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_NULL_DATA + s.clear(); + s << OP_RETURN << std::vector({75}); + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_WITNESS_V0_KEYHASH + s.clear(); + s << OP_0 << ToByteVector(pubkey); + BOOST_CHECK(!ExtractDestination(s, address)); + + // TX_WITNESS_V0_SCRIPTHASH + s.clear(); + s << OP_0 << ToByteVector(CScriptID(redeemScript)); + BOOST_CHECK(!ExtractDestination(s, address)); +} + +BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript s; + txnouttype whichType; + std::vector addresses; + int nRequired; + + // TX_PUBKEY + s.clear(); + s << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEY); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + + // TX_PUBKEYHASH + s.clear(); + s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + + // TX_SCRIPTHASH + CScript redeemScript(s); // initialize with leftover P2PKH script + s.clear(); + s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH); + BOOST_CHECK_EQUAL(addresses.size(), 1); + BOOST_CHECK_EQUAL(nRequired, 1); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == CScriptID(redeemScript)); + + // TX_MULTISIG + s.clear(); + s << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired)); + BOOST_CHECK_EQUAL(whichType, TX_MULTISIG); + BOOST_CHECK_EQUAL(addresses.size(), 2); + BOOST_CHECK_EQUAL(nRequired, 2); + BOOST_CHECK(boost::get(&addresses[0]) && + *boost::get(&addresses[0]) == pubkeys[0].GetID()); + BOOST_CHECK(boost::get(&addresses[1]) && + *boost::get(&addresses[1]) == pubkeys[1].GetID()); + + // TX_NULL_DATA + s.clear(); + s << OP_RETURN << std::vector({75}); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); + + // TX_WITNESS_V0_KEYHASH + s.clear(); + s << OP_0 << ToByteVector(pubkeys[0].GetID()); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); + + // TX_WITNESS_V0_SCRIPTHASH + s.clear(); + s << OP_0 << ToByteVector(CScriptID(redeemScript)); + BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired)); +} + +BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) +{ + CKey keys[3]; + CPubKey pubkeys[3]; + for (int i = 0; i < 3; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CScript expected, result; + + // CKeyID + expected.clear(); + expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + result = GetScriptForDestination(pubkeys[0].GetID()); + BOOST_CHECK(result == expected); + + // CScriptID + CScript redeemScript(result); + expected.clear(); + expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + result = GetScriptForDestination(CScriptID(redeemScript)); + BOOST_CHECK(result == expected); + + // CNoDestination + expected.clear(); + result = GetScriptForDestination(CNoDestination()); + BOOST_CHECK(result == expected); + + // GetScriptForRawPubKey + expected.clear(); + expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + result = GetScriptForRawPubKey(pubkeys[0]); + BOOST_CHECK(result == expected); + + // GetScriptForMultisig + expected.clear(); + expected << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + ToByteVector(pubkeys[2]) << + OP_3 << OP_CHECKMULTISIG; + result = GetScriptForMultisig(2, std::vector(pubkeys, pubkeys + 3)); + BOOST_CHECK(result == expected); + + // GetScriptForWitness + CScript witnessScript; + + witnessScript << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + expected.clear(); + expected << OP_0 << ToByteVector(pubkeys[0].GetID()); + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); + + witnessScript.clear(); + witnessScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); + + witnessScript.clear(); + witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()).Finalize(scriptHash.begin()); + + expected.clear(); + expected << OP_0 << ToByteVector(scriptHash); + result = GetScriptForWitness(witnessScript); + BOOST_CHECK(result == expected); +} + +BOOST_AUTO_TEST_SUITE_END() From 2c4ff35a8fce0c40884886a93c1bf12395fb105d Mon Sep 17 00:00:00 2001 From: Jim Posen Date: Tue, 22 Aug 2017 17:47:59 -0700 Subject: [PATCH 29/37] [script] Unit tests for IsMine Does not test watch-only addresses. Github-Pull: #11116 Rebased-From: 7a1e873b27b790c965d9927ecd465710dc103136 --- src/script/ismine.cpp | 2 + src/test/script_standard_tests.cpp | 367 ++++++++++++++++++++++++++++- 2 files changed, 363 insertions(+), 6 deletions(-) diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index 0a3961973..c3aade177 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -46,6 +46,8 @@ isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& i isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion) { + isInvalid = false; + std::vector vSolutions; txnouttype whichType; if (!Solver(scriptPubKey, whichType, vSolutions)) { diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index e6a63ad54..3d17a0dbb 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -3,6 +3,8 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "key.h" +#include "keystore.h" +#include "script/ismine.h" #include "script/script.h" #include "script/script_error.h" #include "script/standard.h" @@ -81,7 +83,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK(solutions[4] == std::vector({3})); // TX_NULL_DATA - solutions.clear(); s.clear(); s << OP_RETURN << std::vector({0}) << @@ -92,7 +93,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK_EQUAL(solutions.size(), 0); // TX_WITNESS_V0_KEYHASH - solutions.clear(); s.clear(); s << OP_0 << ToByteVector(pubkeys[0].GetID()); BOOST_CHECK(Solver(s, whichType, solutions)); @@ -102,9 +102,9 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) // TX_WITNESS_V0_SCRIPTHASH uint256 scriptHash; - CSHA256().Write(&redeemScript[0], redeemScript.size()).Finalize(scriptHash.begin()); + CSHA256().Write(&redeemScript[0], redeemScript.size()) + .Finalize(scriptHash.begin()); - solutions.clear(); s.clear(); s << OP_0 << ToByteVector(scriptHash); BOOST_CHECK(Solver(s, whichType, solutions)); @@ -113,7 +113,6 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success) BOOST_CHECK(solutions[0] == ToByteVector(scriptHash)); // TX_NONSTANDARD - solutions.clear(); s.clear(); s << OP_9 << OP_ADD << OP_11 << OP_EQUAL; BOOST_CHECK(!Solver(s, whichType, solutions)); @@ -374,7 +373,8 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG; uint256 scriptHash; - CSHA256().Write(&witnessScript[0], witnessScript.size()).Finalize(scriptHash.begin()); + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); expected.clear(); expected << OP_0 << ToByteVector(scriptHash); @@ -382,4 +382,359 @@ BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) BOOST_CHECK(result == expected); } +BOOST_AUTO_TEST_CASE(script_standard_IsMine) +{ + CKey keys[2]; + CPubKey pubkeys[2]; + for (int i = 0; i < 2; i++) { + keys[i].MakeNewKey(true); + pubkeys[i] = keys[i].GetPubKey(); + } + + CKey uncompressedKey; + uncompressedKey.MakeNewKey(false); + CPubKey uncompressedPubkey = uncompressedKey.GetPubKey(); + + CScript scriptPubKey; + isminetype result; + bool isInvalid; + + // P2PK compressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << ToByteVector(pubkeys[0]) << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PK uncompressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << ToByteVector(uncompressedPubkey) << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(uncompressedKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PKH compressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2PKH uncompressed + { + CBasicKeyStore keystore; + scriptPubKey.clear(); + scriptPubKey << OP_DUP << OP_HASH160 << ToByteVector(uncompressedPubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + // Keystore does not have key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key + keystore.AddKey(uncompressedKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2SH + { + CBasicKeyStore keystore; + + CScript redeemScript; + redeemScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG; + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore does not have redeemScript or key + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript but no key + keystore.AddCScript(redeemScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript and key + keystore.AddKey(keys[0]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WPKH compressed + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(pubkeys[0].GetID()); + + // Keystore has key, but no P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key and P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WPKH uncompressed + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(uncompressedPubkey.GetID()); + + // Keystore has key, but no P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has key and P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(isInvalid); + } + + // scriptPubKey multisig + { + CBasicKeyStore keystore; + + scriptPubKey.clear(); + scriptPubKey << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + // Keystore does not have any keys + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has 1/2 keys + keystore.AddKey(uncompressedKey); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has 2/2 keys + keystore.AddKey(keys[1]); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2SH multisig + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + keystore.AddKey(keys[1]); + + CScript redeemScript; + redeemScript << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore has no redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has redeemScript + keystore.AddCScript(redeemScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WSH multisig with compressed keys + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + keystore.AddKey(keys[1]); + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(scriptHash); + + // Keystore has keys, but no witnessScript or P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys and witnessScript, but no P2SH redeemScript + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // P2WSH multisig with uncompressed key + { + CBasicKeyStore keystore; + keystore.AddKey(uncompressedKey); + keystore.AddKey(keys[1]); + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(uncompressedPubkey) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + scriptPubKey.clear(); + scriptPubKey << OP_0 << ToByteVector(scriptHash); + + // Keystore has keys, but no witnessScript or P2SH redeemScript + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys and witnessScript, but no P2SH redeemScript + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddCScript(scriptPubKey); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(isInvalid); + } + + // P2WSH multisig wrapped in P2SH + { + CBasicKeyStore keystore; + + CScript witnessScript; + witnessScript << OP_2 << + ToByteVector(pubkeys[0]) << + ToByteVector(pubkeys[1]) << + OP_2 << OP_CHECKMULTISIG; + + uint256 scriptHash; + CSHA256().Write(&witnessScript[0], witnessScript.size()) + .Finalize(scriptHash.begin()); + + CScript redeemScript; + redeemScript << OP_0 << ToByteVector(scriptHash); + + scriptPubKey.clear(); + scriptPubKey << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL; + + // Keystore has no witnessScript, P2SH redeemScript, or keys + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has witnessScript and P2SH redeemScript, but no keys + keystore.AddCScript(redeemScript); + keystore.AddCScript(witnessScript); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + + // Keystore has keys, witnessScript, P2SH redeemScript + keystore.AddKey(keys[0]); + keystore.AddKey(keys[1]); + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); + BOOST_CHECK(!isInvalid); + } + + // OP_RETURN + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]); + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + } + + // Nonstandard + { + CBasicKeyStore keystore; + keystore.AddKey(keys[0]); + + scriptPubKey.clear(); + scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL; + + result = IsMine(keystore, scriptPubKey, isInvalid); + BOOST_CHECK_EQUAL(result, ISMINE_NO); + BOOST_CHECK(!isInvalid); + } +} + BOOST_AUTO_TEST_SUITE_END() From e4605d9dd498a1fa713e6a916347a7c887f2c2b8 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 7 Jun 2017 17:08:32 -0700 Subject: [PATCH 30/37] Tests for zmqpubrawtx and zmqpubrawblock Github-Pull: #10552 Rebased-From: d3677ab757ea57b21d8aed24d5bc3c4bfe9bb68c --- test/functional/test_framework/util.py | 8 ++++ test/functional/zmq_test.py | 52 +++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index b2d8199d1..64966adb9 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -7,6 +7,7 @@ from base64 import b64encode from binascii import hexlify, unhexlify from decimal import Decimal, ROUND_DOWN +import hashlib import json import logging import os @@ -173,6 +174,13 @@ def count_bytes(hex_string): def bytes_to_hex_str(byte_str): return hexlify(byte_str).decode('ascii') +def hash256(byte_str): + sha256 = hashlib.sha256() + sha256.update(byte_str) + sha256d = hashlib.sha256() + sha256d.update(sha256.digest()) + return sha256d.digest()[::-1] + def hex_str_to_bytes(hex_str): return unhexlify(hex_str.encode('ascii')) diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py index 3f2668ee8..382ef5bae 100755 --- a/test/functional/zmq_test.py +++ b/test/functional/zmq_test.py @@ -10,7 +10,8 @@ import struct from test_framework.test_framework import BitcoinTestFramework, SkipTest from test_framework.util import (assert_equal, bytes_to_hex_str, - ) + hash256, + ) class ZMQTest (BitcoinTestFramework): def set_test_params(self): @@ -37,9 +38,12 @@ class ZMQTest (BitcoinTestFramework): self.zmqSubSocket.set(zmq.RCVTIMEO, 60000) self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock") self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashtx") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawblock") + self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"rawtx") ip_address = "tcp://127.0.0.1:28332" self.zmqSubSocket.connect(ip_address) - self.extra_args = [['-zmqpubhashtx=%s' % ip_address, '-zmqpubhashblock=%s' % ip_address], []] + self.extra_args = [['-zmqpubhashblock=%s' % ip_address, '-zmqpubhashtx=%s' % ip_address, + '-zmqpubrawblock=%s' % ip_address, '-zmqpubrawtx=%s' % ip_address], []] self.add_nodes(self.num_nodes, self.extra_args) self.start_nodes() @@ -59,28 +63,51 @@ class ZMQTest (BitcoinTestFramework): msg = self.zmqSubSocket.recv_multipart() topic = msg[0] assert_equal(topic, b"hashtx") - body = msg[1] + txhash = msg[1] msgSequence = struct.unpack(' Date: Wed, 13 Sep 2017 09:17:15 -0400 Subject: [PATCH 31/37] qa: Treat mininode p2p exceptions as fatal Github-Pull: #11319 Rebased-From: a7820422e0b182db6f1df8904242e5d76d6c73fa --- test/functional/test_framework/mininode.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index 592453023..843b67cd5 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -1505,6 +1505,7 @@ class NodeConnCB(object): except: print("ERROR delivering %s (%s)" % (repr(message), sys.exc_info()[0])) + raise def set_deliver_sleep_time(self, value): with mininode_lock: @@ -1708,13 +1709,10 @@ class NodeConn(asyncore.dispatcher): self.cb.on_close(self) def handle_read(self): - try: - t = self.recv(8192) - if len(t) > 0: - self.recvbuf += t - self.got_data() - except: - pass + t = self.recv(8192) + if len(t) > 0: + self.recvbuf += t + self.got_data() def readable(self): return True @@ -1780,8 +1778,10 @@ class NodeConn(asyncore.dispatcher): self.got_message(t) else: logger.warning("Received unknown command from %s:%d: '%s' %s" % (self.dstaddr, self.dstport, command, repr(msg))) + raise ValueError("Unknown command: '%s'" % (command)) except Exception as e: logger.exception('got_data:', repr(e)) + raise def send_message(self, message, pushbuf=False): if self.state != "connected" and not pushbuf: From 8d2e51d86253881abadb5b11f93b12e3761f6232 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 13 Sep 2017 09:21:27 -0400 Subject: [PATCH 32/37] qa: Fix bug introduced in p2p-segwit.py Changing __init__() -> set_test_params() in the tests should not have applied to NodeConnCB-derived objects. Github-Pull: #11319 Rebased-From: f97ab35fa9687fd5c110ad6cca5be5b4a5c2142d --- test/functional/p2p-segwit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 9bb72c819..9105f0ee0 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -33,8 +33,8 @@ def get_virtual_size(witness_block): return vsize class TestNode(NodeConnCB): - def set_test_params(self): - self.num_nodes = 3 + def __init__(self): + super().__init__() self.getdataset = set() def on_getdata(self, conn, message): From a36f3320a94aa70328e133d53146fc1ef57e1e34 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Fri, 29 Sep 2017 17:33:50 -0400 Subject: [PATCH 33/37] Verify DBWrapper iterators are taking snapshots The LevelDB docs seem to indicate that an iterator will not take snapshots (even providing instructions on how to do so yourself). In several of the places we use them, we assume snapshots to have been taken. In order to make sure LevelDB doesn't change out from under us (and to prevent the next person who reads the docs from having the same fright I did), verify that snapshots are taken in our tests. Github-Pull: #11422 Rebased-From: bb8376bbc3d96af727444f90e5f60d47105609dc --- src/test/dbwrapper_tests.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 6ed6e7744..d90fe5027 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -204,19 +204,31 @@ BOOST_AUTO_TEST_CASE(iterator_ordering) for (int x=0x00; x<256; ++x) { uint8_t key = x; uint32_t value = x*x; - BOOST_CHECK(dbw.Write(key, value)); + if (!(x & 1)) BOOST_CHECK(dbw.Write(key, value)); } + // Check that creating an iterator creates a snapshot std::unique_ptr it(const_cast(dbw).NewIterator()); + + for (int x=0x00; x<256; ++x) { + uint8_t key = x; + uint32_t value = x*x; + if (x & 1) BOOST_CHECK(dbw.Write(key, value)); + } + for (int seek_start : {0x00, 0x80}) { it->Seek((uint8_t)seek_start); - for (int x=seek_start; x<256; ++x) { + for (int x=seek_start; x<255; ++x) { uint8_t key; uint32_t value; BOOST_CHECK(it->Valid()); if (!it->Valid()) // Avoid spurious errors about invalid iterator's key and value in case of failure break; BOOST_CHECK(it->GetKey(key)); + if (x & 1) { + BOOST_CHECK_EQUAL(key, x + 1); + continue; + } BOOST_CHECK(it->GetValue(value)); BOOST_CHECK_EQUAL(key, x); BOOST_CHECK_EQUAL(value, x*x); From a825d4af5e3ca353bce421e966ddcb9fc643075c Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Mon, 25 Sep 2017 18:14:03 +0800 Subject: [PATCH 34/37] Fix bip68-sequence rpc test Github-Pull: #11399 Rebased-From: 49f869fe91716785b3276925d64bf8955feff69f --- test/functional/bip68-sequence.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/functional/bip68-sequence.py b/test/functional/bip68-sequence.py index 39012adf9..1391b9ed4 100755 --- a/test/functional/bip68-sequence.py +++ b/test/functional/bip68-sequence.py @@ -369,11 +369,14 @@ class BIP68Test(BitcoinTestFramework): def activateCSV(self): # activation should happen at block height 432 (3 periods) + # getblockchaininfo will show CSV as active at block 431 (144 * 3 -1) since it's returning whether CSV is active for the next block. min_activation_height = 432 height = self.nodes[0].getblockcount() - assert(height < min_activation_height) - self.nodes[0].generate(min_activation_height-height) - assert(get_bip9_status(self.nodes[0], 'csv')['status'] == 'active') + assert_greater_than(min_activation_height - height, 2) + self.nodes[0].generate(min_activation_height - height - 2) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "locked_in") + self.nodes[0].generate(1) + assert_equal(get_bip9_status(self.nodes[0], 'csv')['status'], "active") sync_blocks(self.nodes) # Use self.nodes[1] to test that version 2 transactions are standard. From 806c78f014f6be9e12afb181d85e135f3b44e33e Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Tue, 26 Sep 2017 17:24:26 -0400 Subject: [PATCH 35/37] add functional test for mempoolreplacement command line arg Github-Pull: #11407 Rebased-From: 1088b5322d0e7a8366a285e2baa49c766a9ba5bd --- test/functional/replace-by-fee.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/functional/replace-by-fee.py b/test/functional/replace-by-fee.py index 220e88968..5e1f33991 100755 --- a/test/functional/replace-by-fee.py +++ b/test/functional/replace-by-fee.py @@ -62,13 +62,14 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])): class ReplaceByFeeTest(BitcoinTestFramework): def set_test_params(self): - self.num_nodes = 1 + self.num_nodes = 2 self.extra_args= [["-maxorphantx=1000", "-whitelist=127.0.0.1", "-limitancestorcount=50", "-limitancestorsize=101", "-limitdescendantcount=200", - "-limitdescendantsize=101"]] + "-limitdescendantsize=101"], + ["-mempoolreplacement=0"]] def run_test(self): make_utxo(self.nodes[0], 1*COIN) @@ -115,6 +116,8 @@ class ReplaceByFeeTest(BitcoinTestFramework): tx1a_hex = txToHex(tx1a) tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, True) + self.sync_all([self.nodes]) + # Should fail because we haven't changed the fee tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] @@ -123,12 +126,17 @@ class ReplaceByFeeTest(BitcoinTestFramework): # This will raise an exception due to insufficient fee assert_raises_jsonrpc(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx1b_hex, True) + # This will raise an exception due to transaction replacement being disabled + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) # Extra 0.1 BTC fee tx1b = CTransaction() tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)] tx1b.vout = [CTxOut(int(0.9*COIN), CScript([b'b']))] tx1b_hex = txToHex(tx1b) + # Replacement still disabled even with "enough fee" + assert_raises_jsonrpc(-26, "txn-mempool-conflict", self.nodes[1].sendrawtransaction, tx1b_hex, True) + # Works when enabled tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, True) mempool = self.nodes[0].getrawmempool() @@ -138,6 +146,11 @@ class ReplaceByFeeTest(BitcoinTestFramework): assert_equal(tx1b_hex, self.nodes[0].getrawtransaction(tx1b_txid)) + # Second node is running mempoolreplacement=0, will not replace originally-seen txn + mempool = self.nodes[1].getrawmempool() + assert tx1a_txid in mempool + assert tx1b_txid not in mempool + def test_doublespend_chain(self): """Doublespend of a long chain""" From e169349f8c25d8998492b38500c1fee1074ed6fe Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Sun, 1 Oct 2017 11:19:49 +0200 Subject: [PATCH 36/37] qa: Restore bitcoin-util-test py2 compatibility Github-Pull: #11433 Rebased-From: fafff1220cf798e25f02cdd8affb70506dd366cc --- src/Makefile.test.include | 2 +- test/util/bitcoin-util-test.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 3a932f460..b48bfc76b 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -147,7 +147,7 @@ bitcoin_test_clean : FORCE check-local: @echo "Running test/util/bitcoin-util-test.py..." - $(top_builddir)/test/util/bitcoin-util-test.py + $(PYTHON) $(top_builddir)/test/util/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check if EMBEDDED_UNIVALUE $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue check diff --git a/test/util/bitcoin-util-test.py b/test/util/bitcoin-util-test.py index d15d6a601..ef34955d9 100755 --- a/test/util/bitcoin-util-test.py +++ b/test/util/bitcoin-util-test.py @@ -9,9 +9,14 @@ Runs automatically during `make check`. Can also be run manually.""" +from __future__ import division,print_function,unicode_literals + import argparse import binascii -import configparser +try: + import configparser +except ImportError: + import ConfigParser as configparser import difflib import json import logging @@ -22,7 +27,9 @@ import sys def main(): config = configparser.ConfigParser() - config.read_file(open(os.path.dirname(__file__) + "/../config.ini")) + config.optionxform = str + config.readfp(open(os.path.join(os.path.dirname(__file__), "../config.ini"))) + env_conf = dict(config.items('environment')) parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('-v', '--verbose', action='store_true') @@ -37,7 +44,7 @@ def main(): # Add the format/level to the logger logging.basicConfig(format=formatter, level=level) - bctester(config["environment"]["SRCDIR"] + "/test/util/data", "bitcoin-util-test.json", config["environment"]) + bctester(os.path.join(env_conf["SRCDIR"], "test/util/data"), "bitcoin-util-test.json", env_conf) def bctester(testDir, input_basename, buildenv): """ Loads and parses the input file, runs all tests and reports results""" From 019c492490077a7581ab526b4208439200cbff24 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 2 Oct 2017 13:35:08 +0200 Subject: [PATCH 37/37] qa: Fix lcov for out-of-tree builds Github-Pull: #11443 Rebased-From: fae60e338639b3a09d2f26d8eb5feb3bb576b1fd --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 71e22dc28..e8aa7d5ae 100644 --- a/configure.ac +++ b/configure.ac @@ -1231,6 +1231,7 @@ AC_SUBST(QR_LIBS) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist test/config.ini]) AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh]) AC_CONFIG_FILES([doc/Doxyfile]) +AC_CONFIG_LINKS([contrib/filter-lcov.py:contrib/filter-lcov.py]) AC_CONFIG_LINKS([test/functional/test_runner.py:test/functional/test_runner.py]) AC_CONFIG_LINKS([test/util/bitcoin-util-test.py:test/util/bitcoin-util-test.py])