Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche.py
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | def wait_for_avaresponse(self, timeout=5): | ||||
wait_until( | wait_until( | ||||
lambda: len(self.avaresponses) > 0, | lambda: len(self.avaresponses) > 0, | ||||
timeout=timeout, | timeout=timeout, | ||||
lock=mininode_lock) | lock=mininode_lock) | ||||
with mininode_lock: | with mininode_lock: | ||||
return self.avaresponses.pop(0) | return self.avaresponses.pop(0) | ||||
def wait_for_avapoll(self, timeout=5): | def get_avapoll_if_available(self): | ||||
wait_until( | |||||
lambda: len(self.avapolls) > 0, | |||||
timeout=timeout, | |||||
lock=mininode_lock) | |||||
with mininode_lock: | with mininode_lock: | ||||
return self.avapolls.pop(0) | return self.avapolls.pop(0) if len(self.avapolls) > 0 else None | ||||
class AvalancheTest(BitcoinTestFramework): | class AvalancheTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 2 | self.num_nodes = 2 | ||||
self.extra_args = [ | self.extra_args = [ | ||||
['-enableavalanche=1', '-avacooldown=0'], | ['-enableavalanche=1', '-avacooldown=0'], | ||||
['-enableavalanche=1', '-avacooldown=0', '-noparkdeepreorg', '-maxreorgdepth=-1']] | ['-enableavalanche=1', '-avacooldown=0', '-noparkdeepreorg', '-maxreorgdepth=-1']] | ||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Create a fake node and connect it to our real node. | # Build a fake quorum of nodes. | ||||
poll_node = TestNode() | quorum = [] | ||||
node.add_p2p_connection(poll_node) | for i in range(0, 8): | ||||
poll_node.wait_for_verack() | n = TestNode() | ||||
poll_node.sync_with_ping() | quorum.append(n) | ||||
node.add_p2p_connection(n) | |||||
n.wait_for_verack() | |||||
# Get our own node id so we can use it later. | # Get our own node id so we can use it later. | ||||
nodeid = node.getpeerinfo()[-1]['id'] | n.nodeid = node.getpeerinfo()[-1]['id'] | ||||
# Pick on node from the quorum for polling. | |||||
poll_node = quorum[0] | |||||
# Generate many block and poll for them. | # Generate many block and poll for them. | ||||
address = node.get_deterministic_priv_key().address | address = node.get_deterministic_priv_key().address | ||||
node.generatetoaddress(100, address) | node.generatetoaddress(100, address) | ||||
fork_node = self.nodes[1] | fork_node = self.nodes[1] | ||||
# Make sure the fork node has synced the blocks | # Make sure the fork node has synced the blocks | ||||
self.sync_blocks([node, fork_node]) | self.sync_blocks([node, fork_node]) | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
[AvalancheVote(BLOCK_UNKNOWN, h) for h in various_block_hashes[-3:]]) | [AvalancheVote(BLOCK_UNKNOWN, h) for h in various_block_hashes[-3:]]) | ||||
self.log.info("Trigger polling from the node...") | self.log.info("Trigger polling from the node...") | ||||
# duplicate the deterministic sig test from src/test/key_tests.cpp | # duplicate the deterministic sig test from src/test/key_tests.cpp | ||||
privkey = bytes.fromhex( | privkey = bytes.fromhex( | ||||
"12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747") | "12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747") | ||||
pubkey = schnorr.getpubkey(privkey, compressed=True) | pubkey = schnorr.getpubkey(privkey, compressed=True) | ||||
node.addavalanchepeer(nodeid, pubkey.hex()) | # Activate the quorum. | ||||
for n in quorum: | |||||
node.addavalanchepeer(n.nodeid, pubkey.hex()) | |||||
# Make sure the fork node has synced the blocks | # Make sure the fork node has synced the blocks | ||||
self.sync_blocks([node, fork_node]) | self.sync_blocks([node, fork_node]) | ||||
# Create a fork 2 blocks deep. This should trigger polling. | # Create a fork 2 blocks deep. This should trigger polling. | ||||
fork_node.invalidateblock(fork_node.getblockhash(100)) | fork_node.invalidateblock(fork_node.getblockhash(100)) | ||||
fork_address = fork_node.get_deterministic_priv_key().address | fork_address = fork_node.get_deterministic_priv_key().address | ||||
fork_node.generatetoaddress(2, fork_address) | fork_node.generatetoaddress(2, fork_address) | ||||
def can_find_block_in_poll(hash): | def can_find_block_in_poll(hash): | ||||
poll = poll_node.wait_for_avapoll() | found_hash = False | ||||
invs = poll.invs | for n in quorum: | ||||
poll = n.get_avapoll_if_available() | |||||
# That node has not received a poll | |||||
if poll is None: | |||||
continue | |||||
# We got a poll, check for the hash and repond | |||||
votes = [] | votes = [] | ||||
found_hash = False | for inv in poll.invs: | ||||
for inv in invs: | |||||
# Look for what we expect | # Look for what we expect | ||||
if inv.hash == hash: | if inv.hash == hash: | ||||
found_hash = True | found_hash = True | ||||
# Vote yes to everything | # Vote yes to everything | ||||
votes.append(AvalancheVote(BLOCK_ACCEPTED, inv.hash)) | votes.append(AvalancheVote(BLOCK_ACCEPTED, inv.hash)) | ||||
poll_node.send_avaresponse(poll.round, votes, privkey) | n.send_avaresponse(poll.round, votes, privkey) | ||||
return found_hash | return found_hash | ||||
# Because the new tip is a deep reorg, the node should start to poll | # Because the new tip is a deep reorg, the node should start to poll | ||||
# for it. | # for it. | ||||
hash_to_find = int(fork_node.getbestblockhash(), 16) | hash_to_find = int(fork_node.getbestblockhash(), 16) | ||||
wait_until(lambda: can_find_block_in_poll(hash_to_find), timeout=5) | wait_until(lambda: can_find_block_in_poll(hash_to_find), timeout=5) | ||||
# To verify that responses are processed, do it a few more times. | # To verify that responses are processed, do it a few more times. | ||||
for _ in range(10): | for _ in range(10): | ||||
wait_until(lambda: can_find_block_in_poll(hash_to_find), timeout=5) | wait_until(lambda: can_find_block_in_poll(hash_to_find), timeout=5) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
AvalancheTest().main() | AvalancheTest().main() |