diff options
Diffstat (limited to 'test')
46 files changed, 636 insertions, 241 deletions
diff --git a/test/functional/README.md b/test/functional/README.md index 0d85a74074..82b30fed51 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -87,7 +87,9 @@ P2P messages. These can be found in the following source files: #### Using the P2P interface -- [messages.py](test_framework/messages.py) contains all the definitions for objects that pass +- `P2P`s can be used to test specific P2P protocol behavior. +[p2p.py](test_framework/p2p.py) contains test framework p2p objects and +[messages.py](test_framework/messages.py) contains all the definitions for objects passed over the network (`CBlock`, `CTransaction`, etc, along with the network-level wrappers for them, `msg_block`, `msg_tx`, etc). @@ -100,8 +102,22 @@ contains the higher level logic for processing P2P payloads and connecting to the Bitcoin Core node application logic. For custom behaviour, subclass the P2PInterface object and override the callback methods. -- Can be used to write tests where specific P2P protocol behavior is tested. -Examples tests are [p2p_unrequested_blocks.py](p2p_unrequested_blocks.py), +`P2PConnection`s can be used as such: + +```python +p2p_conn = node.add_p2p_connection(P2PInterface()) +p2p_conn.send_and_ping(msg) +``` + +They can also be referenced by indexing into a `TestNode`'s `p2ps` list, which +contains the list of test framework `p2p` objects connected to itself +(it does not include any `TestNode`s): + +```python +node.p2ps[0].sync_with_ping() +``` + +More examples can be found in [p2p_unrequested_blocks.py](p2p_unrequested_blocks.py), [p2p_compactblocks.py](p2p_compactblocks.py). #### Prototyping tests @@ -157,7 +173,7 @@ way is the use the `profile_with_perf` context manager, e.g. with node.profile_with_perf("send-big-msgs"): # Perform activity on the node you're interested in profiling, e.g.: for _ in range(10000): - node.p2p.send_message(some_large_message) + node.p2ps[0].send_message(some_large_message) ``` To see useful textual output, run diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 083deb6460..3b9bd3048f 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -136,7 +136,7 @@ class ExampleTest(BitcoinTestFramework): """Main test logic""" # Create P2P connections will wait for a verack to make sure the connection is fully up - self.nodes[0].add_p2p_connection(BaseNode()) + peer_messaging = self.nodes[0].add_p2p_connection(BaseNode()) # Generating a block on one of the nodes will get us out of IBD blocks = [int(self.nodes[0].generate(nblocks=1)[0], 16)] @@ -173,7 +173,7 @@ class ExampleTest(BitcoinTestFramework): block.solve() block_message = msg_block(block) # Send message is used to send a P2P message to the node over our P2PInterface - self.nodes[0].p2p.send_message(block_message) + peer_messaging.send_message(block_message) self.tip = block.sha256 blocks.append(self.tip) self.block_time += 1 @@ -191,25 +191,25 @@ class ExampleTest(BitcoinTestFramework): self.log.info("Add P2P connection to node2") self.nodes[0].disconnect_p2ps() - self.nodes[2].add_p2p_connection(BaseNode()) + peer_receiving = self.nodes[2].add_p2p_connection(BaseNode()) self.log.info("Test that node2 propagates all the blocks to us") getdata_request = msg_getdata() for block in blocks: getdata_request.inv.append(CInv(MSG_BLOCK, block)) - self.nodes[2].p2p.send_message(getdata_request) + peer_receiving.send_message(getdata_request) # wait_until() will loop until a predicate condition is met. Use it to test properties of the # P2PInterface objects. - self.nodes[2].p2p.wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5) + peer_receiving.wait_until(lambda: sorted(blocks) == sorted(list(peer_receiving.block_receive_map.keys())), timeout=5) self.log.info("Check that each block was received only once") # The network thread uses a global lock on data access to the P2PConnection objects when sending and receiving # messages. The test thread should acquire the global lock before accessing any P2PConnection data to avoid locking # and synchronization issues. Note p2p.wait_until() acquires this global lock internally when testing the predicate. with p2p_lock: - for block in self.nodes[2].p2p.block_receive_map.values(): + for block in peer_receiving.block_receive_map.values(): assert_equal(block, 1) diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py index dd17e888f9..daefb161ac 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/feature_backwards_compatibility.py @@ -36,12 +36,12 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): self.num_nodes = 6 # Add new version after each release: self.extra_args = [ - ["-addresstype=bech32"], # Pre-release: use to mine blocks + ["-addresstype=bech32", "-wallet="], # Pre-release: use to mine blocks ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # Pre-release: use to receive coins, swap wallets, etc ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.19.1 ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.18.1 ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.17.2 - ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.16.3 + ["-nowallet", "-walletrbf=1", "-addresstype=bech32", "-wallet=wallet.dat"], # v0.16.3 ] def skip_test_if_missing_module(self): diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index efafcfaec3..19753d73ef 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -1386,14 +1386,14 @@ class FullBlockTest(BitcoinTestFramework): """Add a P2P connection to the node. Helper to connect and wait for version handshake.""" - self.nodes[0].add_p2p_connection(P2PDataStore()) + self.helper_peer = self.nodes[0].add_p2p_connection(P2PDataStore()) # We need to wait for the initial getheaders from the peer before we # start populating our blockstore. If we don't, then we may run ahead # to the next subtest before we receive the getheaders. We'd then send # an INV for the next block and receive two getheaders - one for the # IBD and one for the INV. We'd respond to both and could get # unexpectedly disconnected if the DoS score for that error is 50. - self.nodes[0].p2p.wait_for_getheaders(timeout=timeout) + self.helper_peer.wait_for_getheaders(timeout=timeout) def reconnect_p2p(self, timeout=60): """Tear down and bootstrap the P2P connection to the node. @@ -1407,7 +1407,7 @@ class FullBlockTest(BitcoinTestFramework): """Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block. Call with success = False if the tip shouldn't advance to the most recent block.""" - self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect) + self.helper_peer.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason, force_send=force_send, timeout=timeout, expect_disconnect=reconnect) if reconnect: self.reconnect_p2p(timeout=timeout) diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 2919b0ea0b..aad255c4a9 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -75,7 +75,7 @@ class BIP65Test(BitcoinTestFramework): ) def run_test(self): - self.nodes[0].add_p2p_connection(P2PInterface()) + peer = self.nodes[0].add_p2p_connection(P2PInterface()) self.test_cltv_info(is_active=False) @@ -99,7 +99,7 @@ class BIP65Test(BitcoinTestFramework): block.solve() self.test_cltv_info(is_active=False) # Not active as of current tip and next block does not need to obey rules - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules assert_equal(self.nodes[0].getbestblockhash(), block.hash) @@ -111,9 +111,9 @@ class BIP65Test(BitcoinTestFramework): block.solve() with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000003)'.format(block.hash)]): - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - self.nodes[0].p2p.sync_with_ping() + peer.sync_with_ping() self.log.info("Test that invalid-according-to-cltv transactions cannot appear in a block") block.nVersion = 4 @@ -136,9 +136,9 @@ class BIP65Test(BitcoinTestFramework): block.solve() with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]): - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - self.nodes[0].p2p.sync_with_ping() + peer.sync_with_ping() self.log.info("Test that a version 4 block with a valid-according-to-CLTV transaction is accepted") spendtx = cltv_validate(self.nodes[0], spendtx, CLTV_HEIGHT - 1) @@ -150,7 +150,7 @@ class BIP65Test(BitcoinTestFramework): block.solve() self.test_cltv_info(is_active=True) # Not active as of current tip, but next block must obey rules - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) self.test_cltv_info(is_active=True) # Active as of current tip assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index 38e95f00e9..39e8bca751 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -182,10 +182,10 @@ class BIP68_112_113Test(BitcoinTestFramework): """Sends blocks to test node. Syncs and verifies that tip has advanced to most recent block. Call with success = False if the tip shouldn't advance to the most recent block.""" - self.nodes[0].p2p.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason) + self.helper_peer.send_blocks_and_test(blocks, self.nodes[0], success=success, reject_reason=reject_reason) def run_test(self): - self.nodes[0].add_p2p_connection(P2PDataStore()) + self.helper_peer = self.nodes[0].add_p2p_connection(P2PDataStore()) self.log.info("Generate blocks in the past for coinbase outputs.") long_past_time = int(time.time()) - 600 * 1000 # enough to build up to 1000 blocks 10 minutes apart without worrying about getting into the future diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py index 7a2e35c095..4bc47141a1 100755 --- a/test/functional/feature_dbcrash.py +++ b/test/functional/feature_dbcrash.py @@ -56,7 +56,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): # Set -maxmempool=0 to turn off mempool memory sharing with dbcache # Set -rpcservertimeout=900 to reduce socket disconnects in this # long-running test - self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000"] + self.base_args = ["-limitdescendantsize=0", "-maxmempool=0", "-rpcservertimeout=900", "-dbbatchsize=200000", "-wallet="] # Set different crash ratios and cache sizes. Note that not all of # -dbcache goes to the in-memory coins cache. @@ -66,7 +66,7 @@ class ChainstateWriteCrashTest(BitcoinTestFramework): # Node3 is a normal node with default args, except will mine full blocks # and non-standard txs (e.g. txs with "dust" outputs) - self.node3_args = ["-blockmaxweight=4000000", "-acceptnonstdtxn"] + self.node3_args = ["-blockmaxweight=4000000", "-acceptnonstdtxn", "-wallet="] self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args] def skip_test_if_missing_module(self): diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index f263c93c8a..3f7efdbded 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -59,7 +59,7 @@ class BIP66Test(BitcoinTestFramework): ) def run_test(self): - self.nodes[0].add_p2p_connection(P2PInterface()) + peer = self.nodes[0].add_p2p_connection(P2PInterface()) self.test_dersig_info(is_active=False) @@ -84,7 +84,7 @@ class BIP66Test(BitcoinTestFramework): block.solve() self.test_dersig_info(is_active=False) # Not active as of current tip and next block does not need to obey rules - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules assert_equal(self.nodes[0].getbestblockhash(), block.hash) @@ -97,9 +97,9 @@ class BIP66Test(BitcoinTestFramework): block.solve() with self.nodes[0].assert_debug_log(expected_msgs=['{}, bad-version(0x00000002)'.format(block.hash)]): - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - self.nodes[0].p2p.sync_with_ping() + peer.sync_with_ping() self.log.info("Test that transactions with non-DER signatures cannot appear in a block") block.nVersion = 3 @@ -123,9 +123,9 @@ class BIP66Test(BitcoinTestFramework): block.solve() with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]): - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip) - self.nodes[0].p2p.sync_with_ping() + peer.sync_with_ping() self.log.info("Test that a version 3 block with a DERSIG-compliant transaction is accepted") block.vtx[1] = create_transaction(self.nodes[0], self.coinbase_txids[1], self.nodeaddress, amount=1.0) @@ -134,7 +134,7 @@ class BIP66Test(BitcoinTestFramework): block.solve() self.test_dersig_info(is_active=True) # Not active as of current tip, but next block must obey rules - self.nodes[0].p2p.send_and_ping(msg_block(block)) + peer.send_and_ping(msg_block(block)) self.test_dersig_info(is_active=True) # Active as of current tip assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256) diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index 702a1d9995..d89eeec400 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -145,9 +145,9 @@ class EstimateFeeTest(BitcoinTestFramework): # mine non-standard txs (e.g. txs with "dust" outputs) # Force fSendTrickle to true (via whitelist.noban) self.extra_args = [ - ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1"], - ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=68000"], - ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=32000"], + ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-wallet="], + ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=68000", "-wallet="], + ["-acceptnonstdtxn", "-whitelist=noban@127.0.0.1", "-blockmaxweight=32000", "-wallet="], ] def skip_test_if_missing_module(self): diff --git a/test/functional/feature_filelock.py b/test/functional/feature_filelock.py index b56ffe179f..e4ceb62c94 100755 --- a/test/functional/feature_filelock.py +++ b/test/functional/feature_filelock.py @@ -15,7 +15,7 @@ class FilelockTest(BitcoinTestFramework): def setup_network(self): self.add_nodes(self.num_nodes, extra_args=None) - self.nodes[0].start([]) + self.nodes[0].start(['-wallet=']) self.nodes[0].wait_for_rpc_connection() def run_test(self): @@ -30,7 +30,7 @@ class FilelockTest(BitcoinTestFramework): wallet_dir = os.path.join(datadir, 'wallets') self.log.info("Check that we can't start a second bitcoind instance using the same wallet") expected_msg = "Error: Error initializing wallet database environment" - self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX) + self.nodes[1].assert_start_raises_init_error(extra_args=['-walletdir={}'.format(wallet_dir), '-wallet=', '-noserver'], expected_msg=expected_msg, match=ErrorMatch.PARTIAL_REGEX) if __name__ == '__main__': FilelockTest().main() diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index e5c62d1ea7..d0a94658ff 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -145,16 +145,16 @@ class MaxUploadTest(BitcoinTestFramework): self.restart_node(0, ["-whitelist=download@127.0.0.1", "-maxuploadtarget=1"]) # Reconnect to self.nodes[0] - self.nodes[0].add_p2p_connection(TestP2PConn()) + peer = self.nodes[0].add_p2p_connection(TestP2PConn()) #retrieve 20 blocks which should be enough to break the 1MB limit getdata_request.inv = [CInv(MSG_BLOCK, big_new_block)] for i in range(20): - self.nodes[0].p2p.send_and_ping(getdata_request) - assert_equal(self.nodes[0].p2p.block_receive_map[big_new_block], i+1) + peer.send_and_ping(getdata_request) + assert_equal(peer.block_receive_map[big_new_block], i+1) getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)] - self.nodes[0].p2p.send_and_ping(getdata_request) + peer.send_and_ping(getdata_request) self.log.info("Peer still connected after trying to download old block (download permission)") peer_info = self.nodes[0].getpeerinfo() diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index db408ab67a..df54ae777b 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -81,16 +81,16 @@ class PruneTest(BitcoinTestFramework): # Create nodes 0 and 1 to mine. # Create node 2 to test pruning. - self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5"] + self.full_node_default_args = ["-maxreceivebuffer=20000", "-checkblocks=5", "-wallet="] # Create nodes 3 and 4 to test manual pruning (they will be re-started with manual pruning later) # Create nodes 5 to test wallet in prune mode, but do not connect self.extra_args = [ self.full_node_default_args, self.full_node_default_args, - ["-maxreceivebuffer=20000", "-prune=550"], - ["-maxreceivebuffer=20000"], - ["-maxreceivebuffer=20000"], - ["-prune=550"], + ["-wallet=", "-maxreceivebuffer=20000", "-prune=550"], + ["-wallet=", "-maxreceivebuffer=20000"], + ["-wallet=", "-maxreceivebuffer=20000"], + ["-wallet=", "-prune=550"], ] self.rpc_timeout = 120 diff --git a/test/functional/feature_signet.py b/test/functional/feature_signet.py new file mode 100755 index 0000000000..a0e7f3ee6e --- /dev/null +++ b/test/functional/feature_signet.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# Copyright (c) 2019-2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test basic signet functionality""" + +from decimal import Decimal + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal + +signet_blocks = [ + '00000020f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000f575c83235984e7dc4afc1f30944c170462e84437ab6f2d52e16878a79e4678bd1914d5fae77031eccf4070001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025151feffffff0200f2052a010000001600149243f727dd5343293eb83174324019ec16c2630f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205e423a8754336ca99dbe16509b877ef1bf98d008836c725005b3c787c41ebe46022047246e4467ad7cc7f1ad98662afcaf14c115e0095a227c7b05c5182591c23e7e01000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020533b53ded9bff4adc94101d32400a144c54edc5ed492a3b26c63b2d686000000b38fef50592017cfafbcab88eb3d9cf50b2c801711cad8299495d26df5e54812e7914d5fae77031ecfdd0b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025251feffffff0200f2052a01000000160014fd09839740f0e0b4fc6d5e2527e4022aa9b89dfa0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022031d64a1692cdad1fc0ced69838169fe19ae01be524d831b95fcf5ea4e6541c3c02204f9dea0801df8b4d0cd0857c62ab35c6c25cc47c930630dc7fe723531daa3e9b01000120000000000000000000000000000000000000000000000000000000000000000000000000', + '000000202960f3752f0bfa8858a3e333294aedc7808025e868c9dc03e71d88bb320000007765fcd3d5b4966beb338bba2675dc2cf2ad28d4ad1d83bdb6f286e7e27ac1f807924d5fae77031e81d60b0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025351feffffff0200f2052a010000001600141e5fb426042692ae0e87c070e78c39307a5661c20000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402205de93694763a42954865bcf1540cb82958bc62d0ec4eee02070fb7937cd037f4022067f333753bce47b10bc25eb6e1f311482e994c862a7e0b2d41ab1c8679fd1b1101000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020b06443a13ae1d3d50faef5ecad38c6818194dc46abca3e972e2aacdae800000069a5829097e80fee00ac49a56ea9f82d741a6af84d32b3bc455cf31871e2a8ac27924d5fae77031e9c91050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025451feffffff0200f2052a0100000016001430db2f8225dcf7751361ab38735de08190318cb70000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402200936f5f9872f6df5dd242026ad52241a68423f7f682e79169a8d85a374eab9b802202cd2979c48b321b3453e65e8f92460db3fca93cbea8539b450c959f4fbe630c601000120000000000000000000000000000000000000000000000000000000000000000000000000', + '000000207ed403758a4f228a1939418a155e2ebd4ae6b26e5ffd0ae433123f7694010000542e80b609c5bc58af5bdf492e26d4f60cd43a3966c2e063c50444c29b3757a636924d5fae77031ee8601d0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025551feffffff0200f2052a01000000160014edc207e014df34fa3885dff97d1129d356e1186a0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022021a3656609f85a66a2c5672ed9322c2158d57251040d2716ed202a1fe14f0c12022057d68bc6611f7a9424a7e00bbf3e27e6ae6b096f60bac624a094bc97a59aa1ff01000120000000000000000000000000000000000000000000000000000000000000000000000000', + '000000205bea0a88d1422c3df08d766ad72df95084d0700e6f873b75dd4e986c7703000002b57516d33ed60c2bdd9f93d6d5614083324c837e68e5ba6e04287a7285633585924d5fae77031ed171960001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025651feffffff0200f2052a010000001600143ae612599cf96f2442ce572633e0251116eaa52f0000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022059a7c54de76bfdbb1dd44c78ea2dbd2bb4e97f4abad38965f41e76433e56423c022054bf17f04fe17415c0141f60eebd2b839200f574d8ad8d55a0917b92b0eb913401000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020daf3b60d374b19476461f97540498dcfa2eb7016238ec6b1d022f82fb60100007a7ae65b53cb988c2ec92d2384996713821d5645ffe61c9acea60da75cd5edfa1a944d5fae77031e9dbb050001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025751feffffff0200f2052a01000000160014ef2dceae02e35f8137de76768ae3345d99ca68860000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202b3f946d6447f9bf17d00f3696cede7ee70b785495e5498274ee682a493befd5022045fc0bcf9332243168b5d35507175f9f374a8eba2336873885d12aada67ea5f601000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020457cc5f3c2e1a5655bc20e20e48d33e1b7ea68786c614032b5c518f0b6000000541f36942d82c6e7248275ff15c8933487fbe1819c67a9ecc0f4b70bb7e6cf672a944d5fae77031e8f39860001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025851feffffff0200f2052a0100000016001472a27906947c06d034b38ba2fa13c6391a4832790000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402202d62805ce60cbd60591f97f949b5ea5bd7e2307bcde343e6ea8394da92758e72022053a25370b0aa20da100189b7899a8f8675a0fdc60e38ece6b8a4f98edd94569e01000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020a2eb61eb4f3831baa3a3363e1b42db4462663f756f07423e81ed30322102000077224de7dea0f8d0ec22b1d2e2e255f0a987b96fe7200e1a2e6373f48a2f5b7894954d5fae77031e36867e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025951feffffff0200f2052a01000000160014aa0ad9f26801258382e0734dceec03a4a75f60240000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa2490047304402206fa0d59990eed369bd7375767c9a6c9369fae209152b8674e520da270605528c0220749eed3b12dbe3f583f505d21803e4aef59c8e24c5831951eafa4f15a8f92c4e01000120000000000000000000000000000000000000000000000000000000000000000000000000', + '00000020a868e8514be5e46dabd6a122132f423f36a43b716a40c394e2a8d063e1010000f4c6c717e99d800c699c25a2006a75a0c5c09f432a936f385e6fce139cdbd1a5e9964d5fae77031e7d026e0001010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff025a51feffffff0200f2052a01000000160014aaa671c82b138e3b8f510cd801e5f2bd0aa305940000000000000000776a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf94c4fecc7daa24900473044022042309f4c3c7a1a2ac8c24f890f962df1c0086cec10be0868087cfc427520cb2702201dafee8911c269b7e786e242045bb57cef3f5b0f177010c6159abae42f646cc501000120000000000000000000000000000000000000000000000000000000000000000000000000', +] + + +class SignetBasicTest(BitcoinTestFramework): + def set_test_params(self): + self.chain = "signet" + self.num_nodes = 6 + self.setup_clean_chain = True + shared_args1 = ["-signetchallenge=51"] # OP_TRUE + shared_args2 = [] # default challenge + # we use the exact same challenge except we do it as a 2-of-2, which means it should fail + shared_args3 = ["-signetchallenge=522103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae"] + + self.extra_args = [ + shared_args1, shared_args1, + shared_args2, shared_args2, + shared_args3, shared_args3, + ] + + def run_test(self): + self.log.info("basic tests using OP_TRUE challenge") + + self.log.info('getmininginfo') + mining_info = self.nodes[0].getmininginfo() + assert_equal(mining_info['blocks'], 0) + assert_equal(mining_info['chain'], 'signet') + assert 'currentblocktx' not in mining_info + assert 'currentblockweight' not in mining_info + assert_equal(mining_info['networkhashps'], Decimal('0')) + assert_equal(mining_info['pooledtx'], 0) + + self.nodes[0].generate(1) + + self.log.info("pregenerated signet blocks check") + + height = 0 + for block in signet_blocks: + assert_equal(self.nodes[2].submitblock(block), None) + height += 1 + assert_equal(self.nodes[2].getblockcount(), height) + + self.log.info("pregenerated signet blocks check (incompatible solution)") + + assert_equal(self.nodes[4].submitblock(signet_blocks[0]), 'bad-signet-blksig') + + +if __name__ == '__main__': + SignetBasicTest().main() diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index e1016e1581..2e4f4796b0 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -61,7 +61,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] - node.add_p2p_connection(P2PInterface()) + peer = node.add_p2p_connection(P2PInterface()) node_deterministic_address = node.get_deterministic_priv_key().address # Mine one period worth of blocks @@ -69,7 +69,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): self.log.info("Check that there is no warning if previous VB_BLOCKS have <VB_THRESHOLD blocks with unknown versionbits version.") # Build one period of blocks with < VB_THRESHOLD blocks signaling some unknown bit - self.send_blocks_with_version(node.p2p, VB_THRESHOLD - 1, VB_UNKNOWN_VERSION) + self.send_blocks_with_version(peer, VB_THRESHOLD - 1, VB_UNKNOWN_VERSION) node.generatetoaddress(VB_PERIOD - VB_THRESHOLD + 1, node_deterministic_address) # Check that we're not getting any versionbit-related errors in get*info() @@ -77,7 +77,7 @@ class VersionBitsWarningTest(BitcoinTestFramework): assert not VB_PATTERN.match(node.getnetworkinfo()["warnings"]) # Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit - self.send_blocks_with_version(node.p2p, VB_THRESHOLD, VB_UNKNOWN_VERSION) + self.send_blocks_with_version(peer, VB_THRESHOLD, VB_UNKNOWN_VERSION) node.generatetoaddress(VB_PERIOD - VB_THRESHOLD, node_deterministic_address) self.log.info("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version.") diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index ef4780cacb..17032a3b83 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -5,13 +5,24 @@ """Test the ZMQ notification interface.""" import struct -from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE +from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE, ADDRESS_BCRT1_P2WSH_OP_TRUE +from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment from test_framework.test_framework import BitcoinTestFramework -from test_framework.messages import CTransaction, hash256 -from test_framework.util import assert_equal, connect_nodes +from test_framework.messages import CTransaction, hash256, FromHex +from test_framework.util import ( + assert_equal, + connect_nodes, + assert_raises_rpc_error, +) from io import BytesIO from time import sleep +# Test may be skipped and not have zmq installed +try: + import zmq +except ImportError: + pass + def hash256_reversed(byte_str): return hash256(byte_str)[::-1] @@ -21,7 +32,6 @@ class ZMQSubscriber: self.socket = socket self.topic = topic - import zmq self.socket.setsockopt(zmq.SUBSCRIBE, self.topic) def receive(self): @@ -33,6 +43,22 @@ class ZMQSubscriber: self.sequence += 1 return body + def receive_sequence(self): + topic, body, seq = self.socket.recv_multipart() + # Topic should match the subscriber topic. + assert_equal(topic, self.topic) + # Sequence should be incremental. + assert_equal(struct.unpack('<I', seq)[-1], self.sequence) + self.sequence += 1 + hash = body[:32].hex() + label = chr(body[32]) + mempool_sequence = None if len(body) != 32+1+8 else struct.unpack("<Q", body[32+1:])[0] + if mempool_sequence is not None: + assert label == "A" or label == "R" + else: + assert label == "D" or label == "C" + return (hash, label, mempool_sequence) + class ZMQTest (BitcoinTestFramework): def set_test_params(self): @@ -43,10 +69,11 @@ class ZMQTest (BitcoinTestFramework): self.skip_if_no_bitcoind_zmq() def run_test(self): - import zmq self.ctx = zmq.Context() try: self.test_basic() + self.test_sequence() + self.test_mempool_sync() self.test_reorg() finally: # Destroy the ZMQ context. @@ -54,7 +81,6 @@ class ZMQTest (BitcoinTestFramework): self.ctx.destroy(linger=None) def test_basic(self): - import zmq # Invalid zmq arguments don't take down the node, see #17185. self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"]) @@ -146,7 +172,6 @@ class ZMQTest (BitcoinTestFramework): self.log.info("Skipping reorg test because wallet is disabled") return - import zmq address = 'tcp://127.0.0.1:28333' services = [b"hashblock", b"hashtx"] @@ -177,8 +202,8 @@ class ZMQTest (BitcoinTestFramework): assert_equal(hashtx.receive().hex(), payment_txid) assert_equal(hashtx.receive().hex(), disconnect_cb) - # Generate 2 blocks in nodes[1] - connect_blocks = self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) + # Generate 2 blocks in nodes[1] to a different address to ensure split + connect_blocks = self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_P2WSH_OP_TRUE) # nodes[0] will reorg chain after connecting back nodes[1] connect_nodes(self.nodes[0], 1) @@ -204,5 +229,282 @@ class ZMQTest (BitcoinTestFramework): # And the current tip assert_equal(hashtx.receive().hex(), self.nodes[1].getblock(connect_blocks[0])["tx"][0]) + def test_sequence(self): + """ + Sequence zmq notifications give every blockhash and txhash in order + of processing, regardless of IBD, re-orgs, etc. + Format of messages: + <32-byte hash>C : Blockhash connected + <32-byte hash>D : Blockhash disconnected + <32-byte hash>R<8-byte LE uint> : Transactionhash removed from mempool for non-block inclusion reason + <32-byte hash>A<8-byte LE uint> : Transactionhash added mempool + """ + self.log.info("Testing 'sequence' publisher") + address = 'tcp://127.0.0.1:28333' + socket = self.ctx.socket(zmq.SUB) + socket.set(zmq.RCVTIMEO, 60000) + seq = ZMQSubscriber(socket, b'sequence') + + self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)]) + socket.connect(address) + # Relax so that the subscriber is ready before publishing zmq messages + sleep(0.2) + + # Mempool sequence number starts at 1 + seq_num = 1 + + # Generate 1 block in nodes[0] and receive all notifications + dc_block = self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)[0] + + # Note: We are not notified of any block transactions, coinbase or mined + assert_equal((self.nodes[0].getbestblockhash(), "C", None), seq.receive_sequence()) + + # Generate 2 blocks in nodes[1] to a different address to ensure a chain split + self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_P2WSH_OP_TRUE) + + # nodes[0] will reorg chain after connecting back nodes[1] + connect_nodes(self.nodes[0], 1) + + # Then we receive all block (dis)connect notifications for the 2 block reorg + assert_equal((dc_block, "D", None), seq.receive_sequence()) + block_count = self.nodes[1].getblockcount() + assert_equal((self.nodes[1].getblockhash(block_count-1), "C", None), seq.receive_sequence()) + assert_equal((self.nodes[1].getblockhash(block_count), "C", None), seq.receive_sequence()) + + # Rest of test requires wallet functionality + if self.is_wallet_compiled(): + self.log.info("Wait for tx from second node") + payment_txid = self.nodes[1].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=5.0, replaceable=True) + self.sync_all() + self.log.info("Testing sequence notifications with mempool sequence values") + + # Should receive the broadcasted txid. + assert_equal((payment_txid, "A", seq_num), seq.receive_sequence()) + seq_num += 1 + + self.log.info("Testing RBF notification") + # Replace it to test eviction/addition notification + rbf_info = self.nodes[1].bumpfee(payment_txid) + self.sync_all() + assert_equal((payment_txid, "R", seq_num), seq.receive_sequence()) + seq_num += 1 + assert_equal((rbf_info["txid"], "A", seq_num), seq.receive_sequence()) + seq_num += 1 + + # Doesn't get published when mined, make a block and tx to "flush" the possibility + # though the mempool sequence number does go up by the number of transactions + # removed from the mempool by the block mining it. + mempool_size = len(self.nodes[0].getrawmempool()) + c_block = self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)[0] + self.sync_all() + # Make sure the number of mined transactions matches the number of txs out of mempool + mempool_size_delta = mempool_size - len(self.nodes[0].getrawmempool()) + assert_equal(len(self.nodes[0].getblock(c_block)["tx"])-1, mempool_size_delta) + seq_num += mempool_size_delta + payment_txid_2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) + self.sync_all() + assert_equal((c_block, "C", None), seq.receive_sequence()) + assert_equal((payment_txid_2, "A", seq_num), seq.receive_sequence()) + seq_num += 1 + + # Spot check getrawmempool results that they only show up when asked for + assert type(self.nodes[0].getrawmempool()) is list + assert type(self.nodes[0].getrawmempool(mempool_sequence=False)) is list + assert "mempool_sequence" not in self.nodes[0].getrawmempool(verbose=True) + assert_raises_rpc_error(-8, "Verbose results cannot contain mempool sequence values.", self.nodes[0].getrawmempool, True, True) + assert_equal(self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"], seq_num) + + self.log.info("Testing reorg notifications") + # Manually invalidate the last block to test mempool re-entry + # N.B. This part could be made more lenient in exact ordering + # since it greatly depends on inner-workings of blocks/mempool + # during "deep" re-orgs. Probably should "re-construct" + # blockchain/mempool state from notifications instead. + block_count = self.nodes[0].getblockcount() + best_hash = self.nodes[0].getbestblockhash() + self.nodes[0].invalidateblock(best_hash) + sleep(2) # Bit of room to make sure transaction things happened + + # Make sure getrawmempool mempool_sequence results aren't "queued" but immediately reflective + # of the time they were gathered. + assert self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"] > seq_num + + assert_equal((best_hash, "D", None), seq.receive_sequence()) + assert_equal((rbf_info["txid"], "A", seq_num), seq.receive_sequence()) + seq_num += 1 + + # Other things may happen but aren't wallet-deterministic so we don't test for them currently + self.nodes[0].reconsiderblock(best_hash) + self.nodes[1].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + self.sync_all() + + self.log.info("Evict mempool transaction by block conflict") + orig_txid = self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1.0, replaceable=True) + + # More to be simply mined + more_tx = [] + for _ in range(5): + more_tx.append(self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 0.1)) + + raw_tx = self.nodes[0].getrawtransaction(orig_txid) + bump_info = self.nodes[0].bumpfee(orig_txid) + # Mine the pre-bump tx + block = create_block(int(self.nodes[0].getbestblockhash(), 16), create_coinbase(self.nodes[0].getblockcount()+1)) + tx = FromHex(CTransaction(), raw_tx) + block.vtx.append(tx) + for txid in more_tx: + tx = FromHex(CTransaction(), self.nodes[0].getrawtransaction(txid)) + block.vtx.append(tx) + add_witness_commitment(block) + block.solve() + assert_equal(self.nodes[0].submitblock(block.serialize().hex()), None) + tip = self.nodes[0].getbestblockhash() + assert_equal(int(tip, 16), block.sha256) + orig_txid_2 = self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1.0, replaceable=True) + + # Flush old notifications until evicted tx original entry + (hash_str, label, mempool_seq) = seq.receive_sequence() + while hash_str != orig_txid: + (hash_str, label, mempool_seq) = seq.receive_sequence() + mempool_seq += 1 + + # Added original tx + assert_equal(label, "A") + # More transactions to be simply mined + for i in range(len(more_tx)): + assert_equal((more_tx[i], "A", mempool_seq), seq.receive_sequence()) + mempool_seq += 1 + # Bumped by rbf + assert_equal((orig_txid, "R", mempool_seq), seq.receive_sequence()) + mempool_seq += 1 + assert_equal((bump_info["txid"], "A", mempool_seq), seq.receive_sequence()) + mempool_seq += 1 + # Conflict announced first, then block + assert_equal((bump_info["txid"], "R", mempool_seq), seq.receive_sequence()) + mempool_seq += 1 + assert_equal((tip, "C", None), seq.receive_sequence()) + mempool_seq += len(more_tx) + # Last tx + assert_equal((orig_txid_2, "A", mempool_seq), seq.receive_sequence()) + mempool_seq += 1 + self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + self.sync_all() # want to make sure we didn't break "consensus" for other tests + + def test_mempool_sync(self): + """ + Use sequence notification plus getrawmempool sequence results to "sync mempool" + """ + if not self.is_wallet_compiled(): + self.log.info("Skipping mempool sync test") + return + + self.log.info("Testing 'mempool sync' usage of sequence notifier") + address = 'tcp://127.0.0.1:28333' + socket = self.ctx.socket(zmq.SUB) + socket.set(zmq.RCVTIMEO, 60000) + seq = ZMQSubscriber(socket, b'sequence') + + self.restart_node(0, ['-zmqpub%s=%s' % (seq.topic.decode(), address)]) + connect_nodes(self.nodes[0], 1) + socket.connect(address) + # Relax so that the subscriber is ready before publishing zmq messages + sleep(0.2) + + # In-memory counter, should always start at 1 + next_mempool_seq = self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"] + assert_equal(next_mempool_seq, 1) + + # Some transactions have been happening but we aren't consuming zmq notifications yet + # or we lost a ZMQ message somehow and want to start over + txids = [] + num_txs = 5 + for _ in range(num_txs): + txids.append(self.nodes[1].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=1.0, replaceable=True)) + self.sync_all() + + # 1) Consume backlog until we get a mempool sequence number + (hash_str, label, zmq_mem_seq) = seq.receive_sequence() + while zmq_mem_seq is None: + (hash_str, label, zmq_mem_seq) = seq.receive_sequence() + + assert label == "A" or label == "R" + assert hash_str is not None + + # 2) We need to "seed" our view of the mempool + mempool_snapshot = self.nodes[0].getrawmempool(mempool_sequence=True) + mempool_view = set(mempool_snapshot["txids"]) + get_raw_seq = mempool_snapshot["mempool_sequence"] + assert_equal(get_raw_seq, 6) + # Snapshot may be too old compared to zmq message we read off latest + while zmq_mem_seq >= get_raw_seq: + sleep(2) + mempool_snapshot = self.nodes[0].getrawmempool(mempool_sequence=True) + mempool_view = set(mempool_snapshot["txids"]) + get_raw_seq = mempool_snapshot["mempool_sequence"] + + # Things continue to happen in the "interim" while waiting for snapshot results + # We have node 0 do all these to avoid p2p races with RBF announcements + for _ in range(num_txs): + txids.append(self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=0.1, replaceable=True)) + self.nodes[0].bumpfee(txids[-1]) + self.sync_all() + self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + final_txid = self.nodes[0].sendtoaddress(address=self.nodes[0].getnewaddress(), amount=0.1, replaceable=True) + + # 3) Consume ZMQ backlog until we get to "now" for the mempool snapshot + while True: + if zmq_mem_seq == get_raw_seq - 1: + break + (hash_str, label, mempool_sequence) = seq.receive_sequence() + if mempool_sequence is not None: + zmq_mem_seq = mempool_sequence + if zmq_mem_seq > get_raw_seq: + raise Exception("We somehow jumped mempool sequence numbers! zmq_mem_seq: {} > get_raw_seq: {}".format(zmq_mem_seq, get_raw_seq)) + + # 4) Moving forward, we apply the delta to our local view + # remaining txs(5) + 1 rbf(A+R) + 1 block connect + 1 final tx + expected_sequence = get_raw_seq + r_gap = 0 + for _ in range(num_txs + 2 + 1 + 1): + (hash_str, label, mempool_sequence) = seq.receive_sequence() + if mempool_sequence is not None: + if mempool_sequence != expected_sequence: + # Detected "R" gap, means this a conflict eviction, and mempool tx are being evicted before its + # position in the incoming block message "C" + if label == "R": + assert mempool_sequence > expected_sequence + r_gap += mempool_sequence - expected_sequence + else: + raise Exception("WARNING: txhash has unexpected mempool sequence value: {} vs expected {}".format(mempool_sequence, expected_sequence)) + if label == "A": + assert hash_str not in mempool_view + mempool_view.add(hash_str) + expected_sequence = mempool_sequence + 1 + elif label == "R": + assert hash_str in mempool_view + mempool_view.remove(hash_str) + expected_sequence = mempool_sequence + 1 + elif label == "C": + # (Attempt to) remove all txids from known block connects + block_txids = self.nodes[0].getblock(hash_str)["tx"][1:] + for txid in block_txids: + if txid in mempool_view: + expected_sequence += 1 + mempool_view.remove(txid) + expected_sequence -= r_gap + r_gap = 0 + elif label == "D": + # Not useful for mempool tracking per se + continue + else: + raise Exception("Unexpected ZMQ sequence label!") + + assert_equal(self.nodes[0].getrawmempool(), [final_txid]) + assert_equal(self.nodes[0].getrawmempool(mempool_sequence=True)["mempool_sequence"], expected_sequence) + + # 5) If you miss a zmq/mempool sequence number, go back to step (2) + + self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + if __name__ == '__main__': ZMQTest().main() diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py index 6df8f1c3ec..57a059b7f7 100755 --- a/test/functional/mempool_accept.py +++ b/test/functional/mempool_accept.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test mempool acceptance of raw transactions.""" +from decimal import Decimal from io import BytesIO import math @@ -91,20 +92,22 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) txid_0 = tx.rehash() self.check_mempool_result( - result_expected=[{'txid': txid_0, 'allowed': True}], + result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal(str(fee))}}], rawtxs=[raw_tx_0], ) self.log.info('A final transaction not in the mempool') coin = coins.pop() # Pick a random coin(base) to spend + output_amount = 0.025 raw_tx_final = node.signrawtransactionwithwallet(node.createrawtransaction( inputs=[{'txid': coin['txid'], 'vout': coin['vout'], "sequence": 0xffffffff}], # SEQUENCE_FINAL - outputs=[{node.getnewaddress(): 0.025}], + outputs=[{node.getnewaddress(): output_amount}], locktime=node.getblockcount() + 2000, # Can be anything ))['hex'] tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_final))) + fee_expected = int(coin['amount']) - output_amount self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': True}], + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal(str(fee_expected))}}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) @@ -127,7 +130,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_0))) txid_0 = tx.rehash() self.check_mempool_result( - result_expected=[{'txid': txid_0, 'allowed': True}], + result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': Decimal(str(2 * fee))}}], rawtxs=[raw_tx_0], ) @@ -187,7 +190,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework): tx.deserialize(BytesIO(hex_str_to_bytes(raw_tx_reference))) # Reference tx should be valid on itself self.check_mempool_result( - result_expected=[{'txid': tx.rehash(), 'allowed': True}], + result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal(str(0.1 - 0.05))}}], rawtxs=[tx.serialize().hex()], maxfeerate=0, ) diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index ad29d389e2..fd3dd47e2d 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -31,7 +31,7 @@ class MempoolCompatibilityTest(BitcoinTestFramework): 150200, # oldest version supported by the test framework None, ]) - self.start_nodes() + self.start_nodes([[], ["-wallet="]]) self.import_deterministic_coinbase_privkeys() def run_test(self): diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index e74ef8cf16..d7cb7db9f8 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -58,7 +58,7 @@ class MempoolPackagesTest(BitcoinTestFramework): def run_test(self): # Mine some blocks and have them mature. - self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs + peer_inv_store = self.nodes[0].add_p2p_connection(P2PTxInvStore()) # keep track of invs self.nodes[0].generate(101) utxo = self.nodes[0].listunspent(10) txid = utxo[0]['txid'] @@ -80,7 +80,7 @@ class MempoolPackagesTest(BitcoinTestFramework): # Wait until mempool transactions have passed initial broadcast (sent inv and received getdata) # Otherwise, getrawmempool may be inconsistent with getmempoolentry if unbroadcast changes in between - self.nodes[0].p2p.wait_for_broadcast(witness_chain) + peer_inv_store.wait_for_broadcast(witness_chain) # Check mempool has MAX_ANCESTORS transactions in it, and descendant and ancestor # count and fees should look correct diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index b13740750f..1b2c7644bd 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -234,9 +234,9 @@ class MiningTest(BitcoinTestFramework): assert_raises_rpc_error(-25, 'time-too-old', lambda: node.submitheader(hexdata=CBlockHeader(bad_block_time).serialize().hex())) # Should ask for the block from a p2p node, if they announce the header as well: - node.add_p2p_connection(P2PDataStore()) - node.p2p.wait_for_getheaders(timeout=5) # Drop the first getheaders - node.p2p.send_blocks_and_test(blocks=[block], node=node) + peer = node.add_p2p_connection(P2PDataStore()) + peer.wait_for_getheaders(timeout=5) # Drop the first getheaders + peer.send_blocks_and_test(blocks=[block], node=node) # Must be active now: assert chain_tip(block.hash, status='active', branchlen=0) in node.getchaintips() diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 65259f1869..646baa1550 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -17,7 +17,7 @@ class P2PBlocksOnly(BitcoinTestFramework): self.extra_args = [["-blocksonly"]] def run_test(self): - self.nodes[0].add_p2p_connection(P2PInterface()) + block_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface()) self.log.info('Check that txs from p2p are rejected and result in disconnect') prevtx = self.nodes[0].getblock(self.nodes[0].getblockhash(1), 2)['tx'][0] @@ -41,45 +41,49 @@ class P2PBlocksOnly(BitcoinTestFramework): )['hex'] assert_equal(self.nodes[0].getnetworkinfo()['localrelay'], False) with self.nodes[0].assert_debug_log(['transaction sent in violation of protocol peer=0']): - self.nodes[0].p2p.send_message(msg_tx(FromHex(CTransaction(), sigtx))) - self.nodes[0].p2p.wait_for_disconnect() + block_relay_peer.send_message(msg_tx(FromHex(CTransaction(), sigtx))) + block_relay_peer.wait_for_disconnect() assert_equal(self.nodes[0].getmempoolinfo()['size'], 0) # Remove the disconnected peer and add a new one. del self.nodes[0].p2ps[0] - self.nodes[0].add_p2p_connection(P2PInterface()) + tx_relay_peer = self.nodes[0].add_p2p_connection(P2PInterface()) self.log.info('Check that txs from rpc are not rejected and relayed to other peers') assert_equal(self.nodes[0].getpeerinfo()[0]['relaytxes'], True) txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid'] with self.nodes[0].assert_debug_log(['received getdata for: wtx {} peer=1'.format(txid)]): self.nodes[0].sendrawtransaction(sigtx) - self.nodes[0].p2p.wait_for_tx(txid) + tx_relay_peer.wait_for_tx(txid) assert_equal(self.nodes[0].getmempoolinfo()['size'], 1) - self.log.info('Check that txs from forcerelay peers are not rejected and relayed to others') - self.log.info("Restarting node 0 with forcerelay permission and blocksonly") - self.restart_node(0, ["-persistmempool=0", "-whitelist=127.0.0.1", "-whitelistforcerelay", "-blocksonly"]) + self.log.info('Check that txs from peers with relay-permission are not rejected and relayed to others') + self.log.info("Restarting node 0 with relay permission and blocksonly") + self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly"]) assert_equal(self.nodes[0].getrawmempool(), []) first_peer = self.nodes[0].add_p2p_connection(P2PInterface()) second_peer = self.nodes[0].add_p2p_connection(P2PInterface()) peer_1_info = self.nodes[0].getpeerinfo()[0] - assert_equal(peer_1_info['whitelisted'], True) - assert_equal(peer_1_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool', 'download']) + assert_equal(peer_1_info['permissions'], ['relay']) peer_2_info = self.nodes[0].getpeerinfo()[1] - assert_equal(peer_2_info['whitelisted'], True) - assert_equal(peer_2_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool', 'download']) + assert_equal(peer_2_info['permissions'], ['relay']) assert_equal(self.nodes[0].testmempoolaccept([sigtx])[0]['allowed'], True) txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid'] - self.log.info('Check that the tx from forcerelay first_peer is relayed to others (ie.second_peer)') + self.log.info('Check that the tx from first_peer with relay-permission is relayed to others (ie.second_peer)') with self.nodes[0].assert_debug_log(["received getdata"]): + # Note that normally, first_peer would never send us transactions since we're a blocksonly node. + # By activating blocksonly, we explicitly tell our peers that they should not send us transactions, + # and Bitcoin Core respects that choice and will not send transactions. + # But if, for some reason, first_peer decides to relay transactions to us anyway, we should relay them to + # second_peer since we gave relay permission to first_peer. + # See https://github.com/bitcoin/bitcoin/issues/19943 for details. first_peer.send_message(msg_tx(FromHex(CTransaction(), sigtx))) - self.log.info('Check that the forcerelay peer is still connected after sending the transaction') + self.log.info('Check that the peer with relay-permission is still connected after sending the transaction') assert_equal(first_peer.is_connected, True) second_peer.wait_for_tx(txid) assert_equal(self.nodes[0].getmempoolinfo()['size'], 1) - self.log.info("Forcerelay peer's transaction is accepted and relayed") + self.log.info("Relay-permission peer's transaction is accepted and relayed") if __name__ == '__main__': diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index fdae7fb68b..506b480039 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -188,28 +188,21 @@ class CompactBlocksTest(BitcoinTestFramework): test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with too-high version - sendcmpct = msg_sendcmpct() - sendcmpct.version = preferred_version + 1 - sendcmpct.announce = True - test_node.send_and_ping(sendcmpct) + test_node.send_and_ping(msg_sendcmpct(announce=True, version=preferred_version+1)) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message) # Headers sync before next test. test_node.request_headers_and_sync(locator=[tip]) # Now try a SENDCMPCT message with valid version, but announce=False - sendcmpct.version = preferred_version - sendcmpct.announce = False - test_node.send_and_ping(sendcmpct) + test_node.send_and_ping(msg_sendcmpct(announce=False, version=preferred_version)) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message) # Headers sync before next test. test_node.request_headers_and_sync(locator=[tip]) # Finally, try a SENDCMPCT message with announce=True - sendcmpct.version = preferred_version - sendcmpct.announce = True - test_node.send_and_ping(sendcmpct) + test_node.send_and_ping(msg_sendcmpct(announce=True, version=preferred_version)) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message) # Try one more time (no headers sync should be needed!) @@ -220,23 +213,17 @@ class CompactBlocksTest(BitcoinTestFramework): check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message) # Try one more time, after sending a version-1, announce=false message. - sendcmpct.version = preferred_version - 1 - sendcmpct.announce = False - test_node.send_and_ping(sendcmpct) + test_node.send_and_ping(msg_sendcmpct(announce=False, version=preferred_version-1)) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message) # Now turn off announcements - sendcmpct.version = preferred_version - sendcmpct.announce = False - test_node.send_and_ping(sendcmpct) + test_node.send_and_ping(msg_sendcmpct(announce=False, version=preferred_version)) check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message) if old_node is not None: # Verify that a peer using an older protocol version can receive # announcements from this node. - sendcmpct.version = preferred_version - 1 - sendcmpct.announce = True - old_node.send_and_ping(sendcmpct) + old_node.send_and_ping(msg_sendcmpct(announce=True, version=preferred_version-1)) # Header sync old_node.request_headers_and_sync(locator=[tip]) check_announcement_of_new_block(node, old_node, lambda p: "cmpctblock" in p.last_message) @@ -729,11 +716,7 @@ class CompactBlocksTest(BitcoinTestFramework): node = self.nodes[0] tip = node.getbestblockhash() peer.get_headers(locator=[int(tip, 16)], hashstop=0) - - msg = msg_sendcmpct() - msg.version = peer.cmpct_version - msg.announce = True - peer.send_and_ping(msg) + peer.send_and_ping(msg_sendcmpct(announce=True, version=peer.cmpct_version)) def test_compactblock_reconstruction_multiple_peers(self, stalling_peer, delivery_peer): node = self.nodes[0] diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py index 7dd8c3146b..2349afa1ee 100755 --- a/test/functional/p2p_dos_header_tree.py +++ b/test/functional/p2p_dos_header_tree.py @@ -46,8 +46,8 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): self.headers_fork = [FromHex(CBlockHeader(), h) for h in self.headers_fork] self.log.info("Feed all non-fork headers, including and up to the first checkpoint") - self.nodes[0].add_p2p_connection(P2PInterface()) - self.nodes[0].p2p.send_and_ping(msg_headers(self.headers)) + peer_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) + peer_checkpoint.send_and_ping(msg_headers(self.headers)) assert { 'height': 546, 'hash': '000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70', @@ -57,14 +57,14 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): self.log.info("Feed all fork headers (fails due to checkpoint)") with self.nodes[0].assert_debug_log(['bad-fork-prior-to-checkpoint']): - self.nodes[0].p2p.send_message(msg_headers(self.headers_fork)) - self.nodes[0].p2p.wait_for_disconnect() + peer_checkpoint.send_message(msg_headers(self.headers_fork)) + peer_checkpoint.wait_for_disconnect() self.log.info("Feed all fork headers (succeeds without checkpoint)") # On node 0 it succeeds because checkpoints are disabled self.restart_node(0, extra_args=['-nocheckpoints']) - self.nodes[0].add_p2p_connection(P2PInterface()) - self.nodes[0].p2p.send_and_ping(msg_headers(self.headers_fork)) + peer_no_checkpoint = self.nodes[0].add_p2p_connection(P2PInterface()) + peer_no_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", @@ -73,8 +73,8 @@ class RejectLowDifficultyHeadersTest(BitcoinTestFramework): } in self.nodes[0].getchaintips() # On node 1 it succeeds because no checkpoint has been reached yet by a chain tip - self.nodes[1].add_p2p_connection(P2PInterface()) - self.nodes[1].p2p.send_and_ping(msg_headers(self.headers_fork)) + peer_before_checkpoint = self.nodes[1].add_p2p_connection(P2PInterface()) + peer_before_checkpoint.send_and_ping(msg_headers(self.headers_fork)) assert { "height": 2, "hash": "00000000b0494bd6c3d5ff79c497cfce40831871cbf39b1bc28bd1dac817dc39", diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index 613d96eaad..642a217047 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -131,7 +131,7 @@ class FilterTest(BitcoinTestFramework): self.log.debug("Send a mempool msg after connecting and check that the tx is received") self.nodes[0].add_p2p_connection(filter_peer) filter_peer.send_and_ping(filter_peer.watch_filter_init) - self.nodes[0].p2p.send_message(msg_mempool()) + filter_peer.send_message(msg_mempool()) filter_peer.wait_for_tx(txid) def test_frelay_false(self, filter_peer): diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py index 6622ea9ec2..2b75ad5175 100755 --- a/test/functional/p2p_getaddr_caching.py +++ b/test/functional/p2p_getaddr_caching.py @@ -5,13 +5,8 @@ """Test addr response caching""" import time -from test_framework.messages import ( - CAddress, - NODE_NETWORK, - NODE_WITNESS, - msg_addr, - msg_getaddr, -) + +from test_framework.messages import msg_getaddr from test_framework.p2p import ( P2PInterface, p2p_lock @@ -21,21 +16,9 @@ from test_framework.util import ( assert_equal, ) +# As defined in net_processing. MAX_ADDR_TO_SEND = 1000 - -def gen_addrs(n): - addrs = [] - for i in range(n): - addr = CAddress() - addr.time = int(time.time()) - addr.nServices = NODE_NETWORK | NODE_WITNESS - # Use first octets to occupy different AddrMan buckets - first_octet = i >> 8 - second_octet = i % 256 - addr.ip = "{}.{}.1.1".format(first_octet, second_octet) - addr.port = 8333 - addrs.append(addr) - return addrs +MAX_PCT_ADDR_TO_SEND = 23 class AddrReceiver(P2PInterface): @@ -62,18 +45,16 @@ class AddrTest(BitcoinTestFramework): self.num_nodes = 1 def run_test(self): - self.log.info('Create connection that sends and requests addr messages') - addr_source = self.nodes[0].add_p2p_connection(P2PInterface()) - - msg_send_addrs = msg_addr() self.log.info('Fill peer AddrMan with a lot of records') - # Since these addrs are sent from the same source, not all of them will be stored, - # because we allocate a limited number of AddrMan buckets per addr source. - total_addrs = 10000 - addrs = gen_addrs(total_addrs) - for i in range(int(total_addrs/MAX_ADDR_TO_SEND)): - msg_send_addrs.addrs = addrs[i * MAX_ADDR_TO_SEND:(i + 1) * MAX_ADDR_TO_SEND] - addr_source.send_and_ping(msg_send_addrs) + for i in range(10000): + first_octet = i >> 8 + second_octet = i % 256 + a = "{}.{}.1.1".format(first_octet, second_octet) + self.nodes[0].addpeeraddress(a, 8333) + + # Need to make sure we hit MAX_ADDR_TO_SEND records in the addr response later because + # only a fraction of all known addresses can be cached and returned. + assert(len(self.nodes[0].getnodeaddresses(0)) > int(MAX_ADDR_TO_SEND / (MAX_PCT_ADDR_TO_SEND / 100))) responses = [] self.log.info('Send many addr requests within short time to receive same response') @@ -89,7 +70,7 @@ class AddrTest(BitcoinTestFramework): responses.append(addr_receiver.get_received_addrs()) for response in responses[1:]: assert_equal(response, responses[0]) - assert(len(response) < MAX_ADDR_TO_SEND) + assert(len(response) == MAX_ADDR_TO_SEND) cur_mock_time += 3 * 24 * 60 * 60 self.nodes[0].setmocktime(cur_mock_time) diff --git a/test/functional/p2p_getdata.py b/test/functional/p2p_getdata.py index 51921a8ab5..89d68d5ba0 100755 --- a/test/functional/p2p_getdata.py +++ b/test/functional/p2p_getdata.py @@ -42,7 +42,7 @@ class GetdataTest(BitcoinTestFramework): good_getdata = msg_getdata() good_getdata.inv.append(CInv(t=2, h=best_block)) p2p_block_store.send_and_ping(good_getdata) - p2p_block_store.wait_until(lambda: self.nodes[0].p2ps[0].blocks[best_block] == 1) + p2p_block_store.wait_until(lambda: p2p_block_store.blocks[best_block] == 1) if __name__ == '__main__': diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index b2c3c5d45f..483f25f48c 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -27,7 +27,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework): def run_test(self): # Add p2p connection to node0 node = self.nodes[0] # convenience reference to the node - node.add_p2p_connection(P2PDataStore()) + peer = node.add_p2p_connection(P2PDataStore()) best_block = node.getblock(node.getbestblockhash()) tip = int(node.getbestblockhash(), 16) @@ -42,7 +42,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework): # Save the coinbase for later block1 = block tip = block.sha256 - node.p2p.send_blocks_and_test([block1], node, success=True) + peer.send_blocks_and_test([block1], node, success=True) self.log.info("Mature the block.") node.generatetoaddress(100, node.get_deterministic_priv_key().address) @@ -80,7 +80,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework): assert_equal(orig_hash, block2.rehash()) assert block2_orig.vtx != block2.vtx - node.p2p.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate') + peer.send_blocks_and_test([block2], node, success=False, reject_reason='bad-txns-duplicate') # Check transactions for duplicate inputs (CVE-2018-17144) self.log.info("Test duplicate input block.") @@ -91,7 +91,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework): block2_dup.hashMerkleRoot = block2_dup.calc_merkle_root() block2_dup.rehash() block2_dup.solve() - node.p2p.send_blocks_and_test([block2_dup], node, success=False, reject_reason='bad-txns-inputs-duplicate') + peer.send_blocks_and_test([block2_dup], node, success=False, reject_reason='bad-txns-inputs-duplicate') self.log.info("Test very broken block.") @@ -104,14 +104,14 @@ class InvalidBlockRequestTest(BitcoinTestFramework): block3.rehash() block3.solve() - node.p2p.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount') + peer.send_blocks_and_test([block3], node, success=False, reject_reason='bad-cb-amount') # Complete testing of CVE-2012-2459 by sending the original block. # It should be accepted even though it has the same hash as the mutated one. self.log.info("Test accepting original block after rejecting its mutated version.") - node.p2p.send_blocks_and_test([block2_orig], node, success=True, timeout=5) + peer.send_blocks_and_test([block2_orig], node, success=True, timeout=5) # Update tip info height += 1 @@ -131,7 +131,7 @@ class InvalidBlockRequestTest(BitcoinTestFramework): block4.rehash() block4.solve() self.log.info("Test inflation by duplicating input") - node.p2p.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate') + peer.send_blocks_and_test([block4], node, success=False, reject_reason='bad-txns-inputs-duplicate') if __name__ == '__main__': InvalidBlockRequestTest().main() diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 24328c2919..e4fc9fd178 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -23,20 +23,20 @@ class InvalidLocatorTest(BitcoinTestFramework): block_count = node.getblockcount() for msg in [msg_getheaders(), msg_getblocks()]: self.log.info('Wait for disconnect when sending {} hashes in locator'.format(MAX_LOCATOR_SZ + 1)) - node.add_p2p_connection(P2PInterface()) + exceed_max_peer = node.add_p2p_connection(P2PInterface()) msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ + 1), -1)] - node.p2p.send_message(msg) - node.p2p.wait_for_disconnect() + exceed_max_peer.send_message(msg) + exceed_max_peer.wait_for_disconnect() node.disconnect_p2ps() self.log.info('Wait for response when sending {} hashes in locator'.format(MAX_LOCATOR_SZ)) - node.add_p2p_connection(P2PInterface()) + within_max_peer = node.add_p2p_connection(P2PInterface()) msg.locator.vHave = [int(node.getblockhash(i - 1), 16) for i in range(block_count, block_count - (MAX_LOCATOR_SZ), -1)] - node.p2p.send_message(msg) + within_max_peer.send_message(msg) if type(msg) == msg_getheaders: - node.p2p.wait_for_header(node.getbestblockhash()) + within_max_peer.wait_for_header(node.getbestblockhash()) else: - node.p2p.wait_for_block(int(node.getbestblockhash(), 16)) + within_max_peer.wait_for_block(int(node.getbestblockhash(), 16)) if __name__ == '__main__': diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index fe57057a83..bdcefe2ff5 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -22,12 +22,11 @@ from test_framework.p2p import ( P2PInterface, ) from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, -) +from test_framework.util import assert_equal VALID_DATA_LIMIT = MAX_PROTOCOL_MESSAGE_LENGTH - 5 # Account for the 5-byte length prefix + class msg_unrecognized: """Nonsensical message. Modeled after similar types in test_framework.messages.""" @@ -64,13 +63,13 @@ class InvalidMessagesTest(BitcoinTestFramework): conn = self.nodes[0].add_p2p_connection(P2PDataStore()) # Create valid message msg = conn.build_message(msg_ping(nonce=12345)) - cut_pos = 12 # Chosen at an arbitrary position within the header + cut_pos = 12 # Chosen at an arbitrary position within the header # Send message in two pieces - before = int(self.nodes[0].getnettotals()['totalbytesrecv']) + before = self.nodes[0].getnettotals()['totalbytesrecv'] conn.send_raw_message(msg[:cut_pos]) # Wait until node has processed the first half of the message - self.wait_until(lambda: int(self.nodes[0].getnettotals()['totalbytesrecv']) != before) - middle = int(self.nodes[0].getnettotals()['totalbytesrecv']) + self.wait_until(lambda: self.nodes[0].getnettotals()['totalbytesrecv'] != before) + middle = self.nodes[0].getnettotals()['totalbytesrecv'] # If this assert fails, we've hit an unlikely race # where the test framework sent a message in between the two halves assert_equal(middle, before + cut_pos) @@ -100,6 +99,8 @@ class InvalidMessagesTest(BitcoinTestFramework): msg = msg[:cut_len] + b'\xff' * 4 + msg[cut_len + 4:] conn.send_raw_message(msg) conn.sync_with_ping(timeout=1) + # Check that traffic is accounted for (24 bytes header + 2 bytes payload) + assert_equal(self.nodes[0].getpeerinfo()[0]['bytesrecv_per_msg']['*other*'], 26) self.nodes[0].disconnect_p2ps() def test_size(self): @@ -123,6 +124,8 @@ class InvalidMessagesTest(BitcoinTestFramework): msg = msg[:7] + b'\x00' + msg[7 + 1:] conn.send_raw_message(msg) conn.sync_with_ping(timeout=1) + # Check that traffic is accounted for (24 bytes header + 2 bytes payload) + assert_equal(self.nodes[0].getpeerinfo()[0]['bytesrecv_per_msg']['*other*'], 26) self.nodes[0].disconnect_p2ps() def test_oversized_msg(self, msg, size): diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index a0ef6c9d6e..489d903c21 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -61,7 +61,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): # Save the coinbase for later block1 = block tip = block.sha256 - node.p2p.send_blocks_and_test([block], node, success=True) + node.p2ps[0].send_blocks_and_test([block], node, success=True) self.log.info("Mature the block.") self.nodes[0].generatetoaddress(100, self.nodes[0].get_deterministic_priv_key().address) @@ -72,7 +72,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): self.log.info("Testing invalid transaction: %s", BadTxTemplate.__name__) template = BadTxTemplate(spend_block=block1) tx = template.get_tx() - node.p2p.send_txs_and_test( + node.p2ps[0].send_txs_and_test( [tx], node, success=False, expect_disconnect=template.expect_disconnect, reject_reason=template.reject_reason, @@ -121,7 +121,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): self.log.info('Send the orphans ... ') # Send valid orphan txs from p2ps[0] - node.p2p.send_txs_and_test([tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid], node, success=False) + node.p2ps[0].send_txs_and_test([tx_orphan_1, tx_orphan_2_no_fee, tx_orphan_2_valid], node, success=False) # Send invalid tx from p2ps[1] node.p2ps[1].send_txs_and_test([tx_orphan_2_invalid], node, success=False) @@ -130,7 +130,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): self.log.info('Send the withhold tx ... ') with node.assert_debug_log(expected_msgs=["bad-txns-in-belowout"]): - node.p2p.send_txs_and_test([tx_withhold], node, success=True) + node.p2ps[0].send_txs_and_test([tx_withhold], node, success=True) # Transactions that should end up in the mempool expected_mempool = { @@ -155,14 +155,14 @@ class InvalidTxRequestTest(BitcoinTestFramework): orphan_tx_pool[i].vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) with node.assert_debug_log(['mapOrphan overflow, removed 1 tx']): - node.p2p.send_txs_and_test(orphan_tx_pool, node, success=False) + node.p2ps[0].send_txs_and_test(orphan_tx_pool, node, success=False) rejected_parent = CTransaction() rejected_parent.vin.append(CTxIn(outpoint=COutPoint(tx_orphan_2_invalid.sha256, 0))) rejected_parent.vout.append(CTxOut(nValue=11 * COIN, scriptPubKey=SCRIPT_PUB_KEY_OP_TRUE)) rejected_parent.rehash() with node.assert_debug_log(['not keeping orphan with rejected parents {}'.format(rejected_parent.hash)]): - node.p2p.send_txs_and_test([rejected_parent], node, success=False) + node.p2ps[0].send_txs_and_test([rejected_parent], node, success=False) if __name__ == '__main__': diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 9503391030..d79ed449e5 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -3,6 +3,7 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test segwit transactions and blocks on P2P network.""" +from decimal import Decimal import math import random import struct @@ -88,7 +89,6 @@ from test_framework.util import ( # The versionbit bit used to signal activation of SegWit VB_WITNESS_BIT = 1 -VB_PERIOD = 144 VB_TOP_BITS = 0x20000000 MAX_SIGOP_COST = 80000 @@ -695,13 +695,13 @@ class SegWitTest(BitcoinTestFramework): if not self.segwit_active: # Just check mempool acceptance, but don't add the transaction to the mempool, since witness is disallowed # in blocks and the tx is impossible to mine right now. - assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}]) + assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}]) # Create the same output as tx3, but by replacing tx tx3_out = tx3.vout[0] tx3 = tx tx3.vout = [tx3_out] tx3.rehash() - assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True}]) + assert_equal(self.nodes[0].testmempoolaccept([tx3.serialize_with_witness().hex()]), [{'txid': tx3.hash, 'allowed': True, 'vsize': tx3.get_vsize(), 'fees': { 'base': Decimal('0.00011000')}}]) test_transaction_acceptance(self.nodes[0], self.test_node, tx3, with_witness=True, accepted=True) self.nodes[0].generate(1) @@ -2096,14 +2096,14 @@ class SegWitTest(BitcoinTestFramework): tx = FromHex(CTransaction(), raw) assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, serialize_with_bogus_witness(tx).hex()) with self.nodes[0].assert_debug_log(['Superfluous witness record']): - self.nodes[0].p2p.send_and_ping(msg_bogus_tx(tx)) + self.test_node.send_and_ping(msg_bogus_tx(tx)) raw = self.nodes[0].signrawtransactionwithwallet(raw) assert raw['complete'] raw = raw['hex'] tx = FromHex(CTransaction(), raw) assert_raises_rpc_error(-22, "TX decode failed", self.nodes[0].decoderawtransaction, serialize_with_bogus_witness(tx).hex()) with self.nodes[0].assert_debug_log(['Unknown transaction optional data']): - self.nodes[0].p2p.send_and_ping(msg_bogus_tx(tx)) + self.test_node.send_and_ping(msg_bogus_tx(tx)) @subtest # type: ignore def test_wtxid_relay(self): diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index c005584485..35cea85c07 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -317,7 +317,7 @@ class BlockchainTest(BitcoinTestFramework): def _test_waitforblockheight(self): self.log.info("Test waitforblockheight") node = self.nodes[0] - node.add_p2p_connection(P2PInterface()) + peer = node.add_p2p_connection(P2PInterface()) current_height = node.getblock(node.getbestblockhash())['height'] @@ -334,7 +334,7 @@ class BlockchainTest(BitcoinTestFramework): def solve_and_send_block(prevhash, height, time): b = create_block(prevhash, create_coinbase(height), time) b.solve() - node.p2p.send_and_ping(msg_block(b)) + peer.send_and_ping(msg_block(b)) return b b21f = solve_and_send_block(int(b20hash, 16), 21, b20['time'] + 1) diff --git a/test/functional/rpc_getpeerinfo_banscore_deprecation.py b/test/functional/rpc_getpeerinfo_banscore_deprecation.py deleted file mode 100755 index b830248e1e..0000000000 --- a/test/functional/rpc_getpeerinfo_banscore_deprecation.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2020 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -"""Test deprecation of getpeerinfo RPC banscore field.""" - -from test_framework.test_framework import BitcoinTestFramework - - -class GetpeerinfoBanscoreDeprecationTest(BitcoinTestFramework): - def set_test_params(self): - self.num_nodes = 2 - self.extra_args = [[], ["-deprecatedrpc=banscore"]] - - def run_test(self): - self.log.info("Test getpeerinfo by default no longer returns a banscore field") - assert "banscore" not in self.nodes[0].getpeerinfo()[0].keys() - - self.log.info("Test getpeerinfo returns banscore with -deprecatedrpc=banscore") - assert "banscore" in self.nodes[1].getpeerinfo()[0].keys() - - -if __name__ == "__main__": - GetpeerinfoBanscoreDeprecationTest().main() diff --git a/test/functional/rpc_getpeerinfo_deprecation.py b/test/functional/rpc_getpeerinfo_deprecation.py new file mode 100755 index 0000000000..287c40ae3e --- /dev/null +++ b/test/functional/rpc_getpeerinfo_deprecation.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test deprecation of getpeerinfo RPC fields.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import connect_nodes + + +class GetpeerinfoDeprecationTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 2 + self.extra_args = [[], ["-deprecatedrpc=banscore"]] + + def run_test(self): + self.test_banscore_deprecation() + self.test_addnode_deprecation() + + def test_banscore_deprecation(self): + self.log.info("Test getpeerinfo by default no longer returns a banscore field") + assert "banscore" not in self.nodes[0].getpeerinfo()[0].keys() + + self.log.info("Test getpeerinfo returns banscore with -deprecatedrpc=banscore") + assert "banscore" in self.nodes[1].getpeerinfo()[0].keys() + + def test_addnode_deprecation(self): + self.restart_node(1, ["-deprecatedrpc=getpeerinfo_addnode"]) + connect_nodes(self.nodes[0], 1) + + self.log.info("Test getpeerinfo by default no longer returns an addnode field") + assert "addnode" not in self.nodes[0].getpeerinfo()[0].keys() + + self.log.info("Test getpeerinfo returns addnode with -deprecatedrpc=addnode") + assert "addnode" in self.nodes[1].getpeerinfo()[0].keys() + + +if __name__ == "__main__": + GetpeerinfoDeprecationTest().main() diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index bc0e5b458e..b8a04f494d 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -175,6 +175,12 @@ class NetTest(BitcoinTestFramework): for info in peer_info: assert_net_servicesnames(int(info[0]["services"], 0x10), info[0]["servicesnames"]) + assert_equal(peer_info[0][0]['connection_type'], 'inbound') + assert_equal(peer_info[0][1]['connection_type'], 'manual') + + assert_equal(peer_info[1][0]['connection_type'], 'manual') + assert_equal(peer_info[1][1]['connection_type'], 'inbound') + def test_service_flags(self): self.log.info("Test service flags") self.nodes[0].add_p2p_connection(P2PInterface(), services=(1 << 4) | (1 << 63)) diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index b4e609df3a..00cf1ef66d 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -22,6 +22,7 @@ from codecs import encode import copy import hashlib from io import BytesIO +import math import random import socket import struct @@ -67,6 +68,8 @@ MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG FILTER_TYPE_BASIC = 0 +WITNESS_SCALE_FACTOR = 4 + # Serialization/deserialization tools def sha256(s): return hashlib.new('sha256', s).digest() @@ -537,6 +540,13 @@ class CTransaction: return False return True + # Calculate the virtual transaction size using witness and non-witness + # serialization size (does NOT use sigops). + def get_vsize(self): + with_witness_size = len(self.serialize_with_witness()) + without_witness_size = len(self.serialize_without_witness()) + return math.ceil(((WITNESS_SCALE_FACTOR - 1) * without_witness_size + with_witness_size) / WITNESS_SCALE_FACTOR) + def __repr__(self): return "CTransaction(nVersion=%i vin=%s vout=%s wit=%s nLockTime=%i)" \ % (self.nVersion, repr(self.vin), repr(self.vout), repr(self.wit), self.nLockTime) @@ -1462,9 +1472,9 @@ class msg_sendcmpct: __slots__ = ("announce", "version") msgtype = b"sendcmpct" - def __init__(self): - self.announce = False - self.version = 1 + def __init__(self, announce=False, version=1): + self.announce = announce + self.version = version def deserialize(self, f): self.announce = struct.unpack("<?", f.read(1))[0] diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py index 963a507f53..5f9b316b18 100755 --- a/test/functional/test_framework/p2p.py +++ b/test/functional/test_framework/p2p.py @@ -109,6 +109,7 @@ MAGIC_BYTES = { "mainnet": b"\xf9\xbe\xb4\xd9", # mainnet "testnet3": b"\x0b\x11\x09\x07", # testnet3 "regtest": b"\xfa\xbf\xb5\xda", # regtest + "signet": b"\x0a\x03\xcf\x40", # signet } diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index d034986821..046efe730e 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -542,15 +542,6 @@ class TestNode(): return p2p_conn - @property - def p2p(self): - """Return the first p2p connection - - Convenience property - most tests only use a single p2p connection to each - node, so this saves having to write node.p2ps[0] many times.""" - assert self.p2ps, self._node_msg("No p2p connection") - return self.p2ps[0] - def num_test_p2p_connections(self): """Return number of test framework p2p connections to the node.""" return len([peer for peer in self.getpeerinfo() if peer['subver'] == MY_SUBVERSION]) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index a3e160f12e..c8cf173d5f 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -208,6 +208,7 @@ BASE_SCRIPTS = [ 'rpc_bind.py --ipv6', 'rpc_bind.py --nonloopback', 'mining_basic.py', + 'feature_signet.py', 'wallet_bumpfee.py', 'wallet_implicitsegwit.py', 'rpc_named_arguments.py', @@ -250,7 +251,7 @@ BASE_SCRIPTS = [ 'feature_config_args.py', 'feature_settings.py', 'rpc_getdescriptorinfo.py', - 'rpc_getpeerinfo_banscore_deprecation.py', + 'rpc_getpeerinfo_deprecation.py', 'rpc_help.py', 'feature_help.py', 'feature_shutdown.py', diff --git a/test/functional/wallet_backup.py b/test/functional/wallet_backup.py index 4766355335..bcbac18d57 100755 --- a/test/functional/wallet_backup.py +++ b/test/functional/wallet_backup.py @@ -50,10 +50,10 @@ class WalletBackupTest(BitcoinTestFramework): # nodes 1, 2,3 are spenders, let's give them a keypool=100 # whitelist all peers to speed up tx relay / mempool sync self.extra_args = [ - ["-whitelist=noban@127.0.0.1", "-keypool=100"], - ["-whitelist=noban@127.0.0.1", "-keypool=100"], - ["-whitelist=noban@127.0.0.1", "-keypool=100"], - ["-whitelist=noban@127.0.0.1"], + ["-whitelist=noban@127.0.0.1", "-keypool=100", "-wallet="], + ["-whitelist=noban@127.0.0.1", "-keypool=100", "-wallet="], + ["-whitelist=noban@127.0.0.1", "-keypool=100", "-wallet="], + ["-whitelist=noban@127.0.0.1", "-wallet="], ] self.rpc_timeout = 120 diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py index 06f01ef191..09581d864b 100755 --- a/test/functional/wallet_dump.py +++ b/test/functional/wallet_dump.py @@ -95,7 +95,7 @@ def read_dump(file_name, addrs, script_addrs, hd_master_addr_old): class WalletDumpTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - self.extra_args = [["-keypool=90", "-addresstype=legacy"]] + self.extra_args = [["-keypool=90", "-addresstype=legacy", "-wallet=dump"]] self.rpc_timeout = 120 def skip_test_if_missing_module(self): diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 4ff7f1d525..87deaded09 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -151,7 +151,7 @@ class ImportRescanTest(BitcoinTestFramework): self.skip_if_no_wallet() def setup_network(self): - self.extra_args = [[] for _ in range(self.num_nodes)] + self.extra_args = [["-wallet="] for _ in range(self.num_nodes)] for i, import_node in enumerate(IMPORT_NODES, 2): if import_node.prune: self.extra_args[i] += ["-prune=1"] @@ -159,7 +159,7 @@ class ImportRescanTest(BitcoinTestFramework): self.add_nodes(self.num_nodes, extra_args=self.extra_args) # Import keys with pruning disabled - self.start_nodes(extra_args=[[]] * self.num_nodes) + self.start_nodes(extra_args=[["-wallet="]] * self.num_nodes) for n in self.nodes: n.importprivkey(privkey=n.get_deterministic_priv_key().key, label='coinbase') self.stop_nodes() diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index d64d3dcb49..f0be271c66 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -21,8 +21,6 @@ from test_framework.util import ( get_rpc_proxy, ) -FEATURE_LATEST = 169900 - got_loading_error = False def test_load_unload(node, name): global got_loading_error @@ -43,6 +41,7 @@ class MultiWalletTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 2 self.rpc_timeout = 120 + self.extra_args = [["-wallet="], ["-wallet="]] def skip_test_if_missing_module(self): self.skip_if_no_wallet() @@ -82,7 +81,7 @@ class MultiWalletTest(BitcoinTestFramework): os.rename(wallet_dir("wallet.dat"), wallet_dir("w8")) # create another dummy wallet for use in testing backups later - self.start_node(0, []) + self.start_node(0, ["-wallet="]) self.stop_nodes() empty_wallet = os.path.join(self.options.tmpdir, 'empty.dat') os.rename(wallet_dir("wallet.dat"), empty_wallet) @@ -152,7 +151,7 @@ class MultiWalletTest(BitcoinTestFramework): competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir') os.mkdir(competing_wallet_dir) - self.restart_node(0, ['-walletdir=' + competing_wallet_dir]) + self.restart_node(0, ['-walletdir=' + competing_wallet_dir, '-wallet=']) exp_stderr = r"Error: Error initializing wallet database environment \"\S+competing_walletdir\"!" self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr, match=ErrorMatch.PARTIAL_REGEX) diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index 0327c9e070..d3c03c4764 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -21,7 +21,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] # alias - node.add_p2p_connection(P2PTxInvStore()) + peer_first = node.add_p2p_connection(P2PTxInvStore()) self.log.info("Create a new transaction and wait until it's broadcast") txid = node.sendtoaddress(node.getnewaddress(), 1) @@ -33,10 +33,10 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): time.sleep(1.1) # Can take a few seconds due to transaction trickling - node.p2p.wait_for_broadcast([txid]) + peer_first.wait_for_broadcast([txid]) # Add a second peer since txs aren't rebroadcast to the same peer (see filterInventoryKnown) - node.add_p2p_connection(P2PTxInvStore()) + peer_second = node.add_p2p_connection(P2PTxInvStore()) self.log.info("Create a block") # Create and submit a block without the transaction. @@ -58,13 +58,13 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): two_min = 2 * 60 node.setmocktime(now + twelve_hrs - two_min) time.sleep(2) # ensure enough time has passed for rebroadcast attempt to occur - assert_equal(int(txid, 16) in node.p2ps[1].get_invs(), False) + assert_equal(int(txid, 16) in peer_second.get_invs(), False) self.log.info("Bump time & check that transaction is rebroadcast") # Transaction should be rebroadcast approximately 24 hours in the future, # but can range from 12-36. So bump 36 hours to be sure. node.setmocktime(now + 36 * 60 * 60) - node.p2p.wait_for_broadcast([txid]) + peer_second.wait_for_broadcast([txid]) if __name__ == '__main__': diff --git a/test/functional/wallet_startup.py b/test/functional/wallet_startup.py index cfc4edb8ee..d3119925f7 100755 --- a/test/functional/wallet_startup.py +++ b/test/functional/wallet_startup.py @@ -26,6 +26,16 @@ class WalletStartupTest(BitcoinTestFramework): self.start_nodes() def run_test(self): + self.log.info('Should start without any wallets') + assert_equal(self.nodes[0].listwallets(), []) + assert_equal(self.nodes[0].listwalletdir(), {'wallets': []}) + + self.log.info('New default wallet should load by default when there are no other wallets') + self.nodes[0].createwallet(wallet_name='', load_on_startup=False) + self.restart_node(0) + assert_equal(self.nodes[0].listwallets(), ['']) + + self.log.info('Test load on startup behavior') self.nodes[0].createwallet(wallet_name='w0', load_on_startup=True) self.nodes[0].createwallet(wallet_name='w1', load_on_startup=False) self.nodes[0].createwallet(wallet_name='w2', load_on_startup=True) diff --git a/test/functional/wallet_txn_clone.py b/test/functional/wallet_txn_clone.py index 5e1a804d33..33a2a9411e 100755 --- a/test/functional/wallet_txn_clone.py +++ b/test/functional/wallet_txn_clone.py @@ -25,7 +25,7 @@ class TxnMallTest(BitcoinTestFramework): parser.add_argument("--mineblock", dest="mine_block", default=False, action="store_true", help="Test double-spend of 1-confirmed transaction") parser.add_argument("--segwit", dest="segwit", default=False, action="store_true", - help="Test behaviour with SegWit txn (which should fail") + help="Test behaviour with SegWit txn (which should fail)") def setup_network(self): # Start with split network: diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index 69aa603c6b..031da8da81 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -27,7 +27,7 @@ class UpgradeWalletTest(BitcoinTestFramework): self.setup_clean_chain = True self.num_nodes = 3 self.extra_args = [ - ["-addresstype=bech32"], # current wallet version + ["-addresstype=bech32", "-wallet="], # current wallet version ["-usehd=1"], # v0.16.3 wallet ["-usehd=0"] # v0.15.2 wallet ] |