diff options
Diffstat (limited to 'qa')
-rwxr-xr-x | qa/rpc-tests/p2p-compactblocks.py | 18 | ||||
-rwxr-xr-x | qa/rpc-tests/preciousblock.py | 65 | ||||
-rwxr-xr-x | qa/rpc-tests/smartfees.py | 6 | ||||
-rwxr-xr-x | qa/rpc-tests/test_framework/mininode.py | 26 | ||||
-rw-r--r-- | qa/rpc-tests/test_framework/util.py | 45 |
5 files changed, 97 insertions, 63 deletions
diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 6d1fb3fd9a..1b4c8d90e7 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -300,8 +300,8 @@ class CompactBlocksTest(BitcoinTestFramework): assert(segwit_tx_generated) # check that our test is not broken # Wait until we've seen the block announcement for the resulting tip - tip = int(self.nodes[0].getbestblockhash(), 16) - assert(self.test_node.wait_for_block_announcement(tip)) + tip = int(node.getbestblockhash(), 16) + assert(test_node.wait_for_block_announcement(tip)) # Now mine a block, and look at the resulting compact block. test_node.clear_block_announcement() @@ -589,8 +589,8 @@ class CompactBlocksTest(BitcoinTestFramework): assert_equal(int(node.getbestblockhash(), 16), block.sha256) def test_getblocktxn_handler(self, node, test_node, version): - # bitcoind won't respond for blocks whose height is more than 15 blocks - # deep. + # bitcoind will not send blocktxn responses for blocks whose height is + # more than 10 blocks deep. MAX_GETBLOCKTXN_DEPTH = 10 chain_height = node.getblockcount() current_height = chain_height @@ -623,11 +623,17 @@ class CompactBlocksTest(BitcoinTestFramework): test_node.last_blocktxn = None current_height -= 1 - # Next request should be ignored, as we're past the allowed depth. + # Next request should send a full block response, as we're past the + # 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: + test_node.last_block = None + test_node.last_blocktxn = None test_node.send_and_ping(msg) with mininode_lock: + test_node.last_block.block.calc_sha256() + assert_equal(test_node.last_block.block.sha256, int(block_hash, 16)) assert_equal(test_node.last_blocktxn, None) def test_compactblocks_not_at_tip(self, node, test_node): @@ -648,6 +654,8 @@ class CompactBlocksTest(BitcoinTestFramework): node.generate(1) wait_until(test_node.received_block_announcement, timeout=30) test_node.clear_block_announcement() + with mininode_lock: + test_node.last_block = None test_node.send_message(msg_getdata([CInv(4, int(new_blocks[0], 16))])) success = wait_until(lambda: test_node.last_block is not None, timeout=30) assert(success) diff --git a/qa/rpc-tests/preciousblock.py b/qa/rpc-tests/preciousblock.py index 854dcc7251..3cefa51c0a 100755 --- a/qa/rpc-tests/preciousblock.py +++ b/qa/rpc-tests/preciousblock.py @@ -8,7 +8,12 @@ # from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * +from test_framework.util import ( + assert_equal, + connect_nodes_bi, + sync_chain, + sync_blocks, +) def unidirectional_node_sync_via_rpc(node_src, node_dest): blocks_to_copy = [] @@ -33,84 +38,82 @@ def node_sync_via_rpc(nodes): unidirectional_node_sync_via_rpc(node_src, node_dest) class PreciousTest(BitcoinTestFramework): - def setup_chain(self): - print("Initializing test directory "+self.options.tmpdir) - initialize_chain_clean(self.options.tmpdir, 3) + def __init__(self): + super().__init__() + self.setup_clean_chain = True + self.num_nodes = 3 + self.extra_args = [["-debug"]] * self.num_nodes def setup_network(self): - self.nodes = [] - self.is_network_split = False - self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) - self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) + self.nodes = self.setup_nodes() def run_test(self): print("Ensure submitblock can in principle reorg to a competing chain") self.nodes[0].generate(1) - assert(self.nodes[0].getblockcount() == 1) + assert_equal(self.nodes[0].getblockcount(), 1) (hashY, hashZ) = self.nodes[1].generate(2) - assert(self.nodes[1].getblockcount() == 2) + assert_equal(self.nodes[1].getblockcount(), 2) node_sync_via_rpc(self.nodes[0:3]) - assert(self.nodes[0].getbestblockhash() == hashZ) + assert_equal(self.nodes[0].getbestblockhash(), hashZ) print("Mine blocks A-B-C on Node 0") (hashA, hashB, hashC) = self.nodes[0].generate(3) - assert(self.nodes[0].getblockcount() == 5) + assert_equal(self.nodes[0].getblockcount(), 5) print("Mine competing blocks E-F-G on Node 1") (hashE, hashF, hashG) = self.nodes[1].generate(3) - assert(self.nodes[1].getblockcount() == 5) + assert_equal(self.nodes[1].getblockcount(), 5) assert(hashC != hashG) print("Connect nodes and check no reorg occurs") # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync) node_sync_via_rpc(self.nodes[0:2]) connect_nodes_bi(self.nodes,0,1) - assert(self.nodes[0].getbestblockhash() == hashC) - assert(self.nodes[1].getbestblockhash() == hashG) + assert_equal(self.nodes[0].getbestblockhash(), hashC) + assert_equal(self.nodes[1].getbestblockhash(), hashG) print("Make Node0 prefer block G") self.nodes[0].preciousblock(hashG) - assert(self.nodes[0].getbestblockhash() == hashG) + assert_equal(self.nodes[0].getbestblockhash(), hashG) print("Make Node0 prefer block C again") self.nodes[0].preciousblock(hashC) - assert(self.nodes[0].getbestblockhash() == hashC) + assert_equal(self.nodes[0].getbestblockhash(), hashC) print("Make Node1 prefer block C") self.nodes[1].preciousblock(hashC) sync_chain(self.nodes[0:2]) # wait because node 1 may not have downloaded hashC - assert(self.nodes[1].getbestblockhash() == hashC) + assert_equal(self.nodes[1].getbestblockhash(), hashC) print("Make Node1 prefer block G again") self.nodes[1].preciousblock(hashG) - assert(self.nodes[1].getbestblockhash() == hashG) + assert_equal(self.nodes[1].getbestblockhash(), hashG) print("Make Node0 prefer block G again") self.nodes[0].preciousblock(hashG) - assert(self.nodes[0].getbestblockhash() == hashG) + assert_equal(self.nodes[0].getbestblockhash(), hashG) print("Make Node1 prefer block C again") self.nodes[1].preciousblock(hashC) - assert(self.nodes[1].getbestblockhash() == hashC) + assert_equal(self.nodes[1].getbestblockhash(), hashC) print("Mine another block (E-F-G-)H on Node 0 and reorg Node 1") self.nodes[0].generate(1) - assert(self.nodes[0].getblockcount() == 6) + assert_equal(self.nodes[0].getblockcount(), 6) sync_blocks(self.nodes[0:2]) hashH = self.nodes[0].getbestblockhash() - assert(self.nodes[1].getbestblockhash() == hashH) + assert_equal(self.nodes[1].getbestblockhash(), hashH) print("Node1 should not be able to prefer block C anymore") self.nodes[1].preciousblock(hashC) - assert(self.nodes[1].getbestblockhash() == hashH) + assert_equal(self.nodes[1].getbestblockhash(), hashH) print("Mine competing blocks I-J-K-L on Node 2") self.nodes[2].generate(4) - assert(self.nodes[2].getblockcount() == 6) + assert_equal(self.nodes[2].getblockcount(), 6) hashL = self.nodes[2].getbestblockhash() print("Connect nodes and check no reorg occurs") node_sync_via_rpc(self.nodes[0:3]) connect_nodes_bi(self.nodes,1,2) connect_nodes_bi(self.nodes,0,2) - assert(self.nodes[0].getbestblockhash() == hashH) - assert(self.nodes[1].getbestblockhash() == hashH) - assert(self.nodes[2].getbestblockhash() == hashL) + assert_equal(self.nodes[0].getbestblockhash(), hashH) + assert_equal(self.nodes[1].getbestblockhash(), hashH) + assert_equal(self.nodes[2].getbestblockhash(), hashL) print("Make Node1 prefer block L") self.nodes[1].preciousblock(hashL) - assert(self.nodes[1].getbestblockhash() == hashL) + assert_equal(self.nodes[1].getbestblockhash(), hashL) print("Make Node2 prefer block H") self.nodes[2].preciousblock(hashH) - assert(self.nodes[2].getbestblockhash() == hashH) + assert_equal(self.nodes[2].getbestblockhash(), hashH) if __name__ == '__main__': PreciousTest().main() diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index d76fba4b07..74a74f679a 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -225,9 +225,9 @@ class EstimateFeeTest(BitcoinTestFramework): self.memutxo, Decimal("0.005"), min_fee, min_fee) tx_kbytes = (len(txhex) // 2) / 1000.0 self.fees_per_kb.append(float(fee)/tx_kbytes) - sync_mempools(self.nodes[0:3],.1) + sync_mempools(self.nodes[0:3], wait=.1) mined = mining_node.getblock(mining_node.generate(1)[0],True)["tx"] - sync_blocks(self.nodes[0:3],.1) + sync_blocks(self.nodes[0:3], wait=.1) # update which txouts are confirmed newmem = [] for utx in self.memutxo: @@ -259,7 +259,7 @@ class EstimateFeeTest(BitcoinTestFramework): while len(self.nodes[1].getrawmempool()) > 0: self.nodes[1].generate(1) - sync_blocks(self.nodes[0:3],.1) + sync_blocks(self.nodes[0:3], wait=.1) print("Final estimates after emptying mempools") check_estimates(self.nodes[1], self.fees_per_kb, 2) diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py index 4d238c08d9..495c6bdf35 100755 --- a/qa/rpc-tests/test_framework/mininode.py +++ b/qa/rpc-tests/test_framework/mininode.py @@ -41,6 +41,7 @@ from test_framework.siphash import siphash256 BIP0031_VERSION = 60000 MY_VERSION = 70014 # past bip-31 for ping/pong MY_SUBVERSION = b"/python-mininode-tester:0.0.3/" +MY_RELAY = 1 # from version 70001 onwards, fRelay should be appended to version messages (BIP37) MAX_INV_SZ = 50000 MAX_BLOCK_SIZE = 1000000 @@ -951,6 +952,7 @@ class msg_version(object): self.nNonce = random.getrandbits(64) self.strSubVer = MY_SUBVERSION self.nStartingHeight = -1 + self.nRelay = MY_RELAY def deserialize(self, f): self.nVersion = struct.unpack("<i", f.read(4))[0] @@ -960,21 +962,32 @@ class msg_version(object): self.nTime = struct.unpack("<q", f.read(8))[0] self.addrTo = CAddress() self.addrTo.deserialize(f) + if self.nVersion >= 106: self.addrFrom = CAddress() self.addrFrom.deserialize(f) self.nNonce = struct.unpack("<Q", f.read(8))[0] self.strSubVer = deser_string(f) - if self.nVersion >= 209: - self.nStartingHeight = struct.unpack("<i", f.read(4))[0] - else: - self.nStartingHeight = None else: self.addrFrom = None self.nNonce = None self.strSubVer = None self.nStartingHeight = None + if self.nVersion >= 209: + self.nStartingHeight = struct.unpack("<i", f.read(4))[0] + else: + self.nStartingHeight = None + + if self.nVersion >= 70001: + # Relay field is optional for version 70001 onwards + try: + self.nRelay = struct.unpack("<b", f.read(1))[0] + except: + self.nRelay = 0 + else: + self.nRelay = 0 + def serialize(self): r = b"" r += struct.pack("<i", self.nVersion) @@ -985,13 +998,14 @@ class msg_version(object): r += struct.pack("<Q", self.nNonce) r += ser_string(self.strSubVer) r += struct.pack("<i", self.nStartingHeight) + r += struct.pack("<b", self.nRelay) return r def __repr__(self): - return 'msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i)' \ + return 'msg_version(nVersion=%i nServices=%i nTime=%s addrTo=%s addrFrom=%s nNonce=0x%016X strSubVer=%s nStartingHeight=%i nRelay=%i)' \ % (self.nVersion, self.nServices, time.ctime(self.nTime), repr(self.addrTo), repr(self.addrFrom), self.nNonce, - self.strSubVer, self.nStartingHeight) + self.strSubVer, self.nStartingHeight, self.nRelay) class msg_verack(object): diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index c0c2b3a6ef..bf13b7fd84 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -121,33 +121,42 @@ def hex_str_to_bytes(hex_str): def str_to_b64str(string): return b64encode(string.encode('utf-8')).decode('ascii') -def sync_blocks(rpc_connections, wait=1, timeout=60): +def sync_blocks(rpc_connections, *, wait=1, timeout=60): """ - Wait until everybody has the same tip + Wait until everybody has the same tip. + + sync_blocks needs to be called with an rpc_connections set that has least + one node already synced to the latest, stable tip, otherwise there's a + chance it might return before all nodes are stably synced. """ maxheight = 0 - while timeout > 0: - tips = [ x.waitforblockheight(maxheight, int(wait * 1000)) for x in rpc_connections ] - heights = [ x["height"] for x in tips ] - if tips == [ tips[0] ]*len(tips): - return True - if heights == [ heights[0] ]*len(heights): #heights are the same but hashes are not - raise AssertionError("Block sync failed") - timeout -= wait + start_time = cur_time = time.time() + while cur_time <= start_time + timeout: + tips = [r.waitforblockheight(maxheight, int(wait * 1000)) for r in rpc_connections] + heights = [t["height"] for t in tips] + if all(t == tips[0] for t in tips): + return + if all(h == heights[0] for h in heights): + raise AssertionError("Block sync failed, mismatched block hashes:{}".format( + "".join("\n {!r}".format(tip) for tip in tips))) maxheight = max(heights) - raise AssertionError("Block sync failed") + cur_time = time.time() + raise AssertionError("Block sync to height {} timed out:{}".format( + maxheight, "".join("\n {!r}".format(tip) for tip in tips))) -def sync_chain(rpc_connections, wait=1): +def sync_chain(rpc_connections, *, wait=1, timeout=60): """ Wait until everybody has the same best block """ - while True: - counts = [ x.getbestblockhash() for x in rpc_connections ] - if counts == [ counts[0] ]*len(counts): - break + while timeout > 0: + best_hash = [x.getbestblockhash() for x in rpc_connections] + if best_hash == [best_hash[0]]*len(best_hash): + return time.sleep(wait) + timeout -= wait + raise AssertionError("Chain sync failed: Best block hashes don't match") -def sync_mempools(rpc_connections, wait=1, timeout=60): +def sync_mempools(rpc_connections, *, wait=1, timeout=60): """ Wait until everybody has the same transactions in their memory pools @@ -159,7 +168,7 @@ def sync_mempools(rpc_connections, wait=1, timeout=60): if set(rpc_connections[i].getrawmempool()) == pool: num_match = num_match+1 if num_match == len(rpc_connections): - return True + return time.sleep(wait) timeout -= wait raise AssertionError("Mempool sync failed") |