Changeset View
Changeset View
Standalone View
Standalone View
test/functional/example_test.py
Show All 12 Lines | |||||
# libraries then local imports). | # libraries then local imports). | ||||
from collections import defaultdict | from collections import defaultdict | ||||
# Avoid wildcard * imports if possible | # Avoid wildcard * imports if possible | ||||
from test_framework.blocktools import (create_block, create_coinbase) | from test_framework.blocktools import (create_block, create_coinbase) | ||||
from test_framework.mininode import ( | from test_framework.mininode import ( | ||||
CInv, | CInv, | ||||
NetworkThread, | NetworkThread, | ||||
NodeConnCB, | P2PInterface, | ||||
mininode_lock, | mininode_lock, | ||||
msg_block, | msg_block, | ||||
msg_getdata, | msg_getdata, | ||||
) | ) | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import ( | from test_framework.util import ( | ||||
assert_equal, | assert_equal, | ||||
connect_nodes, | connect_nodes, | ||||
wait_until, | wait_until, | ||||
) | ) | ||||
# NodeConnCB is a class containing callbacks to be executed when a P2P | # P2PInterface is a class containing callbacks to be executed when a P2P | ||||
# message is received from the node-under-test. Subclass NodeConnCB and | # message is received from the node-under-test. Subclass P2PInterface and | ||||
# override the on_*() methods if you need custom behaviour. | # override the on_*() methods if you need custom behaviour. | ||||
class BaseNode(NodeConnCB): | class BaseNode(P2PInterface): | ||||
def __init__(self): | def __init__(self): | ||||
"""Initialize the NodeConnCB | """Initialize the P2PInterface | ||||
Used to inialize custom properties for the Node that aren't | Used to inialize custom properties for the Node that aren't | ||||
included by default in the base class. Be aware that the NodeConnCB | included by default in the base class. Be aware that the P2PInterface | ||||
base class already stores a counter for each P2P message type and the | base class already stores a counter for each P2P message type and the | ||||
last received message of each type, which should be sufficient for the | last received message of each type, which should be sufficient for the | ||||
needs of most tests. | needs of most tests. | ||||
Call super().__init__() first for standard initialization and then | Call super().__init__() first for standard initialization and then | ||||
initialize custom properties.""" | initialize custom properties.""" | ||||
super().__init__() | super().__init__() | ||||
# Stores a dictionary of all blocks received | # Stores a dictionary of all blocks received | ||||
▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
for i in range(10): | for i in range(10): | ||||
# Use the mininode and blocktools functionality to manually build a block | # Use the mininode and blocktools functionality to manually build a block | ||||
# Calling the generate() rpc is easier, but this allows us to exactly | # Calling the generate() rpc is easier, but this allows us to exactly | ||||
# control the blocks and transactions. | # control the blocks and transactions. | ||||
block = create_block( | block = create_block( | ||||
self.tip, create_coinbase(height), self.block_time) | self.tip, create_coinbase(height), self.block_time) | ||||
block.solve() | block.solve() | ||||
block_message = msg_block(block) | block_message = msg_block(block) | ||||
# Send message is used to send a P2P message to the node over our NodeConn connection | # Send message is used to send a P2P message to the node over our P2PInterface | ||||
self.nodes[0].p2p.send_message(block_message) | self.nodes[0].p2p.send_message(block_message) | ||||
self.tip = block.sha256 | self.tip = block.sha256 | ||||
blocks.append(self.tip) | blocks.append(self.tip) | ||||
self.block_time += 1 | self.block_time += 1 | ||||
height += 1 | height += 1 | ||||
self.log.info( | self.log.info( | ||||
"Wait for node1 to reach current tip (height 11) using RPC") | "Wait for node1 to reach current tip (height 11) using RPC") | ||||
Show All 10 Lines | def run_test(self): | ||||
"Wait for node2 reach current tip. Test that it has propagated all the blocks to us") | "Wait for node2 reach current tip. Test that it has propagated all the blocks to us") | ||||
getdata_request = msg_getdata() | getdata_request = msg_getdata() | ||||
for block in blocks: | for block in blocks: | ||||
getdata_request.inv.append(CInv(2, block)) | getdata_request.inv.append(CInv(2, block)) | ||||
self.nodes[2].p2p.send_message(getdata_request) | self.nodes[2].p2p.send_message(getdata_request) | ||||
# wait_until() will loop until a predicate condition is met. Use it to test properties of the | # wait_until() will loop until a predicate condition is met. Use it to test properties of the | ||||
# NodeConnCB objects. | # P2PInterface objects. | ||||
wait_until(lambda: sorted(blocks) == sorted( | wait_until(lambda: sorted(blocks) == sorted( | ||||
list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock) | list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock) | ||||
self.log.info("Check that each block was received only once") | self.log.info("Check that each block was received only once") | ||||
# The network thread uses a global lock on data access to the NodeConn objects when sending and receiving | # 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 NodeConn data to avoid locking | # 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. | # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate. | ||||
with mininode_lock: | with mininode_lock: | ||||
for block in self.nodes[2].p2p.block_receive_map.values(): | for block in self.nodes[2].p2p.block_receive_map.values(): | ||||
assert_equal(block, 1) | assert_equal(block, 1) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
ExampleTest().main() | ExampleTest().main() |