|
|
@ -27,6 +27,20 @@ generator that returns TestInstance objects. See below for definition. |
|
|
|
|
|
|
|
|
|
|
|
global mininode_lock |
|
|
|
global mininode_lock |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wait_until(predicate, attempts=float('inf'), timeout=float('inf')): |
|
|
|
|
|
|
|
attempt = 0 |
|
|
|
|
|
|
|
elapsed = 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while attempt < attempts and elapsed < timeout: |
|
|
|
|
|
|
|
with mininode_lock: |
|
|
|
|
|
|
|
if predicate(): |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
attempt += 1 |
|
|
|
|
|
|
|
elapsed += 0.05 |
|
|
|
|
|
|
|
time.sleep(0.05) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
class TestNode(NodeConnCB): |
|
|
|
class TestNode(NodeConnCB): |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, block_store, tx_store): |
|
|
|
def __init__(self, block_store, tx_store): |
|
|
@ -43,6 +57,10 @@ class TestNode(NodeConnCB): |
|
|
|
# a response |
|
|
|
# a response |
|
|
|
self.pingMap = {} |
|
|
|
self.pingMap = {} |
|
|
|
self.lastInv = [] |
|
|
|
self.lastInv = [] |
|
|
|
|
|
|
|
self.closed = False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_close(self, conn): |
|
|
|
|
|
|
|
self.closed = True |
|
|
|
|
|
|
|
|
|
|
|
def add_connection(self, conn): |
|
|
|
def add_connection(self, conn): |
|
|
|
self.conn = conn |
|
|
|
self.conn = conn |
|
|
@ -132,6 +150,7 @@ class TestManager(object): |
|
|
|
def __init__(self, testgen, datadir): |
|
|
|
def __init__(self, testgen, datadir): |
|
|
|
self.test_generator = testgen |
|
|
|
self.test_generator = testgen |
|
|
|
self.connections = [] |
|
|
|
self.connections = [] |
|
|
|
|
|
|
|
self.test_nodes = [] |
|
|
|
self.block_store = BlockStore(datadir) |
|
|
|
self.block_store = BlockStore(datadir) |
|
|
|
self.tx_store = TxStore(datadir) |
|
|
|
self.tx_store = TxStore(datadir) |
|
|
|
self.ping_counter = 1 |
|
|
|
self.ping_counter = 1 |
|
|
@ -139,54 +158,40 @@ class TestManager(object): |
|
|
|
def add_all_connections(self, nodes): |
|
|
|
def add_all_connections(self, nodes): |
|
|
|
for i in range(len(nodes)): |
|
|
|
for i in range(len(nodes)): |
|
|
|
# Create a p2p connection to each node |
|
|
|
# Create a p2p connection to each node |
|
|
|
self.connections.append(NodeConn('127.0.0.1', p2p_port(i), |
|
|
|
test_node = TestNode(self.block_store, self.tx_store) |
|
|
|
nodes[i], TestNode(self.block_store, self.tx_store))) |
|
|
|
self.test_nodes.append(test_node) |
|
|
|
|
|
|
|
self.connections.append(NodeConn('127.0.0.1', p2p_port(i), nodes[i], test_node)) |
|
|
|
# Make sure the TestNode (callback class) has a reference to its |
|
|
|
# Make sure the TestNode (callback class) has a reference to its |
|
|
|
# associated NodeConn |
|
|
|
# associated NodeConn |
|
|
|
self.connections[-1].cb.add_connection(self.connections[-1]) |
|
|
|
test_node.add_connection(self.connections[-1]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wait_for_disconnections(self): |
|
|
|
|
|
|
|
def disconnected(): |
|
|
|
|
|
|
|
return all(node.closed for node in self.test_nodes) |
|
|
|
|
|
|
|
return wait_until(disconnected, timeout=10) |
|
|
|
|
|
|
|
|
|
|
|
def wait_for_verack(self): |
|
|
|
def wait_for_verack(self): |
|
|
|
sleep_time = 0.05 |
|
|
|
def veracked(): |
|
|
|
max_tries = 10 / sleep_time # Wait at most 10 seconds |
|
|
|
return all(node.verack_received for node in self.test_nodes) |
|
|
|
while max_tries > 0: |
|
|
|
return wait_until(veracked, timeout=10) |
|
|
|
done = True |
|
|
|
|
|
|
|
with mininode_lock: |
|
|
|
|
|
|
|
for c in self.connections: |
|
|
|
|
|
|
|
if c.cb.verack_received is False: |
|
|
|
|
|
|
|
done = False |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
if done: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
time.sleep(sleep_time) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wait_for_pings(self, counter): |
|
|
|
def wait_for_pings(self, counter): |
|
|
|
received_pongs = False |
|
|
|
def received_pongs(): |
|
|
|
while received_pongs is not True: |
|
|
|
return all(node.received_ping_response(counter) for node in self.test_nodes) |
|
|
|
time.sleep(0.05) |
|
|
|
return wait_until(received_pongs) |
|
|
|
received_pongs = True |
|
|
|
|
|
|
|
with mininode_lock: |
|
|
|
|
|
|
|
for c in self.connections: |
|
|
|
|
|
|
|
if c.cb.received_ping_response(counter) is not True: |
|
|
|
|
|
|
|
received_pongs = False |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# sync_blocks: Wait for all connections to request the blockhash given |
|
|
|
# sync_blocks: Wait for all connections to request the blockhash given |
|
|
|
# then send get_headers to find out the tip of each node, and synchronize |
|
|
|
# then send get_headers to find out the tip of each node, and synchronize |
|
|
|
# the response by using a ping (and waiting for pong with same nonce). |
|
|
|
# the response by using a ping (and waiting for pong with same nonce). |
|
|
|
def sync_blocks(self, blockhash, num_blocks): |
|
|
|
def sync_blocks(self, blockhash, num_blocks): |
|
|
|
# Wait for nodes to request block (50ms sleep * 20 tries * num_blocks) |
|
|
|
def blocks_requested(): |
|
|
|
max_tries = 20*num_blocks |
|
|
|
return all( |
|
|
|
while max_tries > 0: |
|
|
|
blockhash in node.block_request_map and node.block_request_map[blockhash] |
|
|
|
with mininode_lock: |
|
|
|
for node in self.test_nodes |
|
|
|
results = [ blockhash in c.cb.block_request_map and |
|
|
|
) |
|
|
|
c.cb.block_request_map[blockhash] for c in self.connections ] |
|
|
|
|
|
|
|
if False not in results: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
time.sleep(0.05) |
|
|
|
|
|
|
|
max_tries -= 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --> error if not requested |
|
|
|
# --> error if not requested |
|
|
|
if max_tries == 0: |
|
|
|
if not wait_until(blocks_requested, attempts=20*num_blocks): |
|
|
|
# print [ c.cb.block_request_map for c in self.connections ] |
|
|
|
# print [ c.cb.block_request_map for c in self.connections ] |
|
|
|
raise AssertionError("Not all nodes requested block") |
|
|
|
raise AssertionError("Not all nodes requested block") |
|
|
|
# --> Answer request (we did this inline!) |
|
|
|
# --> Answer request (we did this inline!) |
|
|
@ -202,18 +207,14 @@ class TestManager(object): |
|
|
|
# Analogous to sync_block (see above) |
|
|
|
# Analogous to sync_block (see above) |
|
|
|
def sync_transaction(self, txhash, num_events): |
|
|
|
def sync_transaction(self, txhash, num_events): |
|
|
|
# Wait for nodes to request transaction (50ms sleep * 20 tries * num_events) |
|
|
|
# Wait for nodes to request transaction (50ms sleep * 20 tries * num_events) |
|
|
|
max_tries = 20*num_events |
|
|
|
def transaction_requested(): |
|
|
|
while max_tries > 0: |
|
|
|
return all( |
|
|
|
with mininode_lock: |
|
|
|
txhash in node.tx_request_map and node.tx_request_map[txhash] |
|
|
|
results = [ txhash in c.cb.tx_request_map and |
|
|
|
for node in self.test_nodes |
|
|
|
c.cb.tx_request_map[txhash] for c in self.connections ] |
|
|
|
) |
|
|
|
if False not in results: |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
time.sleep(0.05) |
|
|
|
|
|
|
|
max_tries -= 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# --> error if not requested |
|
|
|
# --> error if not requested |
|
|
|
if max_tries == 0: |
|
|
|
if not wait_until(transaction_requested, attempts=20*num_events): |
|
|
|
# print [ c.cb.tx_request_map for c in self.connections ] |
|
|
|
# print [ c.cb.tx_request_map for c in self.connections ] |
|
|
|
raise AssertionError("Not all nodes requested transaction") |
|
|
|
raise AssertionError("Not all nodes requested transaction") |
|
|
|
# --> Answer request (we did this inline!) |
|
|
|
# --> Answer request (we did this inline!) |
|
|
@ -336,6 +337,7 @@ class TestManager(object): |
|
|
|
print "Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ] |
|
|
|
print "Test %d: PASS" % test_number, [ c.rpc.getblockcount() for c in self.connections ] |
|
|
|
test_number += 1 |
|
|
|
test_number += 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[ c.disconnect_node() for c in self.connections ] |
|
|
|
|
|
|
|
self.wait_for_disconnections() |
|
|
|
self.block_store.close() |
|
|
|
self.block_store.close() |
|
|
|
self.tx_store.close() |
|
|
|
self.tx_store.close() |
|
|
|
[ c.disconnect_node() for c in self.connections ] |
|
|
|
|
|
|
|