Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2020-2021 The Bitcoin developers | # Copyright (c) 2020-2021 The Bitcoin developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test the resolution of forks via avalanche.""" | """Test the resolution of forks via avalanche.""" | ||||
import random | import random | ||||
import struct | import struct | ||||
import time | |||||
from test_framework.avatools import create_coinbase_stakes | from test_framework.avatools import create_coinbase_stakes | ||||
from test_framework.key import ( | from test_framework.key import ( | ||||
bytes_to_wif, | bytes_to_wif, | ||||
ECKey, | ECKey, | ||||
ECPubKey, | ECPubKey, | ||||
) | ) | ||||
from test_framework.p2p import P2PInterface, p2p_lock | from test_framework.p2p import P2PInterface, p2p_lock | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
AvalancheDelegation, | AvalancheDelegation, | ||||
AvalancheProof, | AvalancheProof, | ||||
AvalancheResponse, | AvalancheResponse, | ||||
AvalancheVote, | AvalancheVote, | ||||
CInv, | CInv, | ||||
FromHex, | FromHex, | ||||
hash256, | hash256, | ||||
msg_avahello, | msg_avahello, | ||||
msg_avapoll, | msg_avapoll, | ||||
MSG_AVA_PROOF, | |||||
msg_getdata, | |||||
msg_tcpavaresponse, | msg_tcpavaresponse, | ||||
NODE_AVALANCHE, | NODE_AVALANCHE, | ||||
NODE_NETWORK, | NODE_NETWORK, | ||||
TCPAvalancheResponse, | TCPAvalancheResponse, | ||||
) | ) | ||||
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, | ||||
wait_until, | wait_until, | ||||
) | ) | ||||
BLOCK_ACCEPTED = 0 | BLOCK_ACCEPTED = 0 | ||||
BLOCK_INVALID = 1 | BLOCK_INVALID = 1 | ||||
BLOCK_PARKED = 2 | BLOCK_PARKED = 2 | ||||
BLOCK_FORK = 3 | BLOCK_FORK = 3 | ||||
BLOCK_UNKNOWN = -1 | BLOCK_UNKNOWN = -1 | ||||
BLOCK_MISSING = -2 | BLOCK_MISSING = -2 | ||||
BLOCK_PENDING = -3 | BLOCK_PENDING = -3 | ||||
QUORUM_NODE_COUNT = 16 | QUORUM_NODE_COUNT = 16 | ||||
UNCONDITIONAL_RELAY_DELAY = 2 * 60 | |||||
class TestNode(P2PInterface): | class TestNode(P2PInterface): | ||||
def __init__(self): | def __init__(self): | ||||
self.round = 0 | self.round = 0 | ||||
self.avahello = None | self.avahello = None | ||||
self.avaresponses = [] | self.avaresponses = [] | ||||
self.avapolls = [] | self.avapolls = [] | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | def set_test_params(self): | ||||
['-enableavalanche=1', '-avacooldown=0', '-noparkdeepreorg', '-maxreorgdepth=-1']] | ['-enableavalanche=1', '-avacooldown=0', '-noparkdeepreorg', '-maxreorgdepth=-1']] | ||||
self.supports_cli = False | self.supports_cli = False | ||||
self.rpc_timeout = 120 | self.rpc_timeout = 120 | ||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Build a fake quorum of nodes. | # Build a fake quorum of nodes. | ||||
def get_node(): | def get_node(services=NODE_NETWORK | NODE_AVALANCHE): | ||||
n = TestNode() | n = TestNode() | ||||
node.add_p2p_connection( | node.add_p2p_connection( | ||||
n, services=NODE_NETWORK | NODE_AVALANCHE) | n, services=services) | ||||
n.wait_for_verack() | 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. | ||||
n.nodeid = node.getpeerinfo()[-1]['id'] | n.nodeid = node.getpeerinfo()[-1]['id'] | ||||
return n | return n | ||||
def get_quorum(): | def get_quorum(): | ||||
▲ Show 20 Lines • Show All 255 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
interface_delegation_hex, delegated_key) | interface_delegation_hex, delegated_key) | ||||
def getdata_found(): | def getdata_found(): | ||||
with p2p_lock: | with p2p_lock: | ||||
return good_interface.last_message.get( | return good_interface.last_message.get( | ||||
"getdata") and good_interface.last_message["getdata"].inv[-1].hash == proofid | "getdata") and good_interface.last_message["getdata"].inv[-1].hash == proofid | ||||
wait_until(getdata_found) | wait_until(getdata_found) | ||||
self.log.info('Check that we can download the proof from our peer') | |||||
# Connect some blocks to trigger the proof verification | |||||
node.generate(2) | |||||
node_proofid = FromHex(AvalancheProof(), proof).proofid | |||||
getdata = msg_getdata([CInv(MSG_AVA_PROOF, node_proofid)]) | |||||
self.log.info( | |||||
"Proof has been inv'ed recently, check it can be requested") | |||||
good_interface.send_message(getdata) | |||||
def proof_received(peer): | |||||
with p2p_lock: | |||||
return peer.last_message.get( | |||||
"avaproof") and peer.last_message["avaproof"].proof.proofid == node_proofid | |||||
wait_until(lambda: proof_received(good_interface)) | |||||
# Restart the node | |||||
self.restart_node(0, self.extra_args[0] + [ | |||||
"-avaproof={}".format(proof), | |||||
"-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", | |||||
]) | |||||
node.generate(2) | |||||
self.log.info( | |||||
"The proof has not been announced, it cannot be requested") | |||||
peer = get_node(services=NODE_NETWORK) | |||||
peer.send_message(getdata) | |||||
# Give enough time for the node to answer. Since we cannot check for a | |||||
# non-event this is the best we can do | |||||
time.sleep(2) | |||||
assert not proof_received(peer) | |||||
self.log.info("The proof is known for long enough to be requested") | |||||
current_time = int(time.time()) | |||||
node.setmocktime(current_time + UNCONDITIONAL_RELAY_DELAY) | |||||
peer.send_message(getdata) | |||||
wait_until(lambda: proof_received(peer)) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
AvalancheTest().main() | AvalancheTest().main() |