aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/assumevalid.py10
-rwxr-xr-xtest/functional/bip9-softforks.py10
-rwxr-xr-xtest/functional/blockchain.py14
-rwxr-xr-xtest/functional/bumpfee.py1
-rwxr-xr-xtest/functional/disconnect_ban.py109
-rwxr-xr-xtest/functional/forknotify.py15
-rwxr-xr-xtest/functional/fundrawtransaction.py4
-rwxr-xr-xtest/functional/importmulti.py2
-rwxr-xr-xtest/functional/keypool.py41
-rwxr-xr-xtest/functional/maxblocksinflight.py97
-rwxr-xr-xtest/functional/maxuploadtarget.py11
-rwxr-xr-xtest/functional/mempool_packages.py12
-rwxr-xr-xtest/functional/net.py67
-rwxr-xr-xtest/functional/nodehandling.py80
-rwxr-xr-xtest/functional/p2p-acceptblock.py17
-rwxr-xr-xtest/functional/p2p-compactblocks.py27
-rwxr-xr-xtest/functional/p2p-feefilter.py4
-rwxr-xr-xtest/functional/p2p-fullblocktest.py4
-rwxr-xr-xtest/functional/p2p-leaktests.py2
-rwxr-xr-xtest/functional/p2p-mempool.py11
-rwxr-xr-xtest/functional/p2p-segwit.py37
-rwxr-xr-xtest/functional/p2p-timeouts.py4
-rwxr-xr-xtest/functional/p2p-versionbits-warning.py17
-rwxr-xr-xtest/functional/sendheaders.py4
-rw-r--r--test/functional/test_framework/blocktools.py11
-rwxr-xr-xtest/functional/test_framework/comptool.py2
-rwxr-xr-xtest/functional/test_framework/mininode.py142
-rw-r--r--test/functional/test_framework/util.py2
-rwxr-xr-xtest/functional/test_runner.py166
-rwxr-xr-xtest/functional/wallet-dump.py6
-rwxr-xr-xtest/functional/wallet-hd.py19
-rwxr-xr-xtest/functional/zmq_test.py21
33 files changed, 544 insertions, 427 deletions
diff --git a/test/functional/README.md b/test/functional/README.md
index 651b01f18a..e6c4849702 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -59,7 +59,7 @@ thread.)
* RPC calls are available in p2p tests.
* Can be used to write free-form tests, where specific p2p-protocol behavior
-is tested. Examples: ```p2p-accept-block.py```, ```maxblocksinflight.py```.
+is tested. Examples: ```p2p-accept-block.py```, ```p2p-compactblocks.py```.
## Comptool
diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py
index da680a5d24..8e301c4379 100755
--- a/test/functional/assumevalid.py
+++ b/test/functional/assumevalid.py
@@ -40,17 +40,14 @@ from test_framework.mininode import (CBlockHeader,
CTxOut,
NetworkThread,
NodeConn,
- SingleNodeConnCB,
+ NodeConnCB,
msg_block,
msg_headers)
from test_framework.script import (CScript, OP_TRUE)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (start_node, p2p_port, assert_equal)
-class BaseNode(SingleNodeConnCB):
- def __init__(self):
- super().__init__()
-
+class BaseNode(NodeConnCB):
def send_header_for_blocks(self, new_blocks):
headers_message = msg_headers()
headers_message.headers = [CBlockHeader(b) for b in new_blocks]
@@ -193,7 +190,8 @@ class AssumeValidTest(BitcoinTestFramework):
# Send all blocks to node1. All blocks will be accepted.
for i in range(2202):
node1.send_message(msg_block(self.blocks[i]))
- node1.sync_with_ping() # make sure the most recent block is synced
+ # Syncing 2200 blocks can take a while on slow systems. Give it plenty of time to sync.
+ node1.sync_with_ping(120)
assert_equal(self.nodes[1].getblock(self.nodes[1].getbestblockhash())['height'], 2202)
# Send blocks to node2. Block 102 will be rejected.
diff --git a/test/functional/bip9-softforks.py b/test/functional/bip9-softforks.py
index 0dffd06e1a..60d262da81 100755
--- a/test/functional/bip9-softforks.py
+++ b/test/functional/bip9-softforks.py
@@ -200,16 +200,14 @@ class BIP9SoftForksTest(ComparisonTestFramework):
yield TestInstance([[block, False]])
# Restart all
- self.test.block_store.close()
+ self.test.clear_all_connections()
stop_nodes(self.nodes)
- shutil.rmtree(self.options.tmpdir)
+ shutil.rmtree(self.options.tmpdir + "/node0")
self.setup_chain()
self.setup_network()
- self.test.block_store = BlockStore(self.options.tmpdir)
- self.test.clear_all_connections()
self.test.add_all_connections(self.nodes)
- NetworkThread().start() # Start up network handling in another thread
-
+ NetworkThread().start()
+ self.test.test_nodes[0].wait_for_verack()
def get_tests(self):
for test in itertools.chain(
diff --git a/test/functional/blockchain.py b/test/functional/blockchain.py
index 596aed50ec..de5e01c2e3 100755
--- a/test/functional/blockchain.py
+++ b/test/functional/blockchain.py
@@ -6,6 +6,10 @@
Test the following RPCs:
- gettxoutsetinfo
+ - getdifficulty
+ - getbestblockhash
+ - getblockhash
+ - getblockheader
- verifychain
Tests correspond to code in rpc/blockchain.cpp.
@@ -40,6 +44,7 @@ class BlockchainTest(BitcoinTestFramework):
def run_test(self):
self._test_gettxoutsetinfo()
self._test_getblockheader()
+ self._test_getdifficulty()
self.nodes[0].verifychain(4, 0)
def _test_gettxoutsetinfo(self):
@@ -57,7 +62,8 @@ class BlockchainTest(BitcoinTestFramework):
def _test_getblockheader(self):
node = self.nodes[0]
- assert_raises_jsonrpc(-5, "Block not found", node.getblockheader, "nonsense")
+ assert_raises_jsonrpc(-5, "Block not found",
+ node.getblockheader, "nonsense")
besthash = node.getbestblockhash()
secondbesthash = node.getblockhash(199)
@@ -79,5 +85,11 @@ class BlockchainTest(BitcoinTestFramework):
assert isinstance(int(header['versionHex'], 16), int)
assert isinstance(header['difficulty'], Decimal)
+ def _test_getdifficulty(self):
+ difficulty = self.nodes[0].getdifficulty()
+ # 1 hash in 2 should be valid, so difficulty should be 1/2**31
+ # binary => decimal => binary math is why we do this check
+ assert abs(difficulty * 2**31 - 1) < 0.0001
+
if __name__ == '__main__':
BlockchainTest().main()
diff --git a/test/functional/bumpfee.py b/test/functional/bumpfee.py
index 172e414188..c51a75cc26 100755
--- a/test/functional/bumpfee.py
+++ b/test/functional/bumpfee.py
@@ -196,7 +196,6 @@ def test_dust_to_fee(rbf_node, dest_address):
def test_settxfee(rbf_node, dest_address):
# check that bumpfee reacts correctly to the use of settxfee (paytxfee)
rbfid = spend_one_input(rbf_node, dest_address)
- rbftx = rbf_node.gettransaction(rbfid)
requested_feerate = Decimal("0.00025000")
rbf_node.settxfee(requested_feerate)
bumped_tx = rbf_node.bumpfee(rbfid)
diff --git a/test/functional/disconnect_ban.py b/test/functional/disconnect_ban.py
new file mode 100755
index 0000000000..3f451d49d2
--- /dev/null
+++ b/test/functional/disconnect_ban.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-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.
+"""Test node disconnect and ban behavior"""
+
+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,
+ start_node,
+ stop_node,
+ )
+
+class DisconnectBanTest(BitcoinTestFramework):
+
+ def __init__(self):
+ super().__init__()
+ self.num_nodes = 2
+ self.setup_clean_chain = False
+
+ def setup_network(self):
+ self.nodes = self.setup_nodes()
+ connect_nodes_bi(self.nodes, 0, 1)
+
+ def run_test(self):
+ self.log.info("Test setban and listbanned RPCs")
+
+ 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")
+ wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0)
+ assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+
+ self.log.info("clearbanned: successfully clear ban list")
+ self.nodes[1].clearbanned()
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+ self.nodes[1].setban("127.0.0.0/24", "add")
+
+ self.log.info("setban: fail to ban an already banned subnet")
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+ assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[1].setban, "127.0.0.1", "add")
+
+ self.log.info("setban: fail to ban an invalid subnet")
+ assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[1].setban, "127.0.0.1/42", "add")
+ assert_equal(len(self.nodes[1].listbanned()), 1) # still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
+
+ self.log.info("setban remove: fail to unban a non-banned subnet")
+ assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[1].setban, "127.0.0.1", "remove")
+ assert_equal(len(self.nodes[1].listbanned()), 1)
+
+ self.log.info("setban remove: successfully unban subnet")
+ self.nodes[1].setban("127.0.0.0/24", "remove")
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+ self.nodes[1].clearbanned()
+ assert_equal(len(self.nodes[1].listbanned()), 0)
+
+ self.log.info("setban: test persistence across node restart")
+ self.nodes[1].setban("127.0.0.0/32", "add")
+ self.nodes[1].setban("127.0.0.0/24", "add")
+ self.nodes[1].setban("192.168.0.1", "add", 1) # ban for 1 seconds
+ self.nodes[1].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) # ban for 1000 seconds
+ listBeforeShutdown = self.nodes[1].listbanned()
+ assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address'])
+ wait_until(lambda: len(self.nodes[1].listbanned()) == 3)
+
+ stop_node(self.nodes[1], 1)
+
+ self.nodes[1] = 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'])
+ assert_equal("/19" in listAfterShutdown[2]['address'], True)
+
+ # Clear ban lists
+ self.nodes[1].clearbanned()
+ connect_nodes_bi(self.nodes, 0, 1)
+
+ self.log.info("Test disconnectrnode RPCs")
+
+ self.log.info("disconnectnode: fail to disconnect when calling with address and nodeid")
+ address1 = self.nodes[0].getpeerinfo()[0]['addr']
+ node1 = self.nodes[0].getpeerinfo()[0]['addr']
+ assert_raises_jsonrpc(-32602, "Only one of address and nodeid should be provided.", self.nodes[0].disconnectnode, address=address1, nodeid=node1)
+
+ self.log.info("disconnectnode: fail to disconnect when calling with junk address")
+ assert_raises_jsonrpc(-29, "Node not found in connected nodes", self.nodes[0].disconnectnode, address="221B Baker Street")
+
+ self.log.info("disconnectnode: successfully disconnect node by address")
+ address1 = self.nodes[0].getpeerinfo()[0]['addr']
+ self.nodes[0].disconnectnode(address=address1)
+ wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1)
+ assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
+
+ self.log.info("disconnectnode: successfully reconnect node")
+ connect_nodes_bi(self.nodes, 0, 1) # reconnect the node
+ assert_equal(len(self.nodes[0].getpeerinfo()), 2)
+ assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1]
+
+ self.log.info("disconnectnode: successfully disconnect node by node id")
+ id1 = self.nodes[0].getpeerinfo()[0]['id']
+ self.nodes[0].disconnectnode(nodeid=id1)
+ wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1)
+ assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1]
+
+if __name__ == '__main__':
+ DisconnectBanTest().main()
diff --git a/test/functional/forknotify.py b/test/functional/forknotify.py
index c2724ba5df..7a365438cc 100755
--- a/test/functional/forknotify.py
+++ b/test/functional/forknotify.py
@@ -3,6 +3,8 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the -alertnotify option."""
+import os
+import time
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -41,12 +43,19 @@ class ForkNotifyTest(BitcoinTestFramework):
self.nodes[1].generate(1)
self.sync_all()
+ # Give bitcoind 10 seconds to write the alert notification
+ timeout = 10.0
+ while timeout > 0:
+ if os.path.exists(self.alert_filename) and os.path.getsize(self.alert_filename):
+ break
+ time.sleep(0.1)
+ timeout -= 0.1
+ else:
+ assert False, "-alertnotify did not warn of up-version blocks"
+
with open(self.alert_filename, 'r', encoding='utf8') as f:
alert_text = f.read()
- if len(alert_text) == 0:
- raise AssertionError("-alertnotify did not warn of up-version blocks")
-
# Mine more up-version blocks, should not get more alerts:
self.nodes[1].generate(1)
self.sync_all()
diff --git a/test/functional/fundrawtransaction.py b/test/functional/fundrawtransaction.py
index 3bfc05d37b..b86ea2d877 100755
--- a/test/functional/fundrawtransaction.py
+++ b/test/functional/fundrawtransaction.py
@@ -467,6 +467,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# drain the keypool
self.nodes[1].getnewaddress()
+ self.nodes[1].getrawchangeaddress()
inputs = []
outputs = {self.nodes[0].getnewaddress():1.1}
rawtx = self.nodes[1].createrawtransaction(inputs, outputs)
@@ -476,6 +477,7 @@ class RawTransactionsTest(BitcoinTestFramework):
#refill the keypool
self.nodes[1].walletpassphrase("test", 100)
+ self.nodes[1].keypoolrefill(8) #need to refill the keypool to get an internal change address
self.nodes[1].walletlock()
assert_raises_jsonrpc(-13, "walletpassphrase", self.nodes[1].sendtoaddress, self.nodes[0].getnewaddress(), 1.2)
@@ -644,7 +646,7 @@ class RawTransactionsTest(BitcoinTestFramework):
if out['value'] > 1.0:
changeaddress += out['scriptPubKey']['addresses'][0]
assert(changeaddress != "")
- nextaddr = self.nodes[3].getnewaddress()
+ nextaddr = self.nodes[3].getrawchangeaddress()
# frt should not have removed the key from the keypool
assert(changeaddress == nextaddr)
diff --git a/test/functional/importmulti.py b/test/functional/importmulti.py
index aa03c6780a..e049302632 100755
--- a/test/functional/importmulti.py
+++ b/test/functional/importmulti.py
@@ -434,7 +434,7 @@ class ImportMultiTest (BitcoinTestFramework):
address_assert = self.nodes[1].validateaddress(watchonly_address)
assert_equal(address_assert['iswatchonly'], True)
assert_equal(address_assert['ismine'], False)
- assert_equal(address_assert['timestamp'], watchonly_timestamp);
+ assert_equal(address_assert['timestamp'], watchonly_timestamp)
# Bad or missing timestamps
self.log.info("Should throw on invalid or missing timestamp values")
diff --git a/test/functional/keypool.py b/test/functional/keypool.py
index cee58563f0..cb9ab688d1 100755
--- a/test/functional/keypool.py
+++ b/test/functional/keypool.py
@@ -27,28 +27,42 @@ class KeyPoolTest(BitcoinTestFramework):
wallet_info = nodes[0].getwalletinfo()
assert(addr_before_encrypting_data['hdmasterkeyid'] != wallet_info['hdmasterkeyid'])
assert(addr_data['hdmasterkeyid'] == wallet_info['hdmasterkeyid'])
-
assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
- # put three new keys in the keypool
+ # put six (plus 2) new keys in the keypool (100% external-, +100% internal-keys, 1 in min)
nodes[0].walletpassphrase('test', 12000)
- nodes[0].keypoolrefill(3)
+ nodes[0].keypoolrefill(6)
nodes[0].walletlock()
+ wi = nodes[0].getwalletinfo()
+ assert_equal(wi['keypoolsize_hd_internal'], 6)
+ assert_equal(wi['keypoolsize'], 6)
- # drain the keys
+ # drain the internal keys
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
+ nodes[0].getrawchangeaddress()
addr = set()
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- # assert that four unique addresses were returned
- assert(len(addr) == 4)
# the next one should fail
assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].getrawchangeaddress)
+ # drain the external keys
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ addr.add(nodes[0].getnewaddress())
+ assert(len(addr) == 6)
+ # the next one should fail
+ assert_raises_jsonrpc(-12, "Error: Keypool ran out, please call keypoolrefill first", nodes[0].getnewaddress)
+
# refill keypool with three new addresses
nodes[0].walletpassphrase('test', 1)
nodes[0].keypoolrefill(3)
+
# test walletpassphrase timeout
time.sleep(1.1)
assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0)
@@ -57,9 +71,14 @@ class KeyPoolTest(BitcoinTestFramework):
nodes[0].generate(1)
nodes[0].generate(1)
nodes[0].generate(1)
- nodes[0].generate(1)
assert_raises_jsonrpc(-12, "Keypool ran out", nodes[0].generate, 1)
+ nodes[0].walletpassphrase('test', 100)
+ nodes[0].keypoolrefill(100)
+ wi = nodes[0].getwalletinfo()
+ assert_equal(wi['keypoolsize_hd_internal'], 100)
+ assert_equal(wi['keypoolsize'], 100)
+
def __init__(self):
super().__init__()
self.setup_clean_chain = False
diff --git a/test/functional/maxblocksinflight.py b/test/functional/maxblocksinflight.py
deleted file mode 100755
index 2c3766125a..0000000000
--- a/test/functional/maxblocksinflight.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2015-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.
-"""Test nodes responses to having many blocks in flight.
-
-In this test we connect to one node over p2p, send it numerous inv's, and
-compare the resulting number of getdata requests to a max allowed value. We
-test for exceeding 128 blocks in flight, which was the limit an 0.9 client will
-reach. [0.10 clients shouldn't request more than 16 from a single peer.]
-"""
-
-from test_framework.mininode import *
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-MAX_REQUESTS = 128
-
-class TestManager(NodeConnCB):
- # set up NodeConnCB callbacks, overriding base class
- def on_getdata(self, conn, message):
- self.log.debug("got getdata %s" % repr(message))
- # Log the requests
- for inv in message.inv:
- if inv.hash not in self.blockReqCounts:
- self.blockReqCounts[inv.hash] = 0
- self.blockReqCounts[inv.hash] += 1
-
- def on_close(self, conn):
- if not self.disconnectOkay:
- raise EarlyDisconnectError(0)
-
- def __init__(self):
- NodeConnCB.__init__(self)
-
- def add_new_connection(self, connection):
- self.connection = connection
- self.blockReqCounts = {}
- self.disconnectOkay = False
-
- def run(self):
- self.connection.rpc.generate(1) # Leave IBD
-
- numBlocksToGenerate = [8, 16, 128, 1024]
- for count in range(len(numBlocksToGenerate)):
- current_invs = []
- for i in range(numBlocksToGenerate[count]):
- current_invs.append(CInv(2, random.randrange(0, 1 << 256)))
- if len(current_invs) >= 50000:
- self.connection.send_message(msg_inv(current_invs))
- current_invs = []
- if len(current_invs) > 0:
- self.connection.send_message(msg_inv(current_invs))
-
- # Wait and see how many blocks were requested
- time.sleep(2)
-
- total_requests = 0
- with mininode_lock:
- for key in self.blockReqCounts:
- total_requests += self.blockReqCounts[key]
- if self.blockReqCounts[key] > 1:
- raise AssertionError("Error, test failed: block %064x requested more than once" % key)
- if total_requests > MAX_REQUESTS:
- raise AssertionError("Error, too many blocks (%d) requested" % total_requests)
- self.log.info("Round %d: success (total requests: %d)" % (count, total_requests))
-
- self.disconnectOkay = True
- self.connection.disconnect_node()
-
-
-class MaxBlocksInFlightTest(BitcoinTestFramework):
- def add_options(self, parser):
- parser.add_option("--testbinary", dest="testbinary",
- default=os.getenv("BITCOIND", "bitcoind"),
- help="Binary to test max block requests behavior")
-
- def __init__(self):
- super().__init__()
- self.setup_clean_chain = True
- self.num_nodes = 1
-
- def setup_network(self):
- self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
- extra_args=[['-whitelist=127.0.0.1']],
- binary=[self.options.testbinary])
-
- def run_test(self):
- test = TestManager()
- # pass log handler through to the test manager object
- test.log = self.log
- test.add_new_connection(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test))
- NetworkThread().start() # Start up network handling in another thread
- test.run()
-
-if __name__ == '__main__':
- MaxBlocksInFlightTest().main()
diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py
index 40cd85c9ec..9b42bf276c 100755
--- a/test/functional/maxuploadtarget.py
+++ b/test/functional/maxuploadtarget.py
@@ -20,7 +20,7 @@ import time
# p2p messages to a node, generating the messages in the main testing logic.
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
+ super().__init__()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
@@ -68,15 +68,6 @@ class TestNode(NodeConnCB):
def on_close(self, conn):
self.peer_disconnected = True
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- def received_pong():
- return (self.last_pong.nonce == self.ping_counter)
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- success = wait_until(received_pong, timeout=timeout)
- self.ping_counter += 1
- return success
-
class MaxUploadTest(BitcoinTestFramework):
def __init__(self):
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 17e3a9a967..feec8a7fd9 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -101,6 +101,18 @@ class MempoolPackagesTest(BitcoinTestFramework):
assert_equal(mempool[x], v_descendants[x])
assert(chain[0] not in v_descendants.keys())
+ # Check that ancestor modified fees includes fee deltas from
+ # prioritisetransaction
+ self.nodes[0].prioritisetransaction(chain[0], 1000)
+ mempool = self.nodes[0].getrawmempool(True)
+ ancestor_fees = 0
+ for x in chain:
+ ancestor_fees += mempool[x]['fee']
+ assert_equal(mempool[x]['ancestorfees'], ancestor_fees * COIN + 1000)
+
+ # Undo the prioritisetransaction for later tests
+ self.nodes[0].prioritisetransaction(chain[0], -1000)
+
# Check that descendant modified fees includes fee deltas from
# prioritisetransaction
self.nodes[0].prioritisetransaction(chain[-1], 1000)
diff --git a/test/functional/net.py b/test/functional/net.py
new file mode 100755
index 0000000000..a82cdabf52
--- /dev/null
+++ b/test/functional/net.py
@@ -0,0 +1,67 @@
+#!/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 RPC calls related to net.
+
+Tests correspond to code in rpc/net.cpp.
+"""
+
+import time
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_jsonrpc,
+ connect_nodes_bi,
+ p2p_port,
+ start_nodes,
+)
+
+
+class NetTest(BitcoinTestFramework):
+ def __init__(self):
+ super().__init__()
+ self.setup_clean_chain = True
+ self.num_nodes = 2
+
+ def setup_network(self):
+ self.nodes = start_nodes(self.num_nodes, self.options.tmpdir)
+ connect_nodes_bi(self.nodes, 0, 1)
+ self.is_network_split = False
+ self.sync_all()
+
+ def run_test(self):
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
+ assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
+
+ self.nodes[0].setnetworkactive(False)
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False)
+ timeout = 3
+ while self.nodes[0].getnetworkinfo()['connections'] != 0:
+ # Wait a bit for all sockets to close
+ assert timeout > 0, 'not all connections closed in time'
+ timeout -= 0.1
+ time.sleep(0.1)
+
+ self.nodes[0].setnetworkactive(True)
+ connect_nodes_bi(self.nodes, 0, 1)
+ assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True)
+ assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2)
+
+ # test getaddednodeinfo
+ assert_equal(self.nodes[0].getaddednodeinfo(), [])
+ # add a node (node2) to node0
+ ip_port = "127.0.0.1:{}".format(p2p_port(2))
+ self.nodes[0].addnode(ip_port, 'add')
+ # check that the node has indeed been added
+ added_nodes = self.nodes[0].getaddednodeinfo(ip_port)
+ assert_equal(len(added_nodes), 1)
+ assert_equal(added_nodes[0]['addednode'], ip_port)
+ # check that a non-existant node returns an error
+ assert_raises_jsonrpc(-24, "Node has not been added",
+ self.nodes[0].getaddednodeinfo, '1.1.1.1')
+
+
+if __name__ == '__main__':
+ NetTest().main()
diff --git a/test/functional/nodehandling.py b/test/functional/nodehandling.py
deleted file mode 100755
index a6b10a0d83..0000000000
--- a/test/functional/nodehandling.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2014-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.
-"""Test node handling."""
-
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import *
-
-import urllib.parse
-
-class NodeHandlingTest (BitcoinTestFramework):
-
- def __init__(self):
- super().__init__()
- self.num_nodes = 4
- self.setup_clean_chain = False
-
- def run_test(self):
- ###########################
- # setban/listbanned tests #
- ###########################
- assert_equal(len(self.nodes[2].getpeerinfo()), 4) #we should have 4 nodes at this point
- self.nodes[2].setban("127.0.0.1", "add")
- time.sleep(3) #wait till the nodes are disconected
- assert_equal(len(self.nodes[2].getpeerinfo()), 0) #all nodes must be disconnected at this point
- assert_equal(len(self.nodes[2].listbanned()), 1)
- self.nodes[2].clearbanned()
- assert_equal(len(self.nodes[2].listbanned()), 0)
- self.nodes[2].setban("127.0.0.0/24", "add")
- assert_equal(len(self.nodes[2].listbanned()), 1)
- # This will throw an exception because 127.0.0.1 is within range 127.0.0.0/24
- assert_raises_jsonrpc(-23, "IP/Subnet already banned", self.nodes[2].setban, "127.0.0.1", "add")
- # This will throw an exception because 127.0.0.1/42 is not a real subnet
- assert_raises_jsonrpc(-30, "Error: Invalid IP/Subnet", self.nodes[2].setban, "127.0.0.1/42", "add")
- assert_equal(len(self.nodes[2].listbanned()), 1) #still only one banned ip because 127.0.0.1 is within the range of 127.0.0.0/24
- # This will throw an exception because 127.0.0.1 was not added above
- assert_raises_jsonrpc(-30, "Error: Unban failed", self.nodes[2].setban, "127.0.0.1", "remove")
- assert_equal(len(self.nodes[2].listbanned()), 1)
- self.nodes[2].setban("127.0.0.0/24", "remove")
- assert_equal(len(self.nodes[2].listbanned()), 0)
- self.nodes[2].clearbanned()
- assert_equal(len(self.nodes[2].listbanned()), 0)
-
- ##test persisted banlist
- self.nodes[2].setban("127.0.0.0/32", "add")
- self.nodes[2].setban("127.0.0.0/24", "add")
- self.nodes[2].setban("192.168.0.1", "add", 1) #ban for 1 seconds
- self.nodes[2].setban("2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/19", "add", 1000) #ban for 1000 seconds
- listBeforeShutdown = self.nodes[2].listbanned()
- assert_equal("192.168.0.1/32", listBeforeShutdown[2]['address']) #must be here
- time.sleep(2) #make 100% sure we expired 192.168.0.1 node time
-
- #stop node
- stop_node(self.nodes[2], 2)
-
- self.nodes[2] = start_node(2, self.options.tmpdir)
- listAfterShutdown = self.nodes[2].listbanned()
- assert_equal("127.0.0.0/24", listAfterShutdown[0]['address'])
- assert_equal("127.0.0.0/32", listAfterShutdown[1]['address'])
- assert_equal("/19" in listAfterShutdown[2]['address'], True)
-
- ###########################
- # RPC disconnectnode test #
- ###########################
- url = urllib.parse.urlparse(self.nodes[1].url)
- self.nodes[0].disconnectnode(url.hostname+":"+str(p2p_port(1)))
- time.sleep(2) #disconnecting a node needs a little bit of time
- for node in self.nodes[0].getpeerinfo():
- assert(node['addr'] != url.hostname+":"+str(p2p_port(1)))
-
- connect_nodes_bi(self.nodes,0,1) #reconnect the node
- found = False
- for node in self.nodes[0].getpeerinfo():
- if node['addr'] == url.hostname+":"+str(p2p_port(1)):
- found = True
- assert(found)
-
-if __name__ == '__main__':
- NodeHandlingTest ().main ()
diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py
index e1111da4ae..c09945baa6 100755
--- a/test/functional/p2p-acceptblock.py
+++ b/test/functional/p2p-acceptblock.py
@@ -58,7 +58,7 @@ from test_framework.blocktools import create_block, create_coinbase
# p2p messages to a node, generating the messages in the main testing logic.
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
+ super().__init__()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
@@ -88,21 +88,6 @@ class TestNode(NodeConnCB):
def on_pong(self, conn, message):
self.last_pong = message
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- received_pong = False
- sleep_time = 0.05
- while not received_pong and timeout > 0:
- time.sleep(sleep_time)
- timeout -= sleep_time
- with mininode_lock:
- if self.last_pong.nonce == self.ping_counter:
- received_pong = True
- self.ping_counter += 1
- return received_pong
-
-
class AcceptBlockTest(BitcoinTestFramework):
def add_options(self, parser):
parser.add_option("--testbinary", dest="testbinary",
diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py
index 1fc0312c34..bf8d113767 100755
--- a/test/functional/p2p-compactblocks.py
+++ b/test/functional/p2p-compactblocks.py
@@ -15,9 +15,9 @@ from test_framework.blocktools import create_block, create_coinbase, add_witness
from test_framework.script import CScript, OP_TRUE
# TestNode: A peer we use to send messages to bitcoind, and store responses.
-class TestNode(SingleNodeConnCB):
+class TestNode(NodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
+ super().__init__()
self.last_sendcmpct = []
self.last_headers = None
self.last_inv = None
@@ -32,6 +32,13 @@ class TestNode(SingleNodeConnCB):
# This is for synchronizing the p2p message traffic,
# so we can eg wait until a particular block is announced.
self.set_announced_blockhashes = set()
+ self.connected = False
+
+ def on_open(self, conn):
+ self.connected = True
+
+ def on_close(self, conn):
+ self.connected = False
def on_sendcmpct(self, conn, message):
self.last_sendcmpct.append(message)
@@ -107,6 +114,18 @@ class TestNode(SingleNodeConnCB):
return (block_hash in self.set_announced_blockhashes)
return wait_until(received_hash, timeout=timeout)
+ def send_await_disconnect(self, message, timeout=30):
+ """Sends a message to the node and wait for disconnect.
+
+ 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
+
class CompactBlocksTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
@@ -274,8 +293,8 @@ class CompactBlocksTest(BitcoinTestFramework):
# This index will be too high
prefilled_txn = PrefilledTransaction(1, block.vtx[0])
cmpct_block.prefilled_txn = [prefilled_txn]
- self.test_node.send_and_ping(msg_cmpctblock(cmpct_block))
- assert(int(self.nodes[0].getbestblockhash(), 16) == block.hashPrevBlock)
+ self.test_node.send_await_disconnect(msg_cmpctblock(cmpct_block))
+ assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.hashPrevBlock)
# Compare the generated shortids to what we expect based on BIP 152, given
# bitcoind's choice of nonce.
diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py
index d8f07700d0..12539be950 100755
--- a/test/functional/p2p-feefilter.py
+++ b/test/functional/p2p-feefilter.py
@@ -24,9 +24,9 @@ def allInvsMatch(invsExpected, testnode):
# TestNode: bare-bones "peer". Used to track which invs are received from a node
# and to send the node feefilter messages.
-class TestNode(SingleNodeConnCB):
+class TestNode(NodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
+ super().__init__()
self.txinvs = []
def on_inv(self, conn, message):
diff --git a/test/functional/p2p-fullblocktest.py b/test/functional/p2p-fullblocktest.py
index 274dbb8a92..e7fe7372c8 100755
--- a/test/functional/p2p-fullblocktest.py
+++ b/test/functional/p2p-fullblocktest.py
@@ -398,7 +398,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b26 chain to make sure bitcoind isn't accepting b26
b27 = block(27, spend=out[7])
- yield rejected(RejectResult(0, b'bad-prevblk'))
+ yield rejected(False)
# Now try a too-large-coinbase script
tip(15)
@@ -410,7 +410,7 @@ class FullBlockTest(ComparisonTestFramework):
# Extend the b28 chain to make sure bitcoind isn't accepting b28
b29 = block(29, spend=out[7])
- yield rejected(RejectResult(0, b'bad-prevblk'))
+ yield rejected(False)
# b30 has a max-sized coinbase scriptSig.
tip(23)
diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py
index 3a843197fb..5853ec86f0 100755
--- a/test/functional/p2p-leaktests.py
+++ b/test/functional/p2p-leaktests.py
@@ -19,10 +19,10 @@ banscore = 10
class CLazyNode(NodeConnCB):
def __init__(self):
+ super().__init__()
self.connection = None
self.unexpected_msg = False
self.connected = False
- super().__init__()
def add_connection(self, conn):
self.connection = conn
diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py
index 0aa9c90e8f..5064ce74aa 100755
--- a/test/functional/p2p-mempool.py
+++ b/test/functional/p2p-mempool.py
@@ -14,7 +14,7 @@ from test_framework.util import *
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
+ super().__init__()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
@@ -62,15 +62,6 @@ class TestNode(NodeConnCB):
def on_close(self, conn):
self.peer_disconnected = True
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- def received_pong():
- return (self.last_pong.nonce == self.ping_counter)
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- success = wait_until(received_pong, timeout=timeout)
- self.ping_counter += 1
- return success
-
def send_mempool(self):
self.lastInv = []
self.send_message(msg_mempool())
diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py
index dcf2b9a7de..3dd78c8b7d 100755
--- a/test/functional/p2p-segwit.py
+++ b/test/functional/p2p-segwit.py
@@ -8,7 +8,7 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
from test_framework.script import *
-from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, WITNESS_COMMITMENT_HEADER
+from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, get_witness_script, WITNESS_COMMITMENT_HEADER
from test_framework.key import CECKey, CPubKey
import time
import random
@@ -32,10 +32,9 @@ def get_virtual_size(witness_block):
vsize = int((3*base_size + total_size + 3)/4)
return vsize
-# Note: we can reduce code by using SingleNodeConnCB (in master, not 0.12)
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
+ super().__init__()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong(0)
@@ -81,13 +80,6 @@ class TestNode(NodeConnCB):
timeout -= self.sleep_time
raise AssertionError("Sync failed to complete")
- def sync_with_ping(self, timeout=60):
- self.send_message(msg_ping(nonce=self.ping_counter))
- test_function = lambda: self.last_pong.nonce == self.ping_counter
- self.sync(test_function, timeout)
- self.ping_counter += 1
- return
-
def wait_for_block(self, blockhash, timeout=60):
test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash
self.sync(test_function, timeout)
@@ -149,7 +141,7 @@ class TestNode(NodeConnCB):
if with_witness:
tx_message = msg_witness_tx(tx)
self.send_message(tx_message)
- self.sync_with_ping()
+ self.sync_with_ping(60)
assert_equal(tx.hash in self.connection.rpc.getrawmempool(), accepted)
if (reason != None and not accepted):
# Check the rejection reason as well.
@@ -162,7 +154,7 @@ class TestNode(NodeConnCB):
self.send_message(msg_witness_block(block))
else:
self.send_message(msg_block(block))
- self.sync_with_ping()
+ self.sync_with_ping(60)
assert_equal(self.connection.rpc.getbestblockhash() == block.hash, accepted)
@@ -236,7 +228,7 @@ class SegWitTest(BitcoinTestFramework):
block = self.build_next_block(nVersion=1)
block.solve()
self.test_node.send_message(msg_block(block))
- self.test_node.sync_with_ping() # make sure the block was processed
+ self.test_node.sync_with_ping(60) # make sure the block was processed
txid = block.vtx[0].sha256
self.nodes[0].generate(99) # let the block mature
@@ -252,7 +244,7 @@ class SegWitTest(BitcoinTestFramework):
assert_equal(msg_tx(tx).serialize(), msg_witness_tx(tx).serialize())
self.test_node.send_message(msg_witness_tx(tx))
- self.test_node.sync_with_ping() # make sure the tx was processed
+ self.test_node.sync_with_ping(60) # make sure the tx was processed
assert(tx.hash in self.nodes[0].getrawmempool())
# Save this transaction for later
self.utxo.append(UTXO(tx.sha256, 0, 49*100000000))
@@ -292,7 +284,7 @@ class SegWitTest(BitcoinTestFramework):
# But it should not be permanently marked bad...
# Resend without witness information.
self.test_node.send_message(msg_block(block))
- self.test_node.sync_with_ping()
+ self.test_node.sync_with_ping(60)
assert_equal(self.nodes[0].getbestblockhash(), block.hash)
sync_blocks(self.nodes)
@@ -1258,7 +1250,7 @@ class SegWitTest(BitcoinTestFramework):
# Spending a higher version witness output is not allowed by policy,
# even with fRequireStandard=false.
self.test_node.test_transaction_acceptance(tx3, with_witness=True, accepted=False)
- self.test_node.sync_with_ping()
+ self.test_node.sync_with_ping(60)
with mininode_lock:
assert(b"reserved for soft-fork upgrades" in self.test_node.last_reject.reason)
@@ -1388,7 +1380,7 @@ class SegWitTest(BitcoinTestFramework):
for i in range(NUM_TESTS):
# Ping regularly to keep the connection alive
if (not i % 100):
- self.test_node.sync_with_ping()
+ self.test_node.sync_with_ping(60)
# Choose random number of inputs to use.
num_inputs = random.randint(1, 10)
# Create a slight bias for producing more utxos
@@ -1729,15 +1721,10 @@ class SegWitTest(BitcoinTestFramework):
assert('default_witness_commitment' in gbt_results)
witness_commitment = gbt_results['default_witness_commitment']
- # TODO: this duplicates some code from blocktools.py, would be nice
- # to refactor.
# Check that default_witness_commitment is present.
- block = CBlock()
- witness_root = block.get_merkle_root([ser_uint256(0), ser_uint256(txid)])
- check_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(0)))
- from test_framework.blocktools import WITNESS_COMMITMENT_HEADER
- output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(check_commitment)
- script = CScript([OP_RETURN, output_data])
+ witness_root = CBlock.get_merkle_root([ser_uint256(0),
+ ser_uint256(txid)])
+ script = get_witness_script(witness_root, 0)
assert_equal(witness_commitment, bytes_to_hex_str(script))
# undo mocktime
diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py
index 498acb23fe..de4edd6800 100755
--- a/test/functional/p2p-timeouts.py
+++ b/test/functional/p2p-timeouts.py
@@ -27,9 +27,9 @@ from test_framework.mininode import *
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-class TestNode(SingleNodeConnCB):
+class TestNode(NodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
+ super().__init__()
self.connected = False
self.received_version = False
diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py
index dc714e9a4a..da960e2d80 100755
--- a/test/functional/p2p-versionbits-warning.py
+++ b/test/functional/p2p-versionbits-warning.py
@@ -28,7 +28,7 @@ VB_PATTERN = re.compile("^Warning.*versionbit")
# p2p messages to a node, generating the messages in the main testing logic.
class TestNode(NodeConnCB):
def __init__(self):
- NodeConnCB.__init__(self)
+ super().__init__()
self.connection = None
self.ping_counter = 1
self.last_pong = msg_pong()
@@ -46,21 +46,6 @@ class TestNode(NodeConnCB):
def on_pong(self, conn, message):
self.last_pong = message
- # Sync up with the node after delivery of a block
- def sync_with_ping(self, timeout=30):
- self.connection.send_message(msg_ping(nonce=self.ping_counter))
- received_pong = False
- sleep_time = 0.05
- while not received_pong and timeout > 0:
- time.sleep(sleep_time)
- timeout -= sleep_time
- with mininode_lock:
- if self.last_pong.nonce == self.ping_counter:
- received_pong = True
- self.ping_counter += 1
- return received_pong
-
-
class VersionBitsWarningTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py
index de7f5e0849..1a7475ae84 100755
--- a/test/functional/sendheaders.py
+++ b/test/functional/sendheaders.py
@@ -81,9 +81,9 @@ from test_framework.blocktools import create_block, create_coinbase
direct_fetch_response_time = 0.05
-class BaseNode(SingleNodeConnCB):
+class BaseNode(NodeConnCB):
def __init__(self):
- SingleNodeConnCB.__init__(self)
+ super().__init__()
self.last_inv = None
self.last_headers = None
self.last_block = None
diff --git a/test/functional/test_framework/blocktools.py b/test/functional/test_framework/blocktools.py
index 2c9a0857df..5dcf516dc6 100644
--- a/test/functional/test_framework/blocktools.py
+++ b/test/functional/test_framework/blocktools.py
@@ -25,6 +25,13 @@ def create_block(hashprev, coinbase, nTime=None):
# From BIP141
WITNESS_COMMITMENT_HEADER = b"\xaa\x21\xa9\xed"
+
+def get_witness_script(witness_root, witness_nonce):
+ witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
+ output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
+ return CScript([OP_RETURN, output_data])
+
+
# According to BIP141, blocks with witness rules active must commit to the
# hash of all in-block transactions including witness.
def add_witness_commitment(block, nonce=0):
@@ -32,14 +39,12 @@ def add_witness_commitment(block, nonce=0):
# transactions, with witnesses.
witness_nonce = nonce
witness_root = block.calc_witness_merkle_root()
- witness_commitment = uint256_from_str(hash256(ser_uint256(witness_root)+ser_uint256(witness_nonce)))
# witness_nonce should go to coinbase witness.
block.vtx[0].wit.vtxinwit = [CTxInWitness()]
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(witness_nonce)]
# witness commitment is the last OP_RETURN output in coinbase
- output_data = WITNESS_COMMITMENT_HEADER + ser_uint256(witness_commitment)
- block.vtx[0].vout.append(CTxOut(0, CScript([OP_RETURN, output_data])))
+ block.vtx[0].vout.append(CTxOut(0, get_witness_script(witness_root, witness_nonce)))
block.vtx[0].rehash()
block.hashMerkleRoot = block.calc_merkle_root()
block.rehash()
diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py
index 70d1d700ef..25c18bda82 100755
--- a/test/functional/test_framework/comptool.py
+++ b/test/functional/test_framework/comptool.py
@@ -42,7 +42,7 @@ class RejectResult(object):
class TestNode(NodeConnCB):
def __init__(self, block_store, tx_store):
- NodeConnCB.__init__(self)
+ super().__init__()
self.conn = None
self.bestblockhash = None
self.block_store = block_store
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index aace17a043..2383cca58e 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -610,7 +610,8 @@ class CBlock(CBlockHeader):
return r
# Calculate the merkle root given a vector of transaction hashes
- def get_merkle_root(self, hashes):
+ @classmethod
+ def get_merkle_root(cls, hashes):
while len(hashes) > 1:
newhashes = []
for i in range(0, len(hashes), 2):
@@ -1476,25 +1477,9 @@ class NodeConnCB(object):
self.deliver_sleep_time = None
# Remember the services our peer has advertised
self.peer_services = None
-
- def set_deliver_sleep_time(self, value):
- with mininode_lock:
- self.deliver_sleep_time = value
-
- def get_deliver_sleep_time(self):
- with mininode_lock:
- return self.deliver_sleep_time
-
- # Spin until verack message is received from the node.
- # Tests may want to use this as a signal that the test can begin.
- # This can be called from the testing thread, so it needs to acquire the
- # global lock.
- def wait_for_verack(self):
- while True:
- with mininode_lock:
- if self.verack_received:
- return
- time.sleep(0.05)
+ self.connection = None
+ self.ping_counter = 1
+ self.last_pong = msg_pong()
def deliver(self, conn, message):
deliver_sleep = self.get_deliver_sleep_time()
@@ -1506,17 +1491,36 @@ class NodeConnCB(object):
except:
logger.exception("ERROR delivering %s" % repr(message))
- def on_version(self, conn, message):
- if message.nVersion >= 209:
- conn.send_message(msg_verack())
- conn.ver_send = min(MY_VERSION, message.nVersion)
- if message.nVersion < 209:
- conn.ver_recv = conn.ver_send
- conn.nServices = message.nServices
+ def set_deliver_sleep_time(self, value):
+ with mininode_lock:
+ self.deliver_sleep_time = value
- def on_verack(self, conn, message):
- conn.ver_recv = conn.ver_send
- self.verack_received = True
+ def get_deliver_sleep_time(self):
+ with mininode_lock:
+ return self.deliver_sleep_time
+
+ # Callbacks which can be overridden by subclasses
+ #################################################
+
+ def on_addr(self, conn, message): pass
+ def on_alert(self, conn, message): pass
+ def on_block(self, conn, message): pass
+ def on_blocktxn(self, conn, message): pass
+ def on_close(self, conn): pass
+ def on_cmpctblock(self, conn, message): pass
+ def on_feefilter(self, conn, message): pass
+ def on_getaddr(self, conn, message): pass
+ def on_getblocks(self, conn, message): pass
+ def on_getblocktxn(self, conn, message): pass
+ def on_getdata(self, conn, message): pass
+ def on_getheaders(self, conn, message): pass
+ def on_headers(self, conn, message): pass
+ def on_mempool(self, conn): pass
+ def on_open(self, conn): pass
+ def on_reject(self, conn, message): pass
+ def on_sendcmpct(self, conn, message): pass
+ def on_sendheaders(self, conn, message): pass
+ def on_tx(self, conn, message): pass
def on_inv(self, conn, message):
want = msg_getdata()
@@ -1526,37 +1530,27 @@ class NodeConnCB(object):
if len(want.inv):
conn.send_message(want)
- def on_addr(self, conn, message): pass
- def on_alert(self, conn, message): pass
- def on_getdata(self, conn, message): pass
- def on_getblocks(self, conn, message): pass
- def on_tx(self, conn, message): pass
- def on_block(self, conn, message): pass
- def on_getaddr(self, conn, message): pass
- def on_headers(self, conn, message): pass
- def on_getheaders(self, conn, message): pass
def on_ping(self, conn, message):
if conn.ver_send > BIP0031_VERSION:
conn.send_message(msg_pong(message.nonce))
- def on_reject(self, conn, message): pass
- def on_open(self, conn): pass
- def on_close(self, conn): pass
- def on_mempool(self, conn): pass
- def on_pong(self, conn, message): pass
- def on_feefilter(self, conn, message): pass
- def on_sendheaders(self, conn, message): pass
- def on_sendcmpct(self, conn, message): pass
- def on_cmpctblock(self, conn, message): pass
- def on_getblocktxn(self, conn, message): pass
- def on_blocktxn(self, conn, message): pass
-# More useful callbacks and functions for NodeConnCB's which have a single NodeConn
-class SingleNodeConnCB(NodeConnCB):
- def __init__(self):
- NodeConnCB.__init__(self)
- self.connection = None
- self.ping_counter = 1
- self.last_pong = msg_pong()
+ def on_pong(self, conn, message):
+ self.last_pong = message
+
+ def on_verack(self, conn, message):
+ conn.ver_recv = conn.ver_send
+ self.verack_received = True
+
+ def on_version(self, conn, message):
+ if message.nVersion >= 209:
+ conn.send_message(msg_verack())
+ conn.ver_send = min(MY_VERSION, message.nVersion)
+ if message.nVersion < 209:
+ conn.ver_recv = conn.ver_send
+ conn.nServices = message.nServices
+
+ # Helper functions
+ ##################
def add_connection(self, conn):
self.connection = conn
@@ -1569,18 +1563,30 @@ class SingleNodeConnCB(NodeConnCB):
self.send_message(message)
self.sync_with_ping()
- def on_pong(self, conn, message):
- self.last_pong = message
-
# Sync up with the node
- def sync_with_ping(self, timeout=30):
+ def sync_with_ping(self, timeout=60):
def received_pong():
return (self.last_pong.nonce == self.ping_counter)
self.send_message(msg_ping(nonce=self.ping_counter))
success = wait_until(received_pong, timeout=timeout)
+ if not success:
+ logger.error("sync_with_ping failed!")
+ raise AssertionError("sync_with_ping failed!")
self.ping_counter += 1
+
return success
+ # Spin until verack message is received from the node.
+ # Tests may want to use this as a signal that the test can begin.
+ # This can be called from the testing thread, so it needs to acquire the
+ # global lock.
+ def wait_for_verack(self):
+ while True:
+ with mininode_lock:
+ if self.verack_received:
+ return
+ time.sleep(0.05)
+
# The actual NodeConn class
# This class provides an interface for a p2p connection to a specified node
class NodeConn(asyncore.dispatcher):
@@ -1744,7 +1750,7 @@ class NodeConn(asyncore.dispatcher):
def send_message(self, message, pushbuf=False):
if self.state != "connected" and not pushbuf:
raise IOError('Not connected, no pushbuf')
- logger.debug("Send message to %s:%d: %s" % (self.dstaddr, self.dstport, repr(message)))
+ self._log_message("send", message)
command = message.command
data = message.serialize()
tmsg = self.MAGIC_BYTES[self.network]
@@ -1766,9 +1772,19 @@ class NodeConn(asyncore.dispatcher):
self.messagemap[b'ping'] = msg_ping_prebip31
if self.last_sent + 30 * 60 < time.time():
self.send_message(self.messagemap[b'ping']())
- logger.debug("Received message from %s:%d: %s" % (self.dstaddr, self.dstport, repr(message)))
+ self._log_message("receive", message)
self.cb.deliver(self, message)
+ def _log_message(self, direction, msg):
+ if direction == "send":
+ log_message = "Send message to "
+ elif direction == "receive":
+ log_message = "Received message from "
+ log_message += "%s:%d: %s" % (self.dstaddr, self.dstport, repr(msg)[:500])
+ if len(log_message) > 500:
+ log_message += "... (msg truncated)"
+ logger.debug(log_message)
+
def disconnect_node(self):
self.disconnect = True
diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py
index 23ac324510..899b0b5a1b 100644
--- a/test/functional/test_framework/util.py
+++ b/test/functional/test_framework/util.py
@@ -315,7 +315,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=
datadir = os.path.join(dirname, "node"+str(i))
if binary is None:
binary = os.getenv("BITCOIND", "bitcoind")
- args = [ binary, "-datadir="+datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-mocktime="+str(get_mocktime()) ]
+ args = [binary, "-datadir=" + datadir, "-server", "-keypool=1", "-discover=0", "-rest", "-logtimemicros", "-debug", "-debugexclude=libevent", "-debugexclude=leveldb", "-mocktime=" + str(get_mocktime())]
if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr)
logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 37a2ab62a4..2932f82970 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -25,6 +25,27 @@ import tempfile
import re
import logging
+# Formatting. Default colors to empty strings.
+BOLD, BLUE, RED, GREY = ("", ""), ("", ""), ("", ""), ("", "")
+try:
+ # Make sure python thinks it can write unicode to its stdout
+ "\u2713".encode("utf_8").decode(sys.stdout.encoding)
+ TICK = "✓ "
+ CROSS = "✖ "
+ CIRCLE = "○ "
+except UnicodeDecodeError:
+ TICK = "P "
+ CROSS = "x "
+ CIRCLE = "o "
+
+if os.name == 'posix':
+ # primitive formatting on supported
+ # terminal via ANSI escape sequences:
+ BOLD = ('\033[0m', '\033[1m')
+ BLUE = ('\033[0m', '\033[0;34m')
+ RED = ('\033[0m', '\033[0;31m')
+ GREY = ('\033[0m', '\033[1;30m')
+
TEST_EXIT_PASSED = 0
TEST_EXIT_SKIPPED = 77
@@ -56,6 +77,7 @@ BASE_SCRIPTS= [
'rawtransactions.py',
'reindex.py',
# vv Tests less than 30s vv
+ "zmq_test.py",
'mempool_resurrect_test.py',
'txn_doublespend.py --mineblock',
'txn_clone.py',
@@ -67,10 +89,11 @@ BASE_SCRIPTS= [
'multi_rpc.py',
'proxy_test.py',
'signrawtransactions.py',
- 'nodehandling.py',
+ 'disconnect_ban.py',
'decodescript.py',
'blockchain.py',
'disablewallet.py',
+ 'net.py',
'keypool.py',
'p2p-mempool.py',
'prioritise_transaction.py',
@@ -88,11 +111,6 @@ BASE_SCRIPTS= [
'p2p-leaktests.py',
]
-ZMQ_SCRIPTS = [
- # ZMQ test can only be run if bitcoin was built with zmq-enabled.
- # call test_runner.py with -nozmq to explicitly exclude these tests.
- 'zmq_test.py']
-
EXTENDED_SCRIPTS = [
# These tests are not run by the travis build process.
# Longest test should go first, to favor running tests in parallel
@@ -121,12 +139,12 @@ EXTENDED_SCRIPTS = [
'txn_clone.py --mineblock',
'forknotify.py',
'invalidateblock.py',
- 'maxblocksinflight.py',
'p2p-acceptblock.py',
'replace-by-fee.py',
]
-ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
+# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests
+ALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS
NON_SCRIPTS = [
# These are python files that live in the functional tests directory, but are not test scripts.
@@ -149,8 +167,8 @@ def main():
parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
+ parser.add_argument('--keepcache', '-k', action='store_true', help='the default behavior is to flush the cache directory on startup. --keepcache retains the cache from the previous testrun.')
parser.add_argument('--quiet', '-q', action='store_true', help='only print results summary and failure logs')
- parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests')
args, unknown_args = parser.parse_known_args()
# Create a set to store arguments and create the passon string
@@ -168,7 +186,6 @@ def main():
enable_wallet = config["components"].getboolean("ENABLE_WALLET")
enable_utils = config["components"].getboolean("ENABLE_UTILS")
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
- enable_zmq = config["components"].getboolean("ENABLE_ZMQ") and not args.nozmq
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
@@ -181,15 +198,6 @@ def main():
print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
sys.exit(0)
- # python3-zmq may not be installed. Handle this gracefully and with some helpful info
- if enable_zmq:
- try:
- import zmq
- except ImportError:
- print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests."
- "To run zmq tests, see dependency info in /test/README.md.")
- raise
-
# Build list of tests
if tests:
# Individual tests have been specified. Run specified tests that exist
@@ -197,16 +205,13 @@ def main():
test_list = [t for t in ALL_SCRIPTS if
(t in tests or re.sub(".py$", "", t) in tests)]
else:
- # No individual tests have been specified. Run base tests, and
- # optionally ZMQ tests and extended tests.
+ # No individual tests have been specified.
+ # Run all base tests, and optionally run extended tests.
test_list = BASE_SCRIPTS
- if enable_zmq:
- test_list += ZMQ_SCRIPTS
if args.extended:
- test_list += EXTENDED_SCRIPTS
- # TODO: BASE_SCRIPTS and EXTENDED_SCRIPTS are sorted by runtime
- # (for parallel running efficiency). This combined list will is no
- # longer sorted.
+ # place the EXTENDED_SCRIPTS first since the three longest ones
+ # are there and the list is shorter
+ test_list = EXTENDED_SCRIPTS + test_list
# Remove the test cases that the user has explicitly asked to exclude.
if args.exclude:
@@ -227,14 +232,23 @@ def main():
check_script_list(config["environment"]["SRCDIR"])
+ if not args.keepcache:
+ shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True)
+
run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
- BOLD = ("","")
- if os.name == 'posix':
- # primitive formatting on supported
- # terminal via ANSI escape sequences:
- BOLD = ('\033[0m', '\033[1m')
+ # Warn if bitcoind is already running (unix only)
+ try:
+ if subprocess.check_output(["pidof", "bitcoind"]) is not None:
+ print("%sWARNING!%s There is already a bitcoind process running on this system. Tests may fail unexpectedly due to resource contention!" % (BOLD[1], BOLD[0]))
+ except (OSError, subprocess.SubprocessError):
+ pass
+
+ # Warn if there is a cache directory
+ cache_dir = "%s/test/cache" % build_dir
+ if os.path.isdir(cache_dir):
+ print("%sWARNING!%s There is a cache directory here: %s. If tests fail unexpectedly, try deleting the cache directory." % (BOLD[1], BOLD[0], cache_dir))
#Set env vars
if "BITCOIND" not in os.environ:
@@ -243,7 +257,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
tests_dir = src_dir + '/test/functional/'
flags = ["--srcdir={}/src".format(build_dir)] + args
- flags.append("--cachedir=%s/test/cache" % build_dir)
+ flags.append("--cachedir=%s" % cache_dir)
if enable_coverage:
coverage = RPCCoverage()
@@ -257,33 +271,26 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
#Run Tests
- all_passed = True
- time_sum = 0
- time0 = time.time()
-
job_queue = TestHandler(jobs, tests_dir, test_list, flags)
+ time0 = time.time()
+ test_results = []
max_len_name = len(max(test_list, key=len))
- results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0]
+
for _ in range(len(test_list)):
- (name, stdout, stderr, status, duration) = job_queue.get_next()
- all_passed = all_passed and status != "Failed"
- time_sum += duration
-
- if status == "Passed":
- logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], name, BOLD[0], duration))
- elif status == "Skipped":
- logging.debug("\n%s%s%s skipped" % (BOLD[1], name, BOLD[0]))
+ test_result, stdout, stderr = job_queue.get_next()
+ test_results.append(test_result)
+
+ if test_result.status == "Passed":
+ logging.debug("\n%s%s%s passed, Duration: %s s" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
+ elif test_result.status == "Skipped":
+ logging.debug("\n%s%s%s skipped" % (BOLD[1], test_result.name, BOLD[0]))
else:
- print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], name, BOLD[0], duration))
+ print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time))
print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n')
print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n')
- results += "%s | %s | %s s\n" % (name.ljust(max_len_name), status.ljust(7), duration)
-
- results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(7), time_sum) + BOLD[0]
- print(results)
- print("\nRuntime: %s s" % (int(time.time() - time0)))
+ print_results(test_results, max_len_name, (int(time.time() - time0)))
if coverage:
coverage.report_rpc_coverage()
@@ -291,8 +298,28 @@ def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=Fal
logging.debug("Cleaning up coverage data")
coverage.cleanup()
+ all_passed = all(map(lambda test_result: test_result.was_successful, test_results))
+
sys.exit(not all_passed)
+def print_results(test_results, max_len_name, runtime):
+ results = "\n" + BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "STATUS ", "DURATION") + BOLD[0]
+
+ test_results.sort(key=lambda result: result.name.lower())
+ all_passed = True
+ time_sum = 0
+
+ for test_result in test_results:
+ all_passed = all_passed and test_result.was_successful
+ time_sum += test_result.time
+ test_result.padding = max_len_name
+ results += str(test_result)
+
+ status = TICK + "Passed" if all_passed else CROSS + "Failed"
+ results += BOLD[1] + "\n%s | %s | %s s (accumulated) \n" % ("ALL".ljust(max_len_name), status.ljust(9), time_sum) + BOLD[0]
+ results += "Runtime: %s s\n" % (runtime)
+ print(results)
+
class TestHandler:
"""
Trigger the testscrips passed in via the list.
@@ -347,9 +374,35 @@ class TestHandler:
status = "Failed"
self.num_running -= 1
self.jobs.remove(j)
- return name, stdout, stderr, status, int(time.time() - time0)
+
+ return TestResult(name, status, int(time.time() - time0)), stdout, stderr
print('.', end='', flush=True)
+class TestResult():
+ def __init__(self, name, status, time):
+ self.name = name
+ self.status = status
+ self.time = time
+ self.padding = 0
+
+ def __repr__(self):
+ if self.status == "Passed":
+ color = BLUE
+ glyph = TICK
+ elif self.status == "Failed":
+ color = RED
+ glyph = CROSS
+ elif self.status == "Skipped":
+ color = GREY
+ glyph = CIRCLE
+
+ return color[1] + "%s | %s%s | %s s\n" % (self.name.ljust(self.padding), glyph, self.status.ljust(7), self.time) + color[0]
+
+ @property
+ def was_successful(self):
+ return self.status != "Failed"
+
+
def check_script_list(src_dir):
"""Check scripts directory.
@@ -359,9 +412,10 @@ def check_script_list(src_dir):
python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"])
missed_tests = list(python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS)))
if len(missed_tests) != 0:
- print("The following scripts are not being run:" + str(missed_tests))
- print("Check the test lists in test_runner.py")
- sys.exit(1)
+ print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % (BOLD[1], BOLD[0], str(missed_tests)))
+ if os.getenv('TRAVIS') == 'true':
+ # On travis this warning is an error to prevent merging incomplete commits into master
+ sys.exit(1)
class RPCCoverage(object):
"""
diff --git a/test/functional/wallet-dump.py b/test/functional/wallet-dump.py
index b819b72b75..8876f935a4 100755
--- a/test/functional/wallet-dump.py
+++ b/test/functional/wallet-dump.py
@@ -88,7 +88,7 @@ class WalletDumpTest(BitcoinTestFramework):
read_dump(tmpdir + "/node0/wallet.unencrypted.dump", addrs, None)
assert_equal(found_addr, test_addr_count) # all keys must be in the dump
assert_equal(found_addr_chg, 50) # 50 blocks where mined
- assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one)
+ assert_equal(found_addr_rsv, 90*2) # 90 keys plus 100% internal keys
#encrypt wallet, restart, unlock and dump
self.nodes[0].encryptwallet('test')
@@ -102,8 +102,8 @@ class WalletDumpTest(BitcoinTestFramework):
found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_enc = \
read_dump(tmpdir + "/node0/wallet.encrypted.dump", addrs, hd_master_addr_unenc)
assert_equal(found_addr, test_addr_count)
- assert_equal(found_addr_chg, 90 + 1 + 50) # old reserve keys are marked as change now
- assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one)
+ assert_equal(found_addr_chg, 90*2 + 50) # old reserve keys are marked as change now
+ assert_equal(found_addr_rsv, 90*2)
if __name__ == '__main__':
WalletDumpTest().main ()
diff --git a/test/functional/wallet-hd.py b/test/functional/wallet-hd.py
index c40662dc3d..64a6c92782 100755
--- a/test/functional/wallet-hd.py
+++ b/test/functional/wallet-hd.py
@@ -42,6 +42,11 @@ class WalletHDTest(BitcoinTestFramework):
masterkeyid = self.nodes[1].getwalletinfo()['hdmasterkeyid']
assert_equal(len(masterkeyid), 40)
+ # create an internal key
+ change_addr = self.nodes[1].getrawchangeaddress()
+ change_addrV= self.nodes[1].validateaddress(change_addr);
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/0'") #first internal child key
+
# Import a non-HD private key in the HD wallet
non_hd_add = self.nodes[0].getnewaddress()
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
@@ -65,6 +70,11 @@ class WalletHDTest(BitcoinTestFramework):
self.nodes[0].sendtoaddress(non_hd_add, 1)
self.nodes[0].generate(1)
+ # create an internal key (again)
+ change_addr = self.nodes[1].getrawchangeaddress()
+ change_addrV= self.nodes[1].validateaddress(change_addr);
+ assert_equal(change_addrV["hdkeypath"], "m/0'/1'/1'") #second internal child key
+
self.sync_all()
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
@@ -90,6 +100,15 @@ class WalletHDTest(BitcoinTestFramework):
#connect_nodes_bi(self.nodes, 0, 1)
assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
+ # send a tx and make sure its using the internal chain for the changeoutput
+ txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
+ outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout'];
+ keypath = ""
+ for out in outs:
+ if out['value'] != 1:
+ keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
+
+ assert_equal(keypath[0:7], "m/0'/1'")
if __name__ == '__main__':
WalletHDTest().main ()
diff --git a/test/functional/zmq_test.py b/test/functional/zmq_test.py
index 9e27b46381..891b609ffa 100755
--- a/test/functional/zmq_test.py
+++ b/test/functional/zmq_test.py
@@ -3,11 +3,13 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test the ZMQ API."""
+import configparser
+import os
+import struct
+import sys
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
-import zmq
-import struct
class ZMQTest (BitcoinTestFramework):
@@ -18,6 +20,21 @@ class ZMQTest (BitcoinTestFramework):
port = 28332
def setup_nodes(self):
+ # Try to import python3-zmq. Skip this test if the import fails.
+ try:
+ import zmq
+ except ImportError:
+ self.log.warning("python3-zmq module not available. Skipping zmq tests!")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+
+ # Check that bitcoin has been built with ZMQ enabled
+ config = configparser.ConfigParser()
+ config.read_file(open(os.path.dirname(__file__) + "/config.ini"))
+
+ if not config["components"].getboolean("ENABLE_ZMQ"):
+ self.log.warning("bitcoind has not been built with zmq enabled. Skipping zmq tests!")
+ sys.exit(self.TEST_EXIT_SKIPPED)
+
self.zmqContext = zmq.Context()
self.zmqSubSocket = self.zmqContext.socket(zmq.SUB)
self.zmqSubSocket.setsockopt(zmq.SUBSCRIBE, b"hashblock")