diff options
Diffstat (limited to 'test/functional')
66 files changed, 530 insertions, 402 deletions
diff --git a/test/functional/README.md b/test/functional/README.md index aff5f714f2..0d85a74074 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -127,8 +127,8 @@ Base class for functional tests. #### [util.py](test_framework/util.py) Generally useful functions. -#### [mininode.py](test_framework/mininode.py) -Basic code to support P2P connectivity to a bitcoind. +#### [p2p.py](test_framework/p2p.py) +Test objects for interacting with a bitcoind node over the p2p interface. #### [script.py](test_framework/script.py) Utilities for manipulating transaction scripts (originally from python-bitcoinlib) diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 34e4999329..083deb6460 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -16,17 +16,16 @@ from collections import defaultdict # Avoid wildcard * imports from test_framework.blocktools import (create_block, create_coinbase) from test_framework.messages import CInv, MSG_BLOCK -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, - mininode_lock, msg_block, msg_getdata, + p2p_lock, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes, - wait_until, ) # P2PInterface is a class containing callbacks to be executed when a P2P @@ -167,7 +166,7 @@ class ExampleTest(BitcoinTestFramework): height = self.nodes[0].getblockcount() for _ in range(10): - # Use the mininode and blocktools functionality to manually build a block + # Use the blocktools functionality to manually build a block. # Calling the generate() rpc is easier, but this allows us to exactly # control the blocks and transactions. block = create_block(self.tip, create_coinbase(height+1), self.block_time) @@ -203,15 +202,16 @@ class ExampleTest(BitcoinTestFramework): # wait_until() will loop until a predicate condition is met. Use it to test properties of the # P2PInterface objects. - wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock) + self.nodes[2].p2p.wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.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 wait_until() acquires this global lock when testing the predicate. - with mininode_lock: + # 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(): assert_equal(block, 1) + if __name__ == '__main__': ExampleTest().main() diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py index 75267de80b..17fbf50cc8 100755 --- a/test/functional/feature_abortnode.py +++ b/test/functional/feature_abortnode.py @@ -11,7 +11,7 @@ """ from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import wait_until, get_datadir_path, connect_nodes +from test_framework.util import get_datadir_path, connect_nodes import os @@ -41,7 +41,7 @@ class AbortNodeTest(BitcoinTestFramework): # Check that node0 aborted self.log.info("Waiting for crash") - wait_until(lambda: self.nodes[0].is_node_stopped(), timeout=200) + self.nodes[0].wait_until_stopped(timeout=200) self.log.info("Node crashed - now verifying restart fails") self.nodes[0].assert_start_raises_init_error() diff --git a/test/functional/feature_assumevalid.py b/test/functional/feature_assumevalid.py index f19ee12f95..603d7f5d3b 100755 --- a/test/functional/feature_assumevalid.py +++ b/test/functional/feature_assumevalid.py @@ -42,7 +42,7 @@ from test_framework.messages import ( msg_block, msg_headers, ) -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.script import (CScript, OP_TRUE) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal diff --git a/test/functional/feature_backwards_compatibility.py b/test/functional/feature_backwards_compatibility.py index 07dd0f8f82..dd17e888f9 100755 --- a/test/functional/feature_backwards_compatibility.py +++ b/test/functional/feature_backwards_compatibility.py @@ -6,7 +6,7 @@ Test various backwards compatibility scenarios. Download the previous node binaries: -contrib/devtools/previous_release.py -b v0.19.1 v0.18.1 v0.17.1 v0.16.3 v0.15.2 +test/get_previous_releases.py -b v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 v0.15.2 is not required by this test, but it is used in wallet_upgradewallet.py. Due to a hardfork in regtest, it can't be used to sync nodes. @@ -40,7 +40,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): ["-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.1 + ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.17.2 ["-nowallet", "-walletrbf=1", "-addresstype=bech32"], # v0.16.3 ] @@ -54,7 +54,7 @@ class BackwardsCompatibilityTest(BitcoinTestFramework): None, 190100, 180100, - 170100, + 170200, 160300, ]) diff --git a/test/functional/feature_block.py b/test/functional/feature_block.py index c74761869b..efafcfaec3 100755 --- a/test/functional/feature_block.py +++ b/test/functional/feature_block.py @@ -26,7 +26,7 @@ from test_framework.messages import ( uint256_from_compact, uint256_from_str, ) -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.script import ( CScript, MAX_SCRIPT_ELEMENT_SIZE, @@ -53,7 +53,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal from data import invalid_txs -# Use this class for tests that require behavior other than normal "mininode" behavior. +# Use this class for tests that require behavior other than normal p2p behavior. # For now, it is used to serialize a bloated varint (b64). class CBrokenBlock(CBlock): def initialize(self, base_block): diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index fd0330924d..2919b0ea0b 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -10,7 +10,7 @@ Test that the CHECKLOCKTIMEVERIFY soft-fork activates at (regtest) block height from test_framework.blocktools import create_coinbase, create_block, create_transaction from test_framework.messages import CTransaction, msg_block, ToHex -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.script import CScript, OP_1NEGATE, OP_CHECKLOCKTIMEVERIFY, OP_DROP, CScriptNum from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( diff --git a/test/functional/feature_csv_activation.py b/test/functional/feature_csv_activation.py index dfb3683143..38e95f00e9 100755 --- a/test/functional/feature_csv_activation.py +++ b/test/functional/feature_csv_activation.py @@ -44,7 +44,7 @@ import time from test_framework.blocktools import create_coinbase, create_block, create_transaction from test_framework.messages import ToHex, CTransaction -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.script import ( CScript, OP_CHECKSEQUENCEVERIFY, diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 05fdacd451..f263c93c8a 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -9,7 +9,7 @@ Test that the DERSIG soft-fork activates at (regtest) height 1251. from test_framework.blocktools import create_coinbase, create_block, create_transaction from test_framework.messages import msg_block -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.script import CScript from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py index 0dc2839191..e5c62d1ea7 100755 --- a/test/functional/feature_maxuploadtarget.py +++ b/test/functional/feature_maxuploadtarget.py @@ -14,7 +14,7 @@ from collections import defaultdict import time from test_framework.messages import CInv, MSG_BLOCK, msg_getdata -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, mine_large_block diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index dd4c318cee..3497b49a19 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -9,7 +9,6 @@ from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE, keyhash_to_p2pkh from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, connect_nodes, disconnect_nodes, hex_str_to_bytes, @@ -56,7 +55,7 @@ class NotificationsTest(BitcoinTestFramework): blocks = self.nodes[1].generatetoaddress(block_count, self.nodes[1].getnewaddress() if self.is_wallet_compiled() else ADDRESS_BCRT1_UNSPENDABLE) # wait at most 10 seconds for expected number of files before reading the content - wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) + self.wait_until(lambda: len(os.listdir(self.blocknotify_dir)) == block_count, timeout=10) # directory content should equal the generated blocks hashes assert_equal(sorted(blocks), sorted(os.listdir(self.blocknotify_dir))) @@ -64,7 +63,7 @@ class NotificationsTest(BitcoinTestFramework): if self.is_wallet_compiled(): self.log.info("test -walletnotify") # wait at most 10 seconds for expected number of files before reading the content - wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) + self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count))) @@ -78,7 +77,7 @@ class NotificationsTest(BitcoinTestFramework): self.start_node(1) connect_nodes(self.nodes[0], 1) - wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) + self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) # directory content should equal the generated transaction hashes txids_rpc = list(map(lambda t: notify_outputname(self.wallet, t['txid']), self.nodes[1].listtransactions("*", block_count))) @@ -140,7 +139,7 @@ class NotificationsTest(BitcoinTestFramework): # TODO: add test for `-alertnotify` large fork notifications def expect_wallet_notify(self, tx_ids): - wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_ids), timeout=10) + self.wait_until(lambda: len(os.listdir(self.walletnotify_dir)) >= len(tx_ids), timeout=10) assert_equal(sorted(notify_outputname(self.wallet, tx_id) for tx_id in tx_ids), sorted(os.listdir(self.walletnotify_dir))) for tx_file in os.listdir(self.walletnotify_dir): os.remove(os.path.join(self.walletnotify_dir, tx_file)) diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py index 02fa88f7c8..db408ab67a 100755 --- a/test/functional/feature_pruning.py +++ b/test/functional/feature_pruning.py @@ -20,7 +20,6 @@ from test_framework.util import ( assert_raises_rpc_error, connect_nodes, disconnect_nodes, - wait_until, ) # Rescans start at the earliest block up to 2 hours before a key timestamp, so @@ -136,7 +135,7 @@ class PruneTest(BitcoinTestFramework): mine_large_blocks(self.nodes[0], 25) # Wait for blk00000.dat to be pruned - wait_until(lambda: not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), timeout=30) + self.wait_until(lambda: not os.path.isfile(os.path.join(self.prunedir, "blk00000.dat")), timeout=30) self.log.info("Success") usage = calc_usage(self.prunedir) @@ -250,7 +249,7 @@ class PruneTest(BitcoinTestFramework): self.log.info("Verify node 2 reorged back to the main chain, some blocks of which it had to redownload") # Wait for Node 2 to reorg to proper height - wait_until(lambda: self.nodes[2].getblockcount() >= goalbestheight, timeout=900) + self.wait_until(lambda: self.nodes[2].getblockcount() >= goalbestheight, timeout=900) assert_equal(self.nodes[2].getbestblockhash(), goalbesthash) # Verify we can now have the data for a block previously pruned assert_equal(self.nodes[2].getblock(self.forkhash)["height"], self.forkheight) diff --git a/test/functional/feature_shutdown.py b/test/functional/feature_shutdown.py index d782d3b1d8..a76e0f1b50 100755 --- a/test/functional/feature_shutdown.py +++ b/test/functional/feature_shutdown.py @@ -5,7 +5,7 @@ """Test bitcoind shutdown.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, get_rpc_proxy, wait_until +from test_framework.util import assert_equal, get_rpc_proxy from threading import Thread def test_long_call(node): @@ -25,7 +25,7 @@ class ShutdownTest(BitcoinTestFramework): node.getblockcount() Thread(target=test_long_call, args=(node,)).start() # Wait until the server is executing the above `waitfornewblock`. - wait_until(lambda: len(self.nodes[0].getrpcinfo()['active_commands']) == 2) + self.wait_until(lambda: len(self.nodes[0].getrpcinfo()['active_commands']) == 2) # Wait 1 second after requesting shutdown but not before the `stop` call # finishes. This is to ensure event loop waits for current connections # to close. diff --git a/test/functional/feature_versionbits_warning.py b/test/functional/feature_versionbits_warning.py index 0713925141..e1016e1581 100755 --- a/test/functional/feature_versionbits_warning.py +++ b/test/functional/feature_versionbits_warning.py @@ -12,9 +12,8 @@ import re from test_framework.blocktools import create_block, create_coinbase from test_framework.messages import msg_block -from test_framework.mininode import P2PInterface, mininode_lock +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import wait_until VB_PERIOD = 144 # versionbits period length for regtest VB_THRESHOLD = 108 # versionbits activation threshold for regtest @@ -91,14 +90,14 @@ class VersionBitsWarningTest(BitcoinTestFramework): # Generating one block guarantees that we'll get out of IBD node.generatetoaddress(1, node_deterministic_address) - wait_until(lambda: not node.getblockchaininfo()['initialblockdownload'], timeout=10, lock=mininode_lock) + self.wait_until(lambda: not node.getblockchaininfo()['initialblockdownload']) # Generating one more block will be enough to generate an error. node.generatetoaddress(1, node_deterministic_address) # Check that get*info() shows the versionbits unknown rules warning assert WARN_UNKNOWN_RULES_ACTIVE in node.getmininginfo()["warnings"] assert WARN_UNKNOWN_RULES_ACTIVE in node.getnetworkinfo()["warnings"] # Check that the alert file shows the versionbits unknown rules warning - wait_until(lambda: self.versionbits_in_alert_file(), timeout=60) + self.wait_until(lambda: self.versionbits_in_alert_file()) if __name__ == '__main__': VersionBitsWarningTest().main() diff --git a/test/functional/interface_zmq.py b/test/functional/interface_zmq.py index 89c55f31f3..ef4780cacb 100755 --- a/test/functional/interface_zmq.py +++ b/test/functional/interface_zmq.py @@ -54,28 +54,31 @@ class ZMQTest (BitcoinTestFramework): self.ctx.destroy(linger=None) def test_basic(self): - # All messages are received in the same socket which means - # that this test fails if the publishing order changes. - # Note that the publishing order is not defined in the documentation and - # is subject to change. import zmq # Invalid zmq arguments don't take down the node, see #17185. self.restart_node(0, ["-zmqpubrawtx=foo", "-zmqpubhashtx=bar"]) address = 'tcp://127.0.0.1:28332' - socket = self.ctx.socket(zmq.SUB) - socket.set(zmq.RCVTIMEO, 60000) + sockets = [] + subs = [] + services = [b"hashblock", b"hashtx", b"rawblock", b"rawtx"] + for service in services: + sockets.append(self.ctx.socket(zmq.SUB)) + sockets[-1].set(zmq.RCVTIMEO, 60000) + subs.append(ZMQSubscriber(sockets[-1], service)) # Subscribe to all available topics. - hashblock = ZMQSubscriber(socket, b"hashblock") - hashtx = ZMQSubscriber(socket, b"hashtx") - rawblock = ZMQSubscriber(socket, b"rawblock") - rawtx = ZMQSubscriber(socket, b"rawtx") + hashblock = subs[0] + hashtx = subs[1] + rawblock = subs[2] + rawtx = subs[3] self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx, rawblock, rawtx]]) connect_nodes(self.nodes[0], 1) - socket.connect(address) + for socket in sockets: + socket.connect(address) + # Relax so that the subscriber is ready before publishing zmq messages sleep(0.2) @@ -96,15 +99,16 @@ class ZMQTest (BitcoinTestFramework): tx.calc_sha256() assert_equal(tx.hash, txid.hex()) + # Should receive the generated raw block. + block = rawblock.receive() + assert_equal(genhashes[x], hash256_reversed(block[:80]).hex()) + # Should receive the generated block hash. hash = hashblock.receive().hex() assert_equal(genhashes[x], hash) # The block should only have the coinbase txid. assert_equal([txid.hex()], self.nodes[1].getblock(hash)["tx"]) - # Should receive the generated raw block. - block = rawblock.receive() - assert_equal(genhashes[x], hash256_reversed(block[:80]).hex()) if self.is_wallet_compiled(): self.log.info("Wait for tx from second node") @@ -119,6 +123,13 @@ class ZMQTest (BitcoinTestFramework): hex = rawtx.receive() assert_equal(payment_txid, hash256_reversed(hex).hex()) + # Mining the block with this tx should result in second notification + # after coinbase tx notification + self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + hashtx.receive() + txid = hashtx.receive() + assert_equal(payment_txid, txid.hex()) + self.log.info("Test the getzmqnotifications RPC") assert_equal(self.nodes[0].getzmqnotifications(), [ @@ -131,30 +142,67 @@ class ZMQTest (BitcoinTestFramework): assert_equal(self.nodes[1].getzmqnotifications(), []) def test_reorg(self): + if not self.is_wallet_compiled(): + self.log.info("Skipping reorg test because wallet is disabled") + return + import zmq address = 'tcp://127.0.0.1:28333' - socket = self.ctx.socket(zmq.SUB) - socket.set(zmq.RCVTIMEO, 60000) - hashblock = ZMQSubscriber(socket, b'hashblock') + + services = [b"hashblock", b"hashtx"] + sockets = [] + subs = [] + for service in services: + sockets.append(self.ctx.socket(zmq.SUB)) + # 2 second timeout to check end of notifications + sockets[-1].set(zmq.RCVTIMEO, 2000) + subs.append(ZMQSubscriber(sockets[-1], service)) + + # Subscribe to all available topics. + hashblock = subs[0] + hashtx = subs[1] # Should only notify the tip if a reorg occurs - self.restart_node(0, ['-zmqpub%s=%s' % (hashblock.topic.decode(), address)]) - socket.connect(address) + self.restart_node(0, ["-zmqpub%s=%s" % (sub.topic.decode(), address) for sub in [hashblock, hashtx]]) + for socket in sockets: + socket.connect(address) # Relax so that the subscriber is ready before publishing zmq messages sleep(0.2) - # Generate 1 block in nodes[0] and receive all notifications - self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE) + # Generate 1 block in nodes[0] with 1 mempool tx and receive all notifications + payment_txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1.0) + disconnect_block = self.nodes[0].generatetoaddress(1, ADDRESS_BCRT1_UNSPENDABLE)[0] + disconnect_cb = self.nodes[0].getblock(disconnect_block)["tx"][0] assert_equal(self.nodes[0].getbestblockhash(), hashblock.receive().hex()) + assert_equal(hashtx.receive().hex(), payment_txid) + assert_equal(hashtx.receive().hex(), disconnect_cb) # Generate 2 blocks in nodes[1] - self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) + connect_blocks = self.nodes[1].generatetoaddress(2, ADDRESS_BCRT1_UNSPENDABLE) # nodes[0] will reorg chain after connecting back nodes[1] connect_nodes(self.nodes[0], 1) + self.sync_blocks() # tx in mempool valid but not advertised # Should receive nodes[1] tip assert_equal(self.nodes[1].getbestblockhash(), hashblock.receive().hex()) + # During reorg: + # Get old payment transaction notification from disconnect and disconnected cb + assert_equal(hashtx.receive().hex(), payment_txid) + assert_equal(hashtx.receive().hex(), disconnect_cb) + # And the payment transaction again due to mempool entry + assert_equal(hashtx.receive().hex(), payment_txid) + assert_equal(hashtx.receive().hex(), payment_txid) + # And the new connected coinbases + for i in [0, 1]: + assert_equal(hashtx.receive().hex(), self.nodes[1].getblock(connect_blocks[i])["tx"][0]) + + # If we do a simple invalidate we announce the disconnected coinbase + self.nodes[0].invalidateblock(connect_blocks[1]) + assert_equal(hashtx.receive().hex(), self.nodes[1].getblock(connect_blocks[1])["tx"][0]) + # And the current tip + assert_equal(hashtx.receive().hex(), self.nodes[1].getblock(connect_blocks[0])["tx"][0]) + if __name__ == '__main__': ZMQTest().main() diff --git a/test/functional/mempool_compatibility.py b/test/functional/mempool_compatibility.py index 31fb751904..ad29d389e2 100755 --- a/test/functional/mempool_compatibility.py +++ b/test/functional/mempool_compatibility.py @@ -8,7 +8,7 @@ NOTE: The test is designed to prevent cases when compatibility is broken acciden In case we need to break mempool compatibility we can continue to use the test by just bumping the version number. Download node binaries: -contrib/devtools/previous_release.py -b v0.19.1 v0.18.1 v0.17.1 v0.16.3 v0.15.2 +test/get_previous_releases.py -b v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 Only v0.15.2 is required by this test. The rest is used in other backwards compatibility tests. """ diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py index 98dac30ace..e74ef8cf16 100755 --- a/test/functional/mempool_packages.py +++ b/test/functional/mempool_packages.py @@ -7,13 +7,12 @@ from decimal import Decimal from test_framework.messages import COIN -from test_framework.mininode import P2PTxInvStore +from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, satoshi_round, - wait_until, ) # default limits @@ -269,8 +268,8 @@ class MempoolPackagesTest(BitcoinTestFramework): # - txs from previous ancestor test (-> custom ancestor limit) # - parent tx for descendant test # - txs chained off parent tx (-> custom descendant limit) - wait_until(lambda: len(self.nodes[1].getrawmempool(False)) == - MAX_ANCESTORS_CUSTOM + 1 + MAX_DESCENDANTS_CUSTOM, timeout=10) + self.wait_until(lambda: len(self.nodes[1].getrawmempool(False)) == + MAX_ANCESTORS_CUSTOM + 1 + MAX_DESCENDANTS_CUSTOM, timeout=10) mempool0 = self.nodes[0].getrawmempool(False) mempool1 = self.nodes[1].getrawmempool(False) assert set(mempool1).issubset(set(mempool0)) diff --git a/test/functional/mempool_persist.py b/test/functional/mempool_persist.py index 85c4d6d570..f73f1a02a2 100755 --- a/test/functional/mempool_persist.py +++ b/test/functional/mempool_persist.py @@ -39,15 +39,14 @@ from decimal import Decimal import os import time +from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework -from test_framework.mininode import P2PTxInvStore from test_framework.util import ( assert_equal, assert_greater_than_or_equal, assert_raises_rpc_error, connect_nodes, disconnect_nodes, - wait_until, ) @@ -172,7 +171,7 @@ class MempoolPersistTest(BitcoinTestFramework): # check that txn gets broadcast due to unbroadcast logic conn = node0.add_p2p_connection(P2PTxInvStore()) node0.mockscheduler(16*60) # 15 min + 1 for buffer - wait_until(lambda: len(conn.get_invs()) == 1) + self.wait_until(lambda: len(conn.get_invs()) == 1) if __name__ == '__main__': MempoolPersistTest().main() diff --git a/test/functional/mempool_unbroadcast.py b/test/functional/mempool_unbroadcast.py index 365d011157..abd5a03d95 100755 --- a/test/functional/mempool_unbroadcast.py +++ b/test/functional/mempool_unbroadcast.py @@ -7,7 +7,7 @@ to peers until a GETDATA is received.""" import time -from test_framework.mininode import P2PTxInvStore +from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 63d1ccfb36..b13740750f 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -20,7 +20,7 @@ from test_framework.messages import ( CBlockHeader, BLOCK_HEADER_SIZE, ) -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py index 5c7e27a3a8..80f262d0d3 100755 --- a/test/functional/p2p_addr_relay.py +++ b/test/functional/p2p_addr_relay.py @@ -12,9 +12,7 @@ from test_framework.messages import ( NODE_WITNESS, msg_addr, ) -from test_framework.mininode import ( - P2PInterface, -) +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, diff --git a/test/functional/p2p_blockfilters.py b/test/functional/p2p_blockfilters.py index a9e86bd2fc..84178d0dd7 100755 --- a/test/functional/p2p_blockfilters.py +++ b/test/functional/p2p_blockfilters.py @@ -18,13 +18,12 @@ from test_framework.messages import ( ser_uint256, uint256_from_str, ) -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, connect_nodes, disconnect_nodes, - wait_until, ) class CFiltersClient(P2PInterface): @@ -65,11 +64,11 @@ class CompactFiltersTest(BitcoinTestFramework): disconnect_nodes(self.nodes[0], 1) self.nodes[0].generate(1) - wait_until(lambda: self.nodes[0].getblockcount() == 1000) + self.wait_until(lambda: self.nodes[0].getblockcount() == 1000) stale_block_hash = self.nodes[0].getblockhash(1000) self.nodes[1].generate(1001) - wait_until(lambda: self.nodes[1].getblockcount() == 2000) + self.wait_until(lambda: self.nodes[1].getblockcount() == 2000) # Check that nodes have signalled NODE_COMPACT_FILTERS correctly. assert node0.nServices & NODE_COMPACT_FILTERS != 0 diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py index 27e6b669f6..65259f1869 100755 --- a/test/functional/p2p_blocksonly.py +++ b/test/functional/p2p_blocksonly.py @@ -5,7 +5,7 @@ """Test p2p blocksonly""" from test_framework.messages import msg_tx, CTransaction, FromHex -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal diff --git a/test/functional/p2p_compactblocks.py b/test/functional/p2p_compactblocks.py index 225d393e1b..fdae7fb68b 100755 --- a/test/functional/p2p_compactblocks.py +++ b/test/functional/p2p_compactblocks.py @@ -11,10 +11,10 @@ import random from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment from test_framework.messages import BlockTransactions, BlockTransactionsRequest, calculate_shortid, CBlock, CBlockHeader, CInv, COutPoint, CTransaction, CTxIn, CTxInWitness, CTxOut, FromHex, HeaderAndShortIDs, msg_no_witness_block, msg_no_witness_blocktxn, msg_cmpctblock, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_sendcmpct, msg_sendheaders, msg_tx, msg_block, msg_blocktxn, MSG_BLOCK, MSG_CMPCT_BLOCK, MSG_WITNESS_FLAG, NODE_NETWORK, P2PHeaderAndShortIDs, PrefilledTransaction, ser_uint256, ToHex -from test_framework.mininode import mininode_lock, P2PInterface +from test_framework.p2p import p2p_lock, P2PInterface from test_framework.script import CScript, OP_TRUE, OP_DROP from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, wait_until, softfork_active +from test_framework.util import assert_equal, softfork_active # TestP2PConn: A peer we use to send messages to bitcoind, and store responses. class TestP2PConn(P2PInterface): @@ -48,12 +48,12 @@ class TestP2PConn(P2PInterface): self.block_announced = True self.announced_blockhashes.add(x.hash) - # Requires caller to hold mininode_lock + # Requires caller to hold p2p_lock def received_block_announcement(self): return self.block_announced def clear_block_announcement(self): - with mininode_lock: + with p2p_lock: self.block_announced = False self.last_message.pop("inv", None) self.last_message.pop("headers", None) @@ -73,7 +73,7 @@ class TestP2PConn(P2PInterface): def request_headers_and_sync(self, locator, hashstop=0): self.clear_block_announcement() self.get_headers(locator, hashstop) - wait_until(self.received_block_announcement, timeout=30, lock=mininode_lock) + self.wait_until(self.received_block_announcement, timeout=30) self.clear_block_announcement() # Block until a block announcement for a particular block hash is @@ -81,7 +81,7 @@ class TestP2PConn(P2PInterface): def wait_for_block_announcement(self, block_hash, timeout=30): def received_hash(): return (block_hash in self.announced_blockhashes) - wait_until(received_hash, timeout=timeout, lock=mininode_lock) + self.wait_until(received_hash, timeout=timeout) def send_await_disconnect(self, message, timeout=30): """Sends a message to the node and wait for disconnect. @@ -89,7 +89,7 @@ class TestP2PConn(P2PInterface): 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) - wait_until(lambda: not self.is_connected, timeout=timeout, lock=mininode_lock) + self.wait_for_disconnect(timeout) class CompactBlocksTest(BitcoinTestFramework): def set_test_params(self): @@ -154,8 +154,8 @@ class CompactBlocksTest(BitcoinTestFramework): # Make sure we get a SENDCMPCT message from our peer def received_sendcmpct(): return (len(test_node.last_sendcmpct) > 0) - wait_until(received_sendcmpct, timeout=30, lock=mininode_lock) - with mininode_lock: + test_node.wait_until(received_sendcmpct, timeout=30) + with p2p_lock: # Check that the first version received is the preferred one assert_equal(test_node.last_sendcmpct[0].version, preferred_version) # And that we receive versions down to 1. @@ -170,7 +170,7 @@ class CompactBlocksTest(BitcoinTestFramework): peer.wait_for_block_announcement(block_hash, timeout=30) assert peer.block_announced - with mininode_lock: + with p2p_lock: assert predicate(peer), ( "block_hash={!r}, cmpctblock={!r}, inv={!r}".format( block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None))) @@ -294,11 +294,11 @@ class CompactBlocksTest(BitcoinTestFramework): block.rehash() # Wait until the block was announced (via compact blocks) - wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock) + test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) # Now fetch and check the compact block header_and_shortids = None - with mininode_lock: + with p2p_lock: # Convert the on-the-wire representation to absolute indexes header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids) self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block) @@ -308,11 +308,11 @@ class CompactBlocksTest(BitcoinTestFramework): inv = CInv(MSG_CMPCT_BLOCK, block_hash) test_node.send_message(msg_getdata([inv])) - wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock) + test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) # Now fetch and check the compact block header_and_shortids = None - with mininode_lock: + with p2p_lock: # Convert the on-the-wire representation to absolute indexes header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids) self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block) @@ -378,7 +378,7 @@ class CompactBlocksTest(BitcoinTestFramework): if announce == "inv": test_node.send_message(msg_inv([CInv(MSG_BLOCK, block.sha256)])) - wait_until(lambda: "getheaders" in test_node.last_message, timeout=30, lock=mininode_lock) + test_node.wait_until(lambda: "getheaders" in test_node.last_message, timeout=30) test_node.send_header_for_blocks([block]) else: test_node.send_header_for_blocks([block]) @@ -397,7 +397,7 @@ class CompactBlocksTest(BitcoinTestFramework): test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock) # Expect a getblocktxn message. - with mininode_lock: + with p2p_lock: assert "getblocktxn" in test_node.last_message absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute() assert_equal(absolute_indexes, [0]) # should be a coinbase request @@ -439,7 +439,7 @@ class CompactBlocksTest(BitcoinTestFramework): def test_getblocktxn_response(compact_block, peer, expected_result): msg = msg_cmpctblock(compact_block.to_p2p()) peer.send_and_ping(msg) - with mininode_lock: + with p2p_lock: assert "getblocktxn" in peer.last_message absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute() assert_equal(absolute_indexes, expected_result) @@ -504,13 +504,13 @@ class CompactBlocksTest(BitcoinTestFramework): assert tx.hash in mempool # Clear out last request. - with mininode_lock: + with p2p_lock: test_node.last_message.pop("getblocktxn", None) # Send compact block comp_block.initialize_from_block(block, prefill_list=[0], use_witness=with_witness) test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256) - with mininode_lock: + with p2p_lock: # Shouldn't have gotten a request for any transaction assert "getblocktxn" not in test_node.last_message @@ -537,7 +537,7 @@ class CompactBlocksTest(BitcoinTestFramework): comp_block.initialize_from_block(block, prefill_list=[0], use_witness=(version == 2)) test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p())) absolute_indexes = [] - with mininode_lock: + with p2p_lock: assert "getblocktxn" in test_node.last_message absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute() assert_equal(absolute_indexes, [6, 7, 8, 9, 10]) @@ -588,10 +588,10 @@ class CompactBlocksTest(BitcoinTestFramework): num_to_request = random.randint(1, len(block.vtx)) msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request))) test_node.send_message(msg) - wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10, lock=mininode_lock) + test_node.wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10) [tx.calc_sha256() for tx in block.vtx] - with mininode_lock: + with p2p_lock: assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int(block_hash, 16)) all_indices = msg.block_txn_request.to_absolute() for index in all_indices: @@ -611,11 +611,11 @@ class CompactBlocksTest(BitcoinTestFramework): # allowed depth for a blocktxn response. block_hash = node.getblockhash(current_height) msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0]) - with mininode_lock: + with p2p_lock: test_node.last_message.pop("block", None) test_node.last_message.pop("blocktxn", None) test_node.send_and_ping(msg) - with mininode_lock: + with p2p_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16)) assert "blocktxn" not in test_node.last_message @@ -628,21 +628,21 @@ class CompactBlocksTest(BitcoinTestFramework): for _ in range(MAX_CMPCTBLOCK_DEPTH + 1): test_node.clear_block_announcement() new_blocks.append(node.generate(1)[0]) - wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) + test_node.wait_until(test_node.received_block_announcement, timeout=30) test_node.clear_block_announcement() test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) - wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30, lock=mininode_lock) + test_node.wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30) test_node.clear_block_announcement() node.generate(1) - wait_until(test_node.received_block_announcement, timeout=30, lock=mininode_lock) + test_node.wait_until(test_node.received_block_announcement, timeout=30) test_node.clear_block_announcement() - with mininode_lock: + with p2p_lock: test_node.last_message.pop("block", None) test_node.send_message(msg_getdata([CInv(MSG_CMPCT_BLOCK, int(new_blocks[0], 16))])) - wait_until(lambda: "block" in test_node.last_message, timeout=30, lock=mininode_lock) - with mininode_lock: + test_node.wait_until(lambda: "block" in test_node.last_message, timeout=30) + with p2p_lock: test_node.last_message["block"].block.calc_sha256() assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16)) @@ -670,10 +670,10 @@ class CompactBlocksTest(BitcoinTestFramework): # (to avoid fingerprinting attacks). msg = msg_getblocktxn() msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0]) - with mininode_lock: + with p2p_lock: test_node.last_message.pop("blocktxn", None) test_node.send_and_ping(msg) - with mininode_lock: + with p2p_lock: assert "blocktxn" not in test_node.last_message def test_end_to_end_block_relay(self, listeners): @@ -689,8 +689,8 @@ class CompactBlocksTest(BitcoinTestFramework): node.submitblock(ToHex(block)) for l in listeners: - wait_until(lambda: "cmpctblock" in l.last_message, timeout=30, lock=mininode_lock) - with mininode_lock: + l.wait_until(lambda: "cmpctblock" in l.last_message, timeout=30) + with p2p_lock: for l in listeners: l.last_message["cmpctblock"].header_and_shortids.header.calc_sha256() assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256) @@ -747,7 +747,7 @@ class CompactBlocksTest(BitcoinTestFramework): cmpct_block.initialize_from_block(block) msg = msg_cmpctblock(cmpct_block.to_p2p()) peer.send_and_ping(msg) - with mininode_lock: + with p2p_lock: assert "getblocktxn" in peer.last_message return block, cmpct_block diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index 09b9ebeb2d..b7c2a306eb 100755 --- a/test/functional/p2p_disconnect_ban.py +++ b/test/functional/p2p_disconnect_ban.py @@ -10,7 +10,6 @@ from test_framework.util import ( assert_equal, assert_raises_rpc_error, connect_nodes, - wait_until, ) class DisconnectBanTest(BitcoinTestFramework): @@ -28,7 +27,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("setban: successfully ban single IP address") assert_equal(len(self.nodes[1].getpeerinfo()), 2) # node1 should have 2 connections to node0 at this point self.nodes[1].setban(subnet="127.0.0.1", command="add") - wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) + self.wait_until(lambda: len(self.nodes[1].getpeerinfo()) == 0, timeout=10) assert_equal(len(self.nodes[1].getpeerinfo()), 0) # all nodes must be disconnected at this point assert_equal(len(self.nodes[1].listbanned()), 1) @@ -95,7 +94,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("disconnectnode: successfully disconnect node by address") address1 = self.nodes[0].getpeerinfo()[0]['addr'] self.nodes[0].disconnectnode(address=address1) - wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] self.log.info("disconnectnode: successfully reconnect node") @@ -106,7 +105,7 @@ class DisconnectBanTest(BitcoinTestFramework): self.log.info("disconnectnode: successfully disconnect node by node id") id1 = self.nodes[0].getpeerinfo()[0]['id'] self.nodes[0].disconnectnode(nodeid=id1) - wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) + self.wait_until(lambda: len(self.nodes[0].getpeerinfo()) == 1, timeout=10) assert not [node for node in self.nodes[0].getpeerinfo() if node['id'] == id1] if __name__ == '__main__': diff --git a/test/functional/p2p_dos_header_tree.py b/test/functional/p2p_dos_header_tree.py index f8552cf53d..7dd8c3146b 100755 --- a/test/functional/p2p_dos_header_tree.py +++ b/test/functional/p2p_dos_header_tree.py @@ -8,7 +8,7 @@ from test_framework.messages import ( CBlockHeader, FromHex, ) -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, msg_headers, ) diff --git a/test/functional/p2p_eviction.py b/test/functional/p2p_eviction.py index b2b3a89aab..72a255991c 100755 --- a/test/functional/p2p_eviction.py +++ b/test/functional/p2p_eviction.py @@ -15,11 +15,11 @@ Therefore, this test is limited to the remaining protection criteria. import time -from test_framework.test_framework import BitcoinTestFramework -from test_framework.mininode import P2PInterface, P2PDataStore -from test_framework.util import assert_equal, wait_until from test_framework.blocktools import create_block, create_coinbase from test_framework.messages import CTransaction, FromHex, msg_pong, msg_tx +from test_framework.p2p import P2PDataStore, P2PInterface +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal class SlowP2PDataStore(P2PDataStore): @@ -92,7 +92,7 @@ class P2PEvict(BitcoinTestFramework): for _ in range(8): fastpeer = node.add_p2p_connection(P2PInterface()) current_peer += 1 - wait_until(lambda: "ping" in fastpeer.last_message, timeout=10) + self.wait_until(lambda: "ping" in fastpeer.last_message, timeout=10) # Make sure by asking the node what the actual min pings are peerinfo = node.getpeerinfo() diff --git a/test/functional/p2p_feefilter.py b/test/functional/p2p_feefilter.py index 3a9b8dfbd7..0c07b56a69 100755 --- a/test/functional/p2p_feefilter.py +++ b/test/functional/p2p_feefilter.py @@ -7,7 +7,7 @@ from decimal import Decimal from test_framework.messages import MSG_TX, MSG_WTX, msg_feefilter -from test_framework.mininode import mininode_lock, P2PInterface +from test_framework.p2p import P2PInterface, p2p_lock from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal @@ -23,7 +23,7 @@ class FeefilterConn(P2PInterface): self.feefilter_received = True def assert_feefilter_received(self, recv: bool): - with mininode_lock: + with p2p_lock: assert_equal(self.feefilter_received, recv) @@ -39,10 +39,10 @@ class TestP2PConn(P2PInterface): def wait_for_invs_to_match(self, invs_expected): invs_expected.sort() - self.wait_until(lambda: invs_expected == sorted(self.txinvs), timeout=60) + self.wait_until(lambda: invs_expected == sorted(self.txinvs)) def clear_invs(self): - with mininode_lock: + with p2p_lock: self.txinvs = [] diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py index ce3856fc95..613d96eaad 100755 --- a/test/functional/p2p_filter.py +++ b/test/functional/p2p_filter.py @@ -19,7 +19,7 @@ from test_framework.messages import ( msg_mempool, msg_version, ) -from test_framework.mininode import P2PInterface, mininode_lock +from test_framework.p2p import P2PInterface, p2p_lock from test_framework.script import MAX_SCRIPT_ELEMENT_SIZE from test_framework.test_framework import BitcoinTestFramework @@ -60,22 +60,22 @@ class P2PBloomFilter(P2PInterface): @property def tx_received(self): - with mininode_lock: + with p2p_lock: return self._tx_received @tx_received.setter def tx_received(self, value): - with mininode_lock: + with p2p_lock: self._tx_received = value @property def merkleblock_received(self): - with mininode_lock: + with p2p_lock: return self._merkleblock_received @merkleblock_received.setter def merkleblock_received(self, value): - with mininode_lock: + with p2p_lock: self._merkleblock_received = value diff --git a/test/functional/p2p_fingerprint.py b/test/functional/p2p_fingerprint.py index d743abe681..aaf862e6c8 100755 --- a/test/functional/p2p_fingerprint.py +++ b/test/functional/p2p_fingerprint.py @@ -12,7 +12,7 @@ import time from test_framework.blocktools import (create_block, create_coinbase) from test_framework.messages import CInv, MSG_BLOCK -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, msg_headers, msg_block, @@ -22,9 +22,9 @@ from test_framework.mininode import ( from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, ) + class P2PFingerprintTest(BitcoinTestFramework): def set_test_params(self): self.setup_clean_chain = True @@ -102,12 +102,12 @@ class P2PFingerprintTest(BitcoinTestFramework): # Check that getdata request for stale block succeeds self.send_block_request(stale_hash, node0) test_function = lambda: self.last_block_equals(stale_hash, node0) - wait_until(test_function, timeout=3) + self.wait_until(test_function, timeout=3) # Check that getheader request for stale block header succeeds self.send_header_request(stale_hash, node0) test_function = lambda: self.last_header_equals(stale_hash, node0) - wait_until(test_function, timeout=3) + self.wait_until(test_function, timeout=3) # Longest chain is extended so stale is much older than chain tip self.nodes[0].setmocktime(0) @@ -138,11 +138,11 @@ class P2PFingerprintTest(BitcoinTestFramework): self.send_block_request(block_hash, node0) test_function = lambda: self.last_block_equals(block_hash, node0) - wait_until(test_function, timeout=3) + self.wait_until(test_function, timeout=3) self.send_header_request(block_hash, node0) test_function = lambda: self.last_header_equals(block_hash, node0) - wait_until(test_function, timeout=3) + self.wait_until(test_function, timeout=3) if __name__ == '__main__': P2PFingerprintTest().main() diff --git a/test/functional/p2p_getaddr_caching.py b/test/functional/p2p_getaddr_caching.py index c9278eab92..6622ea9ec2 100755 --- a/test/functional/p2p_getaddr_caching.py +++ b/test/functional/p2p_getaddr_caching.py @@ -12,9 +12,9 @@ from test_framework.messages import ( msg_addr, msg_getaddr, ) -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, - mininode_lock + p2p_lock ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -44,7 +44,7 @@ class AddrReceiver(P2PInterface): self.received_addrs = None def get_received_addrs(self): - with mininode_lock: + with p2p_lock: return self.received_addrs def on_addr(self, message): diff --git a/test/functional/p2p_getdata.py b/test/functional/p2p_getdata.py index d1b11c2c61..51921a8ab5 100755 --- a/test/functional/p2p_getdata.py +++ b/test/functional/p2p_getdata.py @@ -9,7 +9,7 @@ from test_framework.messages import ( CInv, msg_getdata, ) -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework diff --git a/test/functional/p2p_invalid_block.py b/test/functional/p2p_invalid_block.py index e280a62997..b2c3c5d45f 100755 --- a/test/functional/p2p_invalid_block.py +++ b/test/functional/p2p_invalid_block.py @@ -14,7 +14,7 @@ import copy from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script from test_framework.messages import COIN -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal diff --git a/test/functional/p2p_invalid_locator.py b/test/functional/p2p_invalid_locator.py index 0155eb21f0..24328c2919 100755 --- a/test/functional/p2p_invalid_locator.py +++ b/test/functional/p2p_invalid_locator.py @@ -6,7 +6,7 @@ """ from test_framework.messages import msg_getheaders, msg_getblocks, MAX_LOCATOR_SZ -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py index d9a9ae5188..fe57057a83 100755 --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -17,14 +17,13 @@ from test_framework.messages import ( MSG_TX, ser_string, ) -from test_framework.mininode import ( +from test_framework.p2p import ( P2PDataStore, P2PInterface, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, ) VALID_DATA_LIMIT = MAX_PROTOCOL_MESSAGE_LENGTH - 5 # Account for the 5-byte length prefix @@ -70,7 +69,7 @@ class InvalidMessagesTest(BitcoinTestFramework): before = int(self.nodes[0].getnettotals()['totalbytesrecv']) conn.send_raw_message(msg[:cut_pos]) # Wait until node has processed the first half of the message - wait_until(lambda: int(self.nodes[0].getnettotals()['totalbytesrecv']) != before) + self.wait_until(lambda: int(self.nodes[0].getnettotals()['totalbytesrecv']) != before) middle = int(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 diff --git a/test/functional/p2p_invalid_tx.py b/test/functional/p2p_invalid_tx.py index c70a892463..a0ef6c9d6e 100755 --- a/test/functional/p2p_invalid_tx.py +++ b/test/functional/p2p_invalid_tx.py @@ -13,11 +13,10 @@ from test_framework.messages import ( CTxIn, CTxOut, ) -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, ) from data import invalid_txs @@ -146,7 +145,7 @@ class InvalidTxRequestTest(BitcoinTestFramework): # tx_orphan_no_fee, because it has too low fee (p2ps[0] is not disconnected for relaying that tx) # tx_orphan_invaid, because it has negative fee (p2ps[1] is disconnected for relaying that tx) - wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected + self.wait_until(lambda: 1 == len(node.getpeerinfo()), timeout=12) # p2ps[1] is no longer connected assert_equal(expected_mempool, set(node.getrawmempool())) self.log.info('Test orphan pool overflow') diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py index 79bf7b2e7c..4b32d60db0 100755 --- a/test/functional/p2p_leak.py +++ b/test/functional/p2p_leak.py @@ -17,12 +17,11 @@ from test_framework.messages import ( msg_ping, msg_version, ) -from test_framework.mininode import mininode_lock, P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_greater_than_or_equal, - wait_until, ) DISCOURAGEMENT_THRESHOLD = 100 @@ -114,9 +113,9 @@ class P2PLeakTest(BitcoinTestFramework): # verack, since we never sent one no_verack_idle_peer.wait_for_verack() - wait_until(lambda: no_version_disconnect_peer.ever_connected, timeout=10, lock=mininode_lock) - wait_until(lambda: no_version_idle_peer.ever_connected, timeout=10, lock=mininode_lock) - wait_until(lambda: no_verack_idle_peer.version_received, timeout=10, lock=mininode_lock) + no_version_disconnect_peer.wait_until(lambda: no_version_disconnect_peer.ever_connected, check_connected=False) + no_version_idle_peer.wait_until(lambda: no_version_idle_peer.ever_connected) + no_verack_idle_peer.wait_until(lambda: no_verack_idle_peer.version_received) # Mine a block and make sure that it's not sent to the connected peers self.nodes[0].generate(nblocks=1) diff --git a/test/functional/p2p_leak_tx.py b/test/functional/p2p_leak_tx.py index da30ad5977..9e761db03f 100755 --- a/test/functional/p2p_leak_tx.py +++ b/test/functional/p2p_leak_tx.py @@ -5,7 +5,7 @@ """Test that we don't leak txs to inbound peers that we haven't yet announced to""" from test_framework.messages import msg_getdata, CInv, MSG_TX -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, diff --git a/test/functional/p2p_nobloomfilter_messages.py b/test/functional/p2p_nobloomfilter_messages.py index accc5dc23c..c2311cb197 100755 --- a/test/functional/p2p_nobloomfilter_messages.py +++ b/test/functional/p2p_nobloomfilter_messages.py @@ -12,7 +12,7 @@ Test that, when bloom filters are not enabled, peers are disconnected if: """ from test_framework.messages import msg_mempool, msg_filteradd, msg_filterload, msg_filterclear -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index a2f6ea538c..2c9cbea5e4 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -9,13 +9,12 @@ and that it responds to getdata requests for blocks correctly: - send a block within 288 + 2 of the tip - disconnect peers who request blocks older than that.""" from test_framework.messages import CInv, MSG_BLOCK, msg_getdata, msg_verack, NODE_NETWORK_LIMITED, NODE_WITNESS -from test_framework.mininode import P2PInterface, mininode_lock +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, disconnect_nodes, connect_nodes, - wait_until, ) @@ -28,7 +27,7 @@ class P2PIgnoreInv(P2PInterface): self.firstAddrnServices = message.addrs[0].nServices def wait_for_addr(self, timeout=5): test_function = lambda: self.last_message.get("addr") - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def send_getdata_for_block(self, blockhash): getdata_request = msg_getdata() getdata_request.inv.append(CInv(MSG_BLOCK, int(blockhash, 16))) diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py index 254352c816..3ec36edb41 100755 --- a/test/functional/p2p_permissions.py +++ b/test/functional/p2p_permissions.py @@ -13,7 +13,7 @@ from test_framework.messages import ( CTxInWitness, FromHex, ) -from test_framework.mininode import P2PDataStore +from test_framework.p2p import P2PDataStore from test_framework.script import ( CScript, OP_TRUE, @@ -24,7 +24,6 @@ from test_framework.util import ( assert_equal, connect_nodes, p2p_port, - wait_until, ) @@ -109,7 +108,7 @@ class P2PPermissionsTests(BitcoinTestFramework): self.sync_all() self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs") - # A python mininode is needed to send the raw transaction directly. If a full node was used, it could only + # A test framework p2p connection is needed to send the raw transaction directly. If a full node was used, it could only # rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would # currently not request a txid that is already in the mempool. self.restart_node(1, extra_args=["-whitelist=forcerelay@127.0.0.1"]) @@ -137,7 +136,7 @@ class P2PPermissionsTests(BitcoinTestFramework): connect_nodes(self.nodes[1], 0) with self.nodes[1].assert_debug_log(["Force relaying tx {} from peer=0".format(txid)]): p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1]) - wait_until(lambda: txid in self.nodes[0].getrawmempool()) + self.wait_until(lambda: txid in self.nodes[0].getrawmempool()) self.log.debug("Check that node[1] will not send an invalid tx to node[0]") tx.vout[0].nValue += 1 diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py index 5f5fd3e104..888e986fba 100755 --- a/test/functional/p2p_ping.py +++ b/test/functional/p2p_ping.py @@ -8,7 +8,7 @@ import time from test_framework.messages import msg_pong -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 564e49f3d8..9503391030 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -25,6 +25,7 @@ from test_framework.messages import ( MSG_BLOCK, MSG_TX, MSG_WITNESS_FLAG, + MSG_WITNESS_TX, MSG_WTX, NODE_NETWORK, NODE_WITNESS, @@ -42,9 +43,9 @@ from test_framework.messages import ( uint256_from_str, FromHex, ) -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, - mininode_lock, + p2p_lock, ) from test_framework.script import ( CScript, @@ -83,7 +84,6 @@ from test_framework.util import ( softfork_active, hex_str_to_bytes, assert_raises_rpc_error, - wait_until, ) # The versionbit bit used to signal activation of SegWit @@ -153,8 +153,8 @@ class TestP2PConn(P2PInterface): self.lastgetdata = [] self.wtxidrelay = wtxidrelay - # Avoid sending out msg_getdata in the mininode thread as a reply to invs. - # They are not needed and would only lead to races because we send msg_getdata out in the test thread + # Don't send getdata message replies to invs automatically. + # We'll send the getdata messages explicitly in the test logic. def on_inv(self, message): pass @@ -177,7 +177,7 @@ class TestP2PConn(P2PInterface): if success: # sanity check assert (self.wtxidrelay and use_wtxid) or (not self.wtxidrelay and not use_wtxid) - with mininode_lock: + with p2p_lock: self.last_message.pop("getdata", None) if use_wtxid: wtxid = tx.calc_sha256(True) @@ -195,7 +195,7 @@ class TestP2PConn(P2PInterface): assert not self.last_message.get("getdata") def announce_block_and_wait_for_getdata(self, block, use_header, timeout=60): - with mininode_lock: + with p2p_lock: self.last_message.pop("getdata", None) self.last_message.pop("getheaders", None) msg = msg_headers() @@ -209,7 +209,7 @@ class TestP2PConn(P2PInterface): self.wait_for_getdata([block.sha256]) def request_block(self, blockhash, inv_type, timeout=60): - with mininode_lock: + with p2p_lock: self.last_message.pop("block", None) self.send_message(msg_getdata(inv=[CInv(inv_type, blockhash)])) self.wait_for_block(blockhash, timeout) @@ -2114,7 +2114,7 @@ class SegWitTest(BitcoinTestFramework): # Check wtxidrelay feature negotiation message through connecting a new peer def received_wtxidrelay(): return (len(self.wtx_node.last_wtxidrelay) > 0) - wait_until(received_wtxidrelay, timeout=60, lock=mininode_lock) + self.wtx_node.wait_until(received_wtxidrelay) # Create a Segwit output from the latest UTXO # and announce it to the network @@ -2138,27 +2138,27 @@ class SegWitTest(BitcoinTestFramework): # Announce Segwit transaction with wtxid # and wait for getdata self.wtx_node.announce_tx_and_wait_for_getdata(tx2, use_wtxid=True) - with mininode_lock: + with p2p_lock: lgd = self.wtx_node.lastgetdata[:] assert_equal(lgd, [CInv(MSG_WTX, tx2.calc_sha256(True))]) # Announce Segwit transaction from non wtxidrelay peer # and wait for getdata self.tx_node.announce_tx_and_wait_for_getdata(tx2, use_wtxid=False) - with mininode_lock: + with p2p_lock: lgd = self.tx_node.lastgetdata[:] assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx2.sha256)]) # Send tx2 through; it's an orphan so won't be accepted - with mininode_lock: + with p2p_lock: self.wtx_node.last_message.pop("getdata", None) test_transaction_acceptance(self.nodes[0], self.wtx_node, tx2, with_witness=True, accepted=False) # Expect a request for parent (tx) by txid despite use of WTX peer self.wtx_node.wait_for_getdata([tx.sha256], 60) - with mininode_lock: + with p2p_lock: lgd = self.wtx_node.lastgetdata[:] - assert_equal(lgd, [CInv(MSG_TX|MSG_WITNESS_FLAG, tx.sha256)]) + assert_equal(lgd, [CInv(MSG_WITNESS_TX, tx.sha256)]) # Send tx through test_transaction_acceptance(self.nodes[0], self.wtx_node, tx, with_witness=False, accepted=True) diff --git a/test/functional/p2p_sendheaders.py b/test/functional/p2p_sendheaders.py index 126a46bd53..04e6ec4172 100755 --- a/test/functional/p2p_sendheaders.py +++ b/test/functional/p2p_sendheaders.py @@ -87,11 +87,11 @@ e. Announce one more that doesn't connect. """ from test_framework.blocktools import create_block, create_coinbase from test_framework.messages import CInv -from test_framework.mininode import ( +from test_framework.p2p import ( CBlockHeader, NODE_WITNESS, P2PInterface, - mininode_lock, + p2p_lock, MSG_BLOCK, msg_block, msg_getblocks, @@ -104,7 +104,6 @@ from test_framework.mininode import ( from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, ) DIRECT_FETCH_RESPONSE_TIME = 0.05 @@ -147,7 +146,7 @@ class BaseNode(P2PInterface): def wait_for_block_announcement(self, block_hash, timeout=60): test_function = lambda: self.last_blockhash_announced == block_hash - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def on_inv(self, message): self.block_announced = True @@ -163,7 +162,7 @@ class BaseNode(P2PInterface): self.last_blockhash_announced = message.headers[-1].sha256 def clear_block_announcements(self): - with mininode_lock: + with p2p_lock: self.block_announced = False self.last_message.pop("inv", None) self.last_message.pop("headers", None) @@ -174,8 +173,8 @@ class BaseNode(P2PInterface): """Test whether the last headers announcements received are right. Headers may be announced across more than one message.""" test_function = lambda: (len(self.recent_headers_announced) >= len(headers)) - wait_until(test_function, timeout=60, lock=mininode_lock) - with mininode_lock: + self.wait_until(test_function) + with p2p_lock: assert_equal(self.recent_headers_announced, headers) self.block_announced = False self.last_message.pop("headers", None) @@ -186,9 +185,9 @@ class BaseNode(P2PInterface): inv should be a list of block hashes.""" test_function = lambda: self.block_announced - wait_until(test_function, timeout=60, lock=mininode_lock) + self.wait_until(test_function) - with mininode_lock: + with p2p_lock: compare_inv = [] if "inv" in self.last_message: compare_inv = [x.hash for x in self.last_message["inv"].inv] @@ -298,7 +297,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.send_header_for_blocks([new_block]) test_node.wait_for_getdata([new_block.sha256]) test_node.send_and_ping(msg_block(new_block)) # make sure this block is processed - wait_until(lambda: inv_node.block_announced, timeout=60, lock=mininode_lock) + inv_node.wait_until(lambda: inv_node.block_announced) inv_node.clear_block_announcements() test_node.clear_block_announcements() @@ -456,7 +455,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.send_header_for_blocks(blocks) test_node.sync_with_ping() # should not have received any getdata messages - with mininode_lock: + with p2p_lock: assert "getdata" not in test_node.last_message # This time, direct fetch should work @@ -494,7 +493,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.last_message.pop("getdata", None) test_node.send_header_for_blocks(blocks[0:1]) test_node.sync_with_ping() - with mininode_lock: + with p2p_lock: assert "getdata" not in test_node.last_message # Announcing one more block on fork should trigger direct fetch for @@ -513,7 +512,7 @@ class SendHeadersTest(BitcoinTestFramework): test_node.last_message.pop("getdata", None) test_node.send_header_for_blocks(blocks[18:19]) test_node.sync_with_ping() - with mininode_lock: + with p2p_lock: assert "getdata" not in test_node.last_message self.log.info("Part 4: success!") @@ -536,7 +535,7 @@ class SendHeadersTest(BitcoinTestFramework): block_time += 1 height += 1 # Send the header of the second block -> this won't connect. - with mininode_lock: + with p2p_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[1]]) test_node.wait_for_getheaders() @@ -559,7 +558,7 @@ class SendHeadersTest(BitcoinTestFramework): for i in range(1, MAX_UNCONNECTING_HEADERS): # Send a header that doesn't connect, check that we get a getheaders. - with mininode_lock: + with p2p_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[i]]) test_node.wait_for_getheaders() @@ -574,7 +573,7 @@ class SendHeadersTest(BitcoinTestFramework): # before we get disconnected. Should be 5*MAX_UNCONNECTING_HEADERS for i in range(5 * MAX_UNCONNECTING_HEADERS - 1): # Send a header that doesn't connect, check that we get a getheaders. - with mininode_lock: + with p2p_lock: test_node.last_message.pop("getheaders", None) test_node.send_header_for_blocks([blocks[i % len(blocks)]]) test_node.wait_for_getheaders() diff --git a/test/functional/p2p_timeouts.py b/test/functional/p2p_timeouts.py index 5a4fa42988..ce12ce26ce 100755 --- a/test/functional/p2p_timeouts.py +++ b/test/functional/p2p_timeouts.py @@ -24,7 +24,7 @@ from time import sleep from test_framework.messages import msg_ping -from test_framework.mininode import P2PInterface +from test_framework.p2p import P2PInterface from test_framework.test_framework import BitcoinTestFramework diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py index 3ea1c6e5e7..653c7ae43f 100755 --- a/test/functional/p2p_tx_download.py +++ b/test/functional/p2p_tx_download.py @@ -16,14 +16,13 @@ from test_framework.messages import ( msg_inv, msg_notfound, ) -from test_framework.mininode import ( +from test_framework.p2p import ( P2PInterface, - mininode_lock, + p2p_lock, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - wait_until, ) from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE @@ -73,14 +72,14 @@ class TxDownloadTest(BitcoinTestFramework): def getdata_found(peer_index): p = self.nodes[0].p2ps[peer_index] - with mininode_lock: + with p2p_lock: return p.last_message.get("getdata") and p.last_message["getdata"].inv[-1].hash == txid node_0_mocktime = int(time.time()) while outstanding_peer_index: node_0_mocktime += MAX_GETDATA_INBOUND_WAIT self.nodes[0].setmocktime(node_0_mocktime) - wait_until(lambda: any(getdata_found(i) for i in outstanding_peer_index)) + self.wait_until(lambda: any(getdata_found(i) for i in outstanding_peer_index)) for i in outstanding_peer_index: if getdata_found(i): outstanding_peer_index.remove(i) @@ -134,24 +133,24 @@ class TxDownloadTest(BitcoinTestFramework): p = self.nodes[0].p2ps[0] - with mininode_lock: + with p2p_lock: p.tx_getdata_count = 0 p.send_message(msg_inv([CInv(t=MSG_WTX, h=i) for i in txids])) - wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT, lock=mininode_lock) - with mininode_lock: + p.wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT) + with p2p_lock: assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT) self.log.info("Now check that if we send a NOTFOUND for a transaction, we'll get one more request") p.send_message(msg_notfound(vec=[CInv(t=MSG_WTX, h=txids[0])])) - wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT + 1, timeout=10, lock=mininode_lock) - with mininode_lock: + p.wait_until(lambda: p.tx_getdata_count >= MAX_GETDATA_IN_FLIGHT + 1, timeout=10) + with p2p_lock: assert_equal(p.tx_getdata_count, MAX_GETDATA_IN_FLIGHT + 1) WAIT_TIME = TX_EXPIRY_INTERVAL // 2 + TX_EXPIRY_INTERVAL self.log.info("if we wait about {} minutes, we should eventually get more requests".format(WAIT_TIME / 60)) self.nodes[0].setmocktime(int(time.time() + WAIT_TIME)) - wait_until(lambda: p.tx_getdata_count == MAX_GETDATA_IN_FLIGHT + 2) + p.wait_until(lambda: p.tx_getdata_count == MAX_GETDATA_IN_FLIGHT + 2) self.nodes[0].setmocktime(0) def test_spurious_notfound(self): diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py index 71b0b0f63a..36b434bce3 100755 --- a/test/functional/p2p_unrequested_blocks.py +++ b/test/functional/p2p_unrequested_blocks.py @@ -55,7 +55,7 @@ import time from test_framework.blocktools import create_block, create_coinbase, create_tx_with_script from test_framework.messages import CBlockHeader, CInv, MSG_BLOCK, msg_block, msg_headers, msg_inv -from test_framework.mininode import mininode_lock, P2PInterface +from test_framework.p2p import p2p_lock, P2PInterface from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, @@ -199,13 +199,13 @@ class AcceptBlockTest(BitcoinTestFramework): # 6. Try to get node to request the missing block. # Poke the node with an inv for block at height 3 and see if that # triggers a getdata on block 2 (it should if block 2 is missing). - with mininode_lock: + with p2p_lock: # Clear state so we can check the getdata request test_node.last_message.pop("getdata", None) test_node.send_message(msg_inv([CInv(MSG_BLOCK, block_h3.sha256)])) test_node.sync_with_ping() - with mininode_lock: + with p2p_lock: getdata = test_node.last_message["getdata"] # Check that the getdata includes the right block diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index 7f4241fb5f..c005584485 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -22,16 +22,6 @@ from decimal import Decimal import http.client import subprocess -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, - assert_greater_than, - assert_greater_than_or_equal, - assert_raises, - assert_raises_rpc_error, - assert_is_hex_string, - assert_is_hash_string, -) from test_framework.blocktools import ( create_block, create_coinbase, @@ -42,8 +32,16 @@ from test_framework.messages import ( FromHex, msg_block, ) -from test_framework.mininode import ( - P2PInterface, +from test_framework.p2p import P2PInterface +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_greater_than, + assert_greater_than_or_equal, + assert_raises, + assert_raises_rpc_error, + assert_is_hex_string, + assert_is_hash_string, ) diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 9404f1e25e..e55f2e6d12 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -17,7 +17,8 @@ class RPCGenerateTest(BitcoinTestFramework): def run_test(self): message = ( - "generate ( nblocks maxtries ) has been replaced by the -generate " + "generate\n" + "has been replaced by the -generate " "cli option. Refer to -help for more information." ) diff --git a/test/functional/rpc_invalidateblock.py b/test/functional/rpc_invalidateblock.py index 1fdc134f97..e788e75557 100755 --- a/test/functional/rpc_invalidateblock.py +++ b/test/functional/rpc_invalidateblock.py @@ -9,7 +9,6 @@ from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR from test_framework.util import ( assert_equal, connect_nodes, - wait_until, ) @@ -57,9 +56,9 @@ class InvalidateTest(BitcoinTestFramework): self.log.info("..and then mine a block") self.nodes[2].generatetoaddress(1, self.nodes[2].get_deterministic_priv_key().address) self.log.info("Verify all nodes are at the right height") - wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5) - wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5) - wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5) + self.wait_until(lambda: self.nodes[2].getblockcount() == 3, timeout=5) + self.wait_until(lambda: self.nodes[0].getblockcount() == 4, timeout=5) + self.wait_until(lambda: self.nodes[1].getblockcount() == 4, timeout=5) self.log.info("Verify that we reconsider all ancestors as well") blocks = self.nodes[1].generatetodescriptor(10, ADDRESS_BCRT1_UNSPENDABLE_DESCRIPTOR) diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index d663815e4c..bc0e5b458e 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -11,6 +11,12 @@ from decimal import Decimal from itertools import product import time +from test_framework.p2p import P2PInterface +import test_framework.messages +from test_framework.messages import ( + NODE_NETWORK, + NODE_WITNESS, +) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_approx, @@ -20,13 +26,6 @@ from test_framework.util import ( assert_raises_rpc_error, connect_nodes, p2p_port, - wait_until, -) -from test_framework.mininode import P2PInterface -import test_framework.messages -from test_framework.messages import ( - NODE_NETWORK, - NODE_WITNESS, ) @@ -93,8 +92,8 @@ class NetTest(BitcoinTestFramework): # the bytes sent/received should change # note ping and pong are 32 bytes each self.nodes[0].ping() - wait_until(lambda: (self.nodes[0].getnettotals()['totalbytessent'] >= net_totals_after['totalbytessent'] + 32 * 2), timeout=1) - wait_until(lambda: (self.nodes[0].getnettotals()['totalbytesrecv'] >= net_totals_after['totalbytesrecv'] + 32 * 2), timeout=1) + self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytessent'] >= net_totals_after['totalbytessent'] + 32 * 2), timeout=1) + self.wait_until(lambda: (self.nodes[0].getnettotals()['totalbytesrecv'] >= net_totals_after['totalbytesrecv'] + 32 * 2), timeout=1) peer_info_after_ping = self.nodes[0].getpeerinfo() for before, after in zip(peer_info, peer_info_after_ping): @@ -113,7 +112,7 @@ class NetTest(BitcoinTestFramework): self.nodes[0].setnetworkactive(state=False) assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], False) # Wait a bit for all sockets to close - wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3) + self.wait_until(lambda: self.nodes[0].getnetworkinfo()['connections'] == 0, timeout=3) with self.nodes[0].assert_debug_log(expected_msgs=['SetNetworkActive: true\n']): self.nodes[0].setnetworkactive(state=True) diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index f7f23bc8f4..1c7dc98d16 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -103,7 +103,16 @@ class PSBTTest(BitcoinTestFramework): final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex'] self.nodes[0].sendrawtransaction(final_tx) - # Get pubkeys + # Manually selected inputs can be locked: + assert_equal(len(self.nodes[0].listlockunspent()), 0) + utxo1 = self.nodes[0].listunspent()[0] + psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0,{"lockUnspents": True})["psbt"] + assert_equal(len(self.nodes[0].listlockunspent()), 1) + + # Locks are ignored for manually selected inputs + self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0) + + # Create p2sh, p2wpkh, and p2wsh addresses pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey'] pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey'] pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey'] diff --git a/test/functional/test_framework/key.py b/test/functional/test_framework/key.py index 912c0ca978..adbffb7dc7 100644 --- a/test/functional/test_framework/key.py +++ b/test/functional/test_framework/key.py @@ -8,22 +8,7 @@ keys, and is trivially vulnerable to side channel attacks. Do not use for anything but tests.""" import random -def modinv(a, n): - """Compute the modular inverse of a modulo n - - See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers. - """ - t1, t2 = 0, 1 - r1, r2 = n, a - while r2 != 0: - q = r1 // r2 - t1, t2 = t2, t1 - q * t2 - r1, r2 = r2, r1 - q * r2 - if r1 > 1: - return None - if t1 < 0: - t1 += n - return t1 +from .util import modinv def jacobi_symbol(n, k): """Compute the Jacobi symbol of n modulo k diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py index 5207b563a1..b4e609df3a 100755 --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -32,7 +32,7 @@ from test_framework.util import hex_str_to_bytes, assert_equal MIN_VERSION_SUPPORTED = 60001 MY_VERSION = 70016 # past wtxid relay -MY_SUBVERSION = b"/python-mininode-tester:0.0.3/" +MY_SUBVERSION = b"/python-p2p-tester:0.0.3/" MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37) MAX_LOCATOR_SZ = 101 @@ -63,6 +63,7 @@ MSG_CMPCT_BLOCK = 4 MSG_WTX = 5 MSG_WITNESS_FLAG = 1 << 30 MSG_TYPE_MASK = 0xffffffff >> 2 +MSG_WITNESS_TX = MSG_TX | MSG_WITNESS_FLAG FILTER_TYPE_BASIC = 0 @@ -244,8 +245,8 @@ class CInv: MSG_TX | MSG_WITNESS_FLAG: "WitnessTx", MSG_BLOCK | MSG_WITNESS_FLAG: "WitnessBlock", MSG_FILTERED_BLOCK: "filtered Block", - 4: "CompactBlock", - 5: "WTX", + MSG_CMPCT_BLOCK: "CompactBlock", + MSG_WTX: "WTX", } def __init__(self, t=0, h=0): @@ -253,12 +254,12 @@ class CInv: self.hash = h def deserialize(self, f): - self.type = struct.unpack("<i", f.read(4))[0] + self.type = struct.unpack("<I", f.read(4))[0] self.hash = deser_uint256(f) def serialize(self): r = b"" - r += struct.pack("<i", self.type) + r += struct.pack("<I", self.type) r += ser_uint256(self.hash) return r diff --git a/test/functional/test_framework/muhash.py b/test/functional/test_framework/muhash.py new file mode 100644 index 0000000000..97d02359cb --- /dev/null +++ b/test/functional/test_framework/muhash.py @@ -0,0 +1,110 @@ +# Copyright (c) 2020 Pieter Wuille +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Native Python MuHash3072 implementation.""" + +import hashlib +import unittest + +from .util import modinv + +def rot32(v, bits): + """Rotate the 32-bit value v left by bits bits.""" + bits %= 32 # Make sure the term below does not throw an exception + return ((v << bits) & 0xffffffff) | (v >> (32 - bits)) + +def chacha20_doubleround(s): + """Apply a ChaCha20 double round to 16-element state array s. + + See https://cr.yp.to/chacha/chacha-20080128.pdf and https://tools.ietf.org/html/rfc8439 + """ + QUARTER_ROUNDS = [(0, 4, 8, 12), + (1, 5, 9, 13), + (2, 6, 10, 14), + (3, 7, 11, 15), + (0, 5, 10, 15), + (1, 6, 11, 12), + (2, 7, 8, 13), + (3, 4, 9, 14)] + + for a, b, c, d in QUARTER_ROUNDS: + s[a] = (s[a] + s[b]) & 0xffffffff + s[d] = rot32(s[d] ^ s[a], 16) + s[c] = (s[c] + s[d]) & 0xffffffff + s[b] = rot32(s[b] ^ s[c], 12) + s[a] = (s[a] + s[b]) & 0xffffffff + s[d] = rot32(s[d] ^ s[a], 8) + s[c] = (s[c] + s[d]) & 0xffffffff + s[b] = rot32(s[b] ^ s[c], 7) + +def chacha20_32_to_384(key32): + """Specialized ChaCha20 implementation with 32-byte key, 0 IV, 384-byte output.""" + # See RFC 8439 section 2.3 for chacha20 parameters + CONSTANTS = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] + + key_bytes = [0]*8 + for i in range(8): + key_bytes[i] = int.from_bytes(key32[(4 * i):(4 * (i+1))], 'little') + + INITIALIZATION_VECTOR = [0] * 4 + init = CONSTANTS + key_bytes + INITIALIZATION_VECTOR + out = bytearray() + for counter in range(6): + init[12] = counter + s = init.copy() + for _ in range(10): + chacha20_doubleround(s) + for i in range(16): + out.extend(((s[i] + init[i]) & 0xffffffff).to_bytes(4, 'little')) + return bytes(out) + +def data_to_num3072(data): + """Hash a 32-byte array data to a 3072-bit number using 6 Chacha20 operations.""" + bytes384 = chacha20_32_to_384(data) + return int.from_bytes(bytes384, 'little') + +class MuHash3072: + """Class representing the MuHash3072 computation of a set. + + See https://cseweb.ucsd.edu/~mihir/papers/inchash.pdf and https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2017-May/014337.html + """ + + MODULUS = 2**3072 - 1103717 + + def __init__(self): + """Initialize for an empty set.""" + self.numerator = 1 + self.denominator = 1 + + def insert(self, data): + """Insert a byte array data in the set.""" + self.numerator = (self.numerator * data_to_num3072(data)) % self.MODULUS + + def remove(self, data): + """Remove a byte array from the set.""" + self.denominator = (self.denominator * data_to_num3072(data)) % self.MODULUS + + def digest(self): + """Extract the final hash. Does not modify this object.""" + val = (self.numerator * modinv(self.denominator, self.MODULUS)) % self.MODULUS + bytes384 = val.to_bytes(384, 'little') + return hashlib.sha256(bytes384).digest() + +class TestFrameworkMuhash(unittest.TestCase): + def test_muhash(self): + muhash = MuHash3072() + muhash.insert([0]*32) + muhash.insert([1] + [0]*31) + muhash.remove([2] + [0]*31) + finalized = muhash.digest() + # This mirrors the result in the C++ MuHash3072 unit test + self.assertEqual(finalized[::-1].hex(), "a44e16d5e34d259b349af21c06e65d653915d2e208e4e03f389af750dc0bfdc3") + + def test_chacha20(self): + def chacha_check(key, result): + self.assertEqual(chacha20_32_to_384(key)[:64].hex(), result) + + # Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 + # Since the nonce is hardcoded to 0 in our function we only use those vectors. + chacha_check([0]*32, "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586") + chacha_check([0]*31 + [1], "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae546963") diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/p2p.py index eaf637fbb8..963a507f53 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/p2p.py @@ -4,10 +4,14 @@ # Copyright (c) 2010-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. -"""Bitcoin P2P network half-a-node. +"""Test objects for interacting with a bitcoind node over the p2p protocol. -This python code was modified from ArtForz' public domain half-a-node, as -found in the mini-node branch of http://github.com/jgarzik/pynode. +The P2PInterface objects interact with the bitcoind nodes under test using the +node's p2p interface. They can be used to send messages to the node, and +callbacks can be registered that execute when messages are received from the +node. Messages are sent to/received from the node on an asyncio event loop. +State held inside the objects must be guarded by the p2p_lock to avoid data +races between the main testing thread and the event loop. P2PConnection: A low-level connection object to a node's P2P interface P2PInterface: A high-level interface object for communicating to a node over P2P @@ -65,9 +69,9 @@ from test_framework.messages import ( NODE_WITNESS, sha256, ) -from test_framework.util import wait_until +from test_framework.util import wait_until_helper -logger = logging.getLogger("TestFramework.mininode") +logger = logging.getLogger("TestFramework.p2p") MESSAGEMAP = { b"addr": msg_addr, @@ -289,7 +293,7 @@ class P2PInterface(P2PConnection): # Track the most recent message of each type. # To wait for a message to be received, pop that message from - # this and use wait_until. + # this and use self.wait_until. self.last_message = {} # A count of the number of ping messages we've sent to the node @@ -320,7 +324,7 @@ class P2PInterface(P2PConnection): We keep a count of how many of each message type has been received and the most recent message of each type.""" - with mininode_lock: + with p2p_lock: try: msgtype = message.msgtype.decode('ascii') self.message_count[msgtype] += 1 @@ -394,7 +398,7 @@ class P2PInterface(P2PConnection): assert self.is_connected return test_function_in() - wait_until(test_function, timeout=timeout, lock=mininode_lock, timeout_factor=self.timeout_factor) + wait_until_helper(test_function, timeout=timeout, lock=p2p_lock, timeout_factor=self.timeout_factor) def wait_for_disconnect(self, timeout=60): test_function = lambda: not self.is_connected @@ -498,7 +502,7 @@ class P2PInterface(P2PConnection): # P2PConnection acquires this lock whenever delivering a message to a P2PInterface. # This lock should be acquired in the thread running the test logic to synchronize # access to any data shared with the P2PInterface or P2PConnection. -mininode_lock = threading.Lock() +p2p_lock = threading.Lock() class NetworkThread(threading.Thread): @@ -518,7 +522,7 @@ class NetworkThread(threading.Thread): def close(self, timeout=10): """Close the connections and network event loop.""" self.network_event_loop.call_soon_threadsafe(self.network_event_loop.stop) - wait_until(lambda: not self.network_event_loop.is_running(), timeout=timeout) + wait_until_helper(lambda: not self.network_event_loop.is_running(), timeout=timeout) self.network_event_loop.close() self.join(timeout) # Safe to remove event loop. @@ -592,7 +596,7 @@ class P2PDataStore(P2PInterface): - if success is False: assert that the node's tip doesn't advance - if reject_reason is set: assert that the correct reject message is logged""" - with mininode_lock: + with p2p_lock: for block in blocks: self.block_store[block.sha256] = block self.last_block_hash = block.sha256 @@ -629,7 +633,7 @@ class P2PDataStore(P2PInterface): - if expect_disconnect is True: Skip the sync with ping - if reject_reason is set: assert that the correct reject message is logged.""" - with mininode_lock: + with p2p_lock: for tx in txs: self.tx_store[tx.sha256] = tx @@ -668,7 +672,7 @@ class P2PTxInvStore(P2PInterface): self.tx_invs_received[i.hash] += 1 def get_invs(self): - with mininode_lock: + with p2p_lock: return list(self.tx_invs_received.keys()) def wait_for_broadcast(self, txns, timeout=60): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 8d402d4888..f41f5129b8 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -20,8 +20,8 @@ import time from .authproxy import JSONRPCException from . import coverage +from .p2p import NetworkThread from .test_node import TestNode -from .mininode import NetworkThread from .util import ( MAX_NODES, PortSeed, @@ -31,7 +31,7 @@ from .util import ( disconnect_nodes, get_datadir_path, initialize_datadir, - wait_until, + wait_until_helper, ) @@ -603,8 +603,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): self.sync_blocks(nodes) self.sync_mempools(nodes) - def wait_until(self, test_function, timeout=60, lock=None): - return wait_until(test_function, timeout=timeout, lock=lock, timeout_factor=self.options.timeout_factor) + def wait_until(self, test_function, timeout=60): + return wait_until_helper(test_function, timeout=timeout, timeout_factor=self.options.timeout_factor) # Private helper methods. These should not be accessed by the subclass test scripts. diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 5eba554a42..d034986821 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -31,7 +31,7 @@ from .util import ( get_auth_cookie, get_rpc_proxy, rpc_url, - wait_until, + wait_until_helper, p2p_port, EncodeDecimal, ) @@ -231,7 +231,7 @@ class TestNode(): if self.version_is_at_least(190000): # getmempoolinfo.loaded is available since commit # bb8ae2c (version 0.19.0) - wait_until(lambda: rpc.getmempoolinfo()['loaded']) + wait_until_helper(lambda: rpc.getmempoolinfo()['loaded'], timeout_factor=self.timeout_factor) # Wait for the node to finish reindex, block import, and # loading the mempool. Usually importing happens fast or # even "immediate" when the node is started. However, there @@ -359,7 +359,7 @@ class TestNode(): return True def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): - wait_until(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor) + wait_until_helper(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor) @contextlib.contextmanager def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): @@ -551,7 +551,7 @@ class TestNode(): assert self.p2ps, self._node_msg("No p2p connection") return self.p2ps[0] - def num_connected_mininodes(self): + 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]) @@ -560,7 +560,7 @@ class TestNode(): for p in self.p2ps: p.peer_disconnect() del self.p2ps[:] - wait_until(lambda: self.num_connected_mininodes() == 0) + wait_until_helper(lambda: self.num_test_p2p_connections() == 0, timeout_factor=self.timeout_factor) class TestNodeCLIAttr: diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index 3362b41209..af7f0b62f4 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -15,6 +15,7 @@ import os import random import re import time +import unittest from . import coverage from .authproxy import AuthServiceProxy, JSONRPCException @@ -225,7 +226,15 @@ def satoshi_round(amount): return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN) -def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0): +def wait_until_helper(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0): + """Sleep until the predicate resolves to be True. + + Warning: Note that this method is not recommended to be used in tests as it is + not aware of the context of the test framework. Using the `wait_until()` members + from `BitcoinTestFramework` or `P2PInterface` class ensures the timeout is + properly scaled. Furthermore, `wait_until()` from `P2PInterface` class in + `p2p.py` has a preset lock. + """ if attempts == float('inf') and timeout == float('inf'): timeout = 60 timeout = timeout * timeout_factor @@ -429,7 +438,7 @@ def disconnect_nodes(from_connection, node_num): raise # wait to disconnect - wait_until(lambda: not get_peer_ids(), timeout=5) + wait_until_helper(lambda: not get_peer_ids(), timeout=5) def connect_nodes(from_connection, node_num): @@ -440,8 +449,8 @@ def connect_nodes(from_connection, node_num): # See comments in net_processing: # * Must have a version message before anything else # * Must have a verack message before anything else - wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo())) - wait_until(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo())) + wait_until_helper(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo())) + wait_until_helper(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo())) # Transaction/Block functions @@ -617,3 +626,33 @@ def find_vout_for_address(node, txid, addr): if any([addr == a for a in tx["vout"][i]["scriptPubKey"]["addresses"]]): return i raise RuntimeError("Vout not found for address: txid=%s, addr=%s" % (txid, addr)) + +def modinv(a, n): + """Compute the modular inverse of a modulo n using the extended Euclidean + Algorithm. See https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers. + """ + # TODO: Change to pow(a, -1, n) available in Python 3.8 + t1, t2 = 0, 1 + r1, r2 = n, a + while r2 != 0: + q = r1 // r2 + t1, t2 = t2, t1 - q * t2 + r1, r2 = r2, r1 - q * r2 + if r1 > 1: + return None + if t1 < 0: + t1 += n + return t1 + +class TestFrameworkUtil(unittest.TestCase): + def test_modinv(self): + test_vectors = [ + [7, 11], + [11, 29], + [90, 13], + [1891, 3797], + [6003722857, 77695236973], + ] + + for a, n in test_vectors: + self.assertEqual(modinv(a, n), pow(a, n-2, n)) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 01232bda3c..578afe5f30 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -69,7 +69,9 @@ TEST_EXIT_SKIPPED = 77 TEST_FRAMEWORK_MODULES = [ "address", "blocktools", + "muhash", "script", + "util", ] EXTENDED_SCRIPTS = [ @@ -105,7 +107,6 @@ BASE_SCRIPTS = [ 'wallet_listtransactions.py', # vv Tests less than 60s vv 'p2p_sendheaders.py', - 'wallet_zapwallettxes.py', 'wallet_importmulti.py', 'mempool_limit.py', 'rpc_txoutproof.py', diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 71a1a3f4f6..147c43f2f7 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -135,11 +135,19 @@ class WalletTest(BitcoinTestFramework): self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) - # An output should be unlocked when spent + # The lock on a manually selected output is ignored unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) - tx = self.nodes[1].fundrawtransaction(tx)['hex'] + self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True}) + + # fundrawtransaction can lock an input + self.nodes[1].lockunspent(True, [unspent_0]) + assert_equal(len(self.nodes[1].listlockunspent()), 0) + tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex'] + assert_equal(len(self.nodes[1].listlockunspent()), 1) + + # Send transaction tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) @@ -526,8 +534,6 @@ class WalletTest(BitcoinTestFramework): maintenance = [ '-rescan', '-reindex', - '-zapwallettxes=1', - '-zapwallettxes=2', ] chainlimit = 6 for m in maintenance: diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py index 53496084ef..56d1da60b7 100755 --- a/test/functional/wallet_bumpfee.py +++ b/test/functional/wallet_bumpfee.py @@ -50,6 +50,11 @@ class BumpFeeTest(BitcoinTestFramework): def skip_test_if_missing_module(self): self.skip_if_no_wallet() + def clear_mempool(self): + # Clear mempool between subtests. The subtests may only depend on chainstate (utxos) + self.nodes[1].generate(1) + self.sync_all() + def run_test(self): # Encrypt wallet for test_locked_wallet_fails test self.nodes[1].encryptwallet(WALLET_PASSPHRASE) @@ -71,7 +76,7 @@ class BumpFeeTest(BitcoinTestFramework): self.log.info("Running tests") dest_address = peer_node.getnewaddress() - test_invalid_parameters(rbf_node, dest_address) + self.test_invalid_parameters(rbf_node, dest_address) test_simple_bumpfee_succeeds(self, "default", rbf_node, peer_node, dest_address) test_simple_bumpfee_succeeds(self, "fee_rate", rbf_node, peer_node, dest_address) test_feerate_args(self, rbf_node, peer_node, dest_address) @@ -93,28 +98,30 @@ class BumpFeeTest(BitcoinTestFramework): test_small_output_with_feerate_succeeds(self, rbf_node, dest_address) test_no_more_inputs_fails(self, rbf_node, dest_address) -def test_invalid_parameters(node, dest_address): - txid = spend_one_input(node, dest_address) - # invalid estimate mode - assert_raises_rpc_error(-8, "Invalid estimate_mode parameter", node.bumpfee, txid, { - "estimate_mode": "moo", - }) - assert_raises_rpc_error(-3, "Expected type string", node.bumpfee, txid, { - "estimate_mode": 38, - }) - assert_raises_rpc_error(-3, "Expected type string", node.bumpfee, txid, { - "estimate_mode": { - "foo": "bar", - }, - }) - assert_raises_rpc_error(-8, "Invalid estimate_mode parameter", node.bumpfee, txid, { - "estimate_mode": Decimal("3.141592"), - }) - # confTarget and conf_target - assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set", node.bumpfee, txid, { - "confTarget": 123, - "conf_target": 456, - }) + def test_invalid_parameters(self, node, dest_address): + txid = spend_one_input(node, dest_address) + # invalid estimate mode + assert_raises_rpc_error(-8, "Invalid estimate_mode parameter", node.bumpfee, txid, { + "estimate_mode": "moo", + }) + assert_raises_rpc_error(-3, "Expected type string", node.bumpfee, txid, { + "estimate_mode": 38, + }) + assert_raises_rpc_error(-3, "Expected type string", node.bumpfee, txid, { + "estimate_mode": { + "foo": "bar", + }, + }) + assert_raises_rpc_error(-8, "Invalid estimate_mode parameter", node.bumpfee, txid, { + "estimate_mode": Decimal("3.141592"), + }) + # confTarget and conf_target + assert_raises_rpc_error(-8, "confTarget and conf_target options should not both be set", node.bumpfee, txid, { + "confTarget": 123, + "conf_target": 456, + }) + self.clear_mempool() + def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address): self.log.info('Test simple bumpfee: {}'.format(mode)) @@ -148,6 +155,7 @@ def test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address): bumpedwtx = rbf_node.gettransaction(bumped_tx["txid"]) assert_equal(oldwtx["replaced_by_txid"], bumped_tx["txid"]) assert_equal(bumpedwtx["replaces_txid"], rbfid) + self.clear_mempool() def test_feerate_args(self, rbf_node, peer_node, dest_address): @@ -167,6 +175,7 @@ def test_feerate_args(self, rbf_node, peer_node, dest_address): assert_raises_rpc_error(-3, "Amount out of range", rbf_node.bumpfee, rbfid, {"fee_rate": -1}) assert_raises_rpc_error(-4, "is too high (cannot be higher than", rbf_node.bumpfee, rbfid, {"fee_rate": TOO_HIGH}) + self.clear_mempool() def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address): @@ -198,12 +207,14 @@ def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address): bumped_tx = rbf_node.bumpfee(rbfid) assert bumped_tx["txid"] in rbf_node.getrawmempool() assert rbfid not in rbf_node.getrawmempool() + self.clear_mempool() def test_nonrbf_bumpfee_fails(self, peer_node, dest_address): self.log.info('Test that we cannot replace a non RBF transaction') not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000")) assert_raises_rpc_error(-4, "not BIP 125 replaceable", peer_node.bumpfee, not_rbfid) + self.clear_mempool() def test_notmine_bumpfee_fails(self, rbf_node, peer_node, dest_address): @@ -211,20 +222,22 @@ def test_notmine_bumpfee_fails(self, rbf_node, peer_node, dest_address): # here, the rbftx has a peer_node coin and then adds a rbf_node input # Note that this test depends upon the RPC code checking input ownership prior to change outputs # (since it can't use fundrawtransaction, it lacks a proper change output) - utxos = [node.listunspent()[-1] for node in (rbf_node, peer_node)] + fee = Decimal("0.001") + utxos = [node.listunspent(query_options={'minimumAmount': fee})[-1] for node in (rbf_node, peer_node)] inputs = [{ "txid": utxo["txid"], "vout": utxo["vout"], "address": utxo["address"], "sequence": BIP125_SEQUENCE_NUMBER } for utxo in utxos] - output_val = sum(utxo["amount"] for utxo in utxos) - Decimal("0.001") + output_val = sum(utxo["amount"] for utxo in utxos) - fee rawtx = rbf_node.createrawtransaction(inputs, {dest_address: output_val}) signedtx = rbf_node.signrawtransactionwithwallet(rawtx) signedtx = peer_node.signrawtransactionwithwallet(signedtx["hex"]) rbfid = rbf_node.sendrawtransaction(signedtx["hex"]) assert_raises_rpc_error(-4, "Transaction contains inputs that don't belong to this wallet", rbf_node.bumpfee, rbfid) + self.clear_mempool() def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address): @@ -235,6 +248,7 @@ def test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_ad tx = rbf_node.signrawtransactionwithwallet(tx) rbf_node.sendrawtransaction(tx["hex"]) assert_raises_rpc_error(-8, "Transaction has descendants in the wallet", rbf_node.bumpfee, parent_id) + self.clear_mempool() def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): @@ -276,6 +290,7 @@ def test_small_output_with_feerate_succeeds(self, rbf_node, dest_address): rbf_node.generatetoaddress(1, rbf_node.getnewaddress()) assert_equal(rbf_node.gettransaction(rbfid)["confirmations"], 1) + self.clear_mempool() def test_dust_to_fee(self, rbf_node, dest_address): @@ -298,6 +313,7 @@ def test_dust_to_fee(self, rbf_node, dest_address): assert_equal(len(fulltx["vout"]), 2) assert_equal(len(full_bumped_tx["vout"]), 1) # change output is eliminated assert_equal(full_bumped_tx["vout"][0]['value'], Decimal("0.00050000")) + self.clear_mempool() def test_settxfee(self, rbf_node, dest_address): @@ -320,6 +336,8 @@ def test_settxfee(self, rbf_node, dest_address): assert_raises_rpc_error(-8, "txfee cannot be more than wallet max tx fee", rbf_node.settxfee, Decimal('0.00003')) self.restart_node(1, self.extra_args[1]) rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) + self.connect_nodes(1, 0) + self.clear_mempool() def test_maxtxfee_fails(self, rbf_node, dest_address): @@ -333,6 +351,8 @@ def test_maxtxfee_fails(self, rbf_node, dest_address): assert_raises_rpc_error(-4, "Unable to create transaction. Fee exceeds maximum configured by -maxtxfee", rbf_node.bumpfee, rbfid) self.restart_node(1, self.extra_args[1]) rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) + self.connect_nodes(1, 0) + self.clear_mempool() def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): @@ -415,6 +435,7 @@ def test_watchonly_psbt(self, peer_node, rbf_node, dest_address): rbf_node.unloadwallet("watcher") rbf_node.unloadwallet("signer") + self.clear_mempool() def test_rebumping(self, rbf_node, dest_address): @@ -423,6 +444,7 @@ def test_rebumping(self, rbf_node, dest_address): bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL}) assert_raises_rpc_error(-4, "already bumped", rbf_node.bumpfee, rbfid, {"fee_rate": NORMAL}) rbf_node.bumpfee(bumped["txid"], {"fee_rate": NORMAL}) + self.clear_mempool() def test_rebumping_not_replaceable(self, rbf_node, dest_address): @@ -431,6 +453,7 @@ def test_rebumping_not_replaceable(self, rbf_node, dest_address): bumped = rbf_node.bumpfee(rbfid, {"fee_rate": ECONOMICAL, "replaceable": False}) assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"], {"fee_rate": NORMAL}) + self.clear_mempool() def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): @@ -470,6 +493,7 @@ def test_unconfirmed_not_spendable(self, rbf_node, rbf_node_address): assert_equal( sum(1 for t in rbf_node.listunspent(minconf=0, include_unsafe=False) if t["txid"] == rbfid and t["address"] == rbf_node_address and t["spendable"]), 1) + self.clear_mempool() def test_bumpfee_metadata(self, rbf_node, dest_address): @@ -481,6 +505,7 @@ def test_bumpfee_metadata(self, rbf_node, dest_address): bumped_wtx = rbf_node.gettransaction(bumped_tx["txid"]) assert_equal(bumped_wtx["comment"], "comment value") assert_equal(bumped_wtx["to"], "to value") + self.clear_mempool() def test_locked_wallet_fails(self, rbf_node, dest_address): @@ -490,6 +515,7 @@ def test_locked_wallet_fails(self, rbf_node, dest_address): assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.", rbf_node.bumpfee, rbfid) rbf_node.walletpassphrase(WALLET_PASSPHRASE, WALLET_PASSPHRASE_TIMEOUT) + self.clear_mempool() def test_change_script_match(self, rbf_node, dest_address): @@ -510,6 +536,7 @@ def test_change_script_match(self, rbf_node, dest_address): assert_equal(change_addresses, get_change_address(bumped_total_tx['txid'])) bumped_rate_tx = rbf_node.bumpfee(bumped_total_tx["txid"]) assert_equal(change_addresses, get_change_address(bumped_rate_tx['txid'])) + self.clear_mempool() def spend_one_input(node, dest_address, change_size=Decimal("0.00049000")): @@ -548,6 +575,7 @@ def test_no_more_inputs_fails(self, rbf_node, dest_address): # spend all funds, no change output rbfid = rbf_node.sendtoaddress(rbf_node.getnewaddress(), rbf_node.getbalance(), "", "", True) assert_raises_rpc_error(-4, "Unable to create transaction. Insufficient funds", rbf_node.bumpfee, rbfid) + self.clear_mempool() if __name__ == "__main__": diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py index 1872545cdb..5c9d7ff629 100755 --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -134,11 +134,6 @@ class MultiWalletTest(BitcoinTestFramework): open(not_a_dir, 'a', encoding="utf8").close() self.nodes[0].assert_start_raises_init_error(['-walletdir=' + not_a_dir], 'Error: Specified -walletdir "' + not_a_dir + '" is not a directory') - self.log.info("Do not allow -zapwallettxes with multiwallet") - self.nodes[0].assert_start_raises_init_error(['-zapwallettxes', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file") - self.nodes[0].assert_start_raises_init_error(['-zapwallettxes=1', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file") - self.nodes[0].assert_start_raises_init_error(['-zapwallettxes=2', '-wallet=w1', '-wallet=w2'], "Error: -zapwallettxes is only allowed with a single wallet file") - # if wallets/ doesn't exist, datadir should be the default wallet dir wallet_dir2 = data_dir('walletdir') os.rename(wallet_dir(), wallet_dir2) diff --git a/test/functional/wallet_resendwallettransactions.py b/test/functional/wallet_resendwallettransactions.py index 3417616d77..0327c9e070 100755 --- a/test/functional/wallet_resendwallettransactions.py +++ b/test/functional/wallet_resendwallettransactions.py @@ -7,9 +7,9 @@ import time from test_framework.blocktools import create_block, create_coinbase from test_framework.messages import ToHex -from test_framework.mininode import P2PTxInvStore, mininode_lock +from test_framework.p2p import P2PTxInvStore from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, wait_until +from test_framework.util import assert_equal class ResendWalletTransactionsTest(BitcoinTestFramework): def set_test_params(self): @@ -24,7 +24,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): node.add_p2p_connection(P2PTxInvStore()) self.log.info("Create a new transaction and wait until it's broadcast") - txid = int(node.sendtoaddress(node.getnewaddress(), 1), 16) + txid = node.sendtoaddress(node.getnewaddress(), 1) # Wallet rebroadcast is first scheduled 1 sec after startup (see # nNextResend in ResendWalletTransactions()). Sleep for just over a @@ -33,7 +33,7 @@ class ResendWalletTransactionsTest(BitcoinTestFramework): time.sleep(1.1) # Can take a few seconds due to transaction trickling - wait_until(lambda: node.p2p.tx_invs_received[txid] >= 1, lock=mininode_lock) + node.p2p.wait_for_broadcast([txid]) # Add a second peer since txs aren't rebroadcast to the same peer (see filterInventoryKnown) node.add_p2p_connection(P2PTxInvStore()) @@ -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(txid in node.p2ps[1].get_invs(), False) + assert_equal(int(txid, 16) in node.p2ps[1].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) - wait_until(lambda: node.p2ps[1].tx_invs_received[txid] >= 1, lock=mininode_lock) + node.p2p.wait_for_broadcast([txid]) if __name__ == '__main__': diff --git a/test/functional/wallet_upgradewallet.py b/test/functional/wallet_upgradewallet.py index 1a76f65215..69aa603c6b 100755 --- a/test/functional/wallet_upgradewallet.py +++ b/test/functional/wallet_upgradewallet.py @@ -6,7 +6,7 @@ Test upgradewallet RPC. Download node binaries: -contrib/devtools/previous_release.py -b v0.19.1 v0.18.1 v0.17.1 v0.16.3 v0.15.2 +test/get_previous_releases.py -b v0.19.1 v0.18.1 v0.17.2 v0.16.3 v0.15.2 Only v0.15.2 and v0.16.3 are required by this test. The others are used in feature_backwards_compatibility.py """ diff --git a/test/functional/wallet_zapwallettxes.py b/test/functional/wallet_zapwallettxes.py deleted file mode 100755 index 7f1cdbd20b..0000000000 --- a/test/functional/wallet_zapwallettxes.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2014-2018 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 the zapwallettxes functionality. - -- start two bitcoind nodes -- create two transactions on node 0 - one is confirmed and one is unconfirmed. -- restart node 0 and verify that both the confirmed and the unconfirmed - transactions are still available. -- restart node 0 with zapwallettxes and persistmempool, and verify that both - the confirmed and the unconfirmed transactions are still available. -- restart node 0 with just zapwallettxes and verify that the confirmed - transactions are still available, but that the unconfirmed transaction has - been zapped. -""" -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import ( - assert_equal, - assert_raises_rpc_error, - wait_until, -) - -class ZapWalletTXesTest (BitcoinTestFramework): - def set_test_params(self): - self.setup_clean_chain = True - self.num_nodes = 2 - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() - - def run_test(self): - self.log.info("Mining blocks...") - self.nodes[0].generate(1) - self.sync_all() - self.nodes[1].generate(100) - self.sync_all() - - # This transaction will be confirmed - txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 10) - - self.nodes[0].generate(1) - self.sync_all() - - # This transaction will not be confirmed - txid2 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 20) - - # Confirmed and unconfirmed transactions are now in the wallet. - assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) - assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) - - # Restart node0. Both confirmed and unconfirmed transactions remain in the wallet. - self.restart_node(0) - - assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) - assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) - - # Restart node0 with zapwallettxes and persistmempool. The unconfirmed - # transaction is zapped from the wallet, but is re-added when the mempool is reloaded. - self.restart_node(0, ["-persistmempool=1", "-zapwallettxes=2"]) - - wait_until(lambda: self.nodes[0].getmempoolinfo()['size'] == 1, timeout=3) - self.nodes[0].syncwithvalidationinterfacequeue() # Flush mempool to wallet - - assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) - assert_equal(self.nodes[0].gettransaction(txid2)['txid'], txid2) - - # Restart node0 with zapwallettxes, but not persistmempool. - # The unconfirmed transaction is zapped and is no longer in the wallet. - self.restart_node(0, ["-zapwallettxes=2"]) - - # tx1 is still be available because it was confirmed - assert_equal(self.nodes[0].gettransaction(txid1)['txid'], txid1) - - # This will raise an exception because the unconfirmed transaction has been zapped - assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', self.nodes[0].gettransaction, txid2) - -if __name__ == '__main__': - ZapWalletTXesTest().main() |