aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
Diffstat (limited to 'qa')
-rwxr-xr-xqa/rpc-tests/p2p-compactblocks.py18
-rwxr-xr-xqa/rpc-tests/preciousblock.py65
-rwxr-xr-xqa/rpc-tests/smartfees.py6
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py26
-rw-r--r--qa/rpc-tests/test_framework/util.py45
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")