mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-12 15:09:59 +01:00
Add p2p-fullblocktest.py
This commit is contained in:
@@ -122,12 +122,19 @@ class TestNode(NodeConnCB):
|
||||
# Instances of these are generated by the test generator, and fed into the
|
||||
# comptool.
|
||||
#
|
||||
# "blocks_and_transactions" should be an array of [obj, True/False/None]:
|
||||
# - obj is either a CBlock or a CTransaction, and
|
||||
# "blocks_and_transactions" should be an array of
|
||||
# [obj, True/False/None, hash/None]:
|
||||
# - obj is either a CBlock, CBlockHeader, or a CTransaction, and
|
||||
# - the second value indicates whether the object should be accepted
|
||||
# into the blockchain or mempool (for tests where we expect a certain
|
||||
# answer), or "None" if we don't expect a certain answer and are just
|
||||
# comparing the behavior of the nodes being tested.
|
||||
# - the third value is the hash to test the tip against (if None or omitted,
|
||||
# use the hash of the block)
|
||||
# - NOTE: if a block header, no test is performed; instead the header is
|
||||
# just added to the block_store. This is to facilitate block delivery
|
||||
# when communicating with headers-first clients (when withholding an
|
||||
# intermediate block).
|
||||
# sync_every_block: if True, then each block will be inv'ed, synced, and
|
||||
# nodes will be tested based on the outcome for the block. If False,
|
||||
# then inv's accumulate until all blocks are processed (or max inv size
|
||||
@@ -194,7 +201,6 @@ class TestManager(object):
|
||||
if not wait_until(blocks_requested, attempts=20*num_blocks):
|
||||
# print [ c.cb.block_request_map for c in self.connections ]
|
||||
raise AssertionError("Not all nodes requested block")
|
||||
# --> Answer request (we did this inline!)
|
||||
|
||||
# Send getheaders message
|
||||
[ c.cb.send_getheaders() for c in self.connections ]
|
||||
@@ -217,7 +223,6 @@ class TestManager(object):
|
||||
if not wait_until(transaction_requested, attempts=20*num_events):
|
||||
# print [ c.cb.tx_request_map for c in self.connections ]
|
||||
raise AssertionError("Not all nodes requested transaction")
|
||||
# --> Answer request (we did this inline!)
|
||||
|
||||
# Get the mempool
|
||||
[ c.cb.send_mempool() for c in self.connections ]
|
||||
@@ -272,29 +277,55 @@ class TestManager(object):
|
||||
# We use these variables to keep track of the last block
|
||||
# and last transaction in the tests, which are used
|
||||
# if we're not syncing on every block or every tx.
|
||||
[ block, block_outcome ] = [ None, None ]
|
||||
[ block, block_outcome, tip ] = [ None, None, None ]
|
||||
[ tx, tx_outcome ] = [ None, None ]
|
||||
invqueue = []
|
||||
|
||||
for b_or_t, outcome in test_instance.blocks_and_transactions:
|
||||
for test_obj in test_instance.blocks_and_transactions:
|
||||
b_or_t = test_obj[0]
|
||||
outcome = test_obj[1]
|
||||
# Determine if we're dealing with a block or tx
|
||||
if isinstance(b_or_t, CBlock): # Block test runner
|
||||
block = b_or_t
|
||||
block_outcome = outcome
|
||||
tip = block.sha256
|
||||
# each test_obj can have an optional third argument
|
||||
# to specify the tip we should compare with
|
||||
# (default is to use the block being tested)
|
||||
if len(test_obj) >= 3:
|
||||
tip = test_obj[2]
|
||||
|
||||
# Add to shared block_store, set as current block
|
||||
# If there was an open getdata request for the block
|
||||
# previously, and we didn't have an entry in the
|
||||
# block_store, then immediately deliver, because the
|
||||
# node wouldn't send another getdata request while
|
||||
# the earlier one is outstanding.
|
||||
first_block_with_hash = True
|
||||
if self.block_store.get(block.sha256) is not None:
|
||||
first_block_with_hash = False
|
||||
with mininode_lock:
|
||||
self.block_store.add_block(block)
|
||||
for c in self.connections:
|
||||
c.cb.block_request_map[block.sha256] = False
|
||||
if first_block_with_hash and block.sha256 in c.cb.block_request_map and c.cb.block_request_map[block.sha256] == True:
|
||||
# There was a previous request for this block hash
|
||||
# Most likely, we delivered a header for this block
|
||||
# but never had the block to respond to the getdata
|
||||
c.send_message(msg_block(block))
|
||||
else:
|
||||
c.cb.block_request_map[block.sha256] = False
|
||||
# Either send inv's to each node and sync, or add
|
||||
# to invqueue for later inv'ing.
|
||||
if (test_instance.sync_every_block):
|
||||
[ c.cb.send_inv(block) for c in self.connections ]
|
||||
self.sync_blocks(block.sha256, 1)
|
||||
if (not self.check_results(block.sha256, outcome)):
|
||||
if (not self.check_results(tip, outcome)):
|
||||
raise AssertionError("Test failed at test %d" % test_number)
|
||||
else:
|
||||
invqueue.append(CInv(2, block.sha256))
|
||||
elif isinstance(b_or_t, CBlockHeader):
|
||||
block_header = b_or_t
|
||||
self.block_store.add_header(block_header)
|
||||
else: # Tx test runner
|
||||
assert(isinstance(b_or_t, CTransaction))
|
||||
tx = b_or_t
|
||||
@@ -322,9 +353,8 @@ class TestManager(object):
|
||||
if len(invqueue) > 0:
|
||||
[ c.send_message(msg_inv(invqueue)) for c in self.connections ]
|
||||
invqueue = []
|
||||
self.sync_blocks(block.sha256,
|
||||
len(test_instance.blocks_and_transactions))
|
||||
if (not self.check_results(block.sha256, block_outcome)):
|
||||
self.sync_blocks(block.sha256, len(test_instance.blocks_and_transactions))
|
||||
if (not self.check_results(tip, block_outcome)):
|
||||
raise AssertionError("Block test failed at test %d" % test_number)
|
||||
if (not test_instance.sync_every_tx and tx is not None):
|
||||
if len(invqueue) > 0:
|
||||
|
||||
Reference in New Issue
Block a user