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.""" | ||||
from io import BytesIO | |||||
import random | import random | ||||
from test_framework.avatools import get_stakes | from test_framework.avatools import get_stakes | ||||
from test_framework.key import ( | from test_framework.key import ( | ||||
ECKey, | ECKey, | ||||
ECPubKey, | ECPubKey, | ||||
) | ) | ||||
from test_framework.mininode import P2PInterface, mininode_lock | from test_framework.mininode import P2PInterface, mininode_lock | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
AvalancheProof, | |||||
AvalancheResponse, | AvalancheResponse, | ||||
AvalancheVote, | AvalancheVote, | ||||
CInv, | CInv, | ||||
msg_avahello, | |||||
msg_avapoll, | msg_avapoll, | ||||
msg_avaproof, | |||||
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, | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | def send_poll(self, hashes): | ||||
for h in hashes: | for h in hashes: | ||||
msg.poll.invs.append(CInv(2, h)) | msg.poll.invs.append(CInv(2, h)) | ||||
self.send_message(msg) | self.send_message(msg) | ||||
def get_avapoll_if_available(self): | def get_avapoll_if_available(self): | ||||
with mininode_lock: | with mininode_lock: | ||||
return self.avapolls.pop(0) if len(self.avapolls) > 0 else None | return self.avapolls.pop(0) if len(self.avapolls) > 0 else None | ||||
def send_avahello(self, hello): | |||||
msg = msg_avahello() | |||||
msg.hello = hello | |||||
self.send_message(msg) | |||||
def wait_for_avahello(self, timeout=5): | def wait_for_avahello(self, timeout=5): | ||||
wait_until( | wait_until( | ||||
lambda: self.avahello is not None, | lambda: self.avahello is not None, | ||||
timeout=timeout, | timeout=timeout, | ||||
lock=mininode_lock) | lock=mininode_lock) | ||||
with mininode_lock: | with mininode_lock: | ||||
return self.avahello | return self.avahello | ||||
def send_avaproof(self, proof): | |||||
msg = msg_avaproof() | |||||
msg.proof = proof | |||||
self.send_message(msg) | |||||
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']] | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# Restart the node | # Restart the node | ||||
self.restart_node(0, self.extra_args[0] + [ | self.restart_node(0, self.extra_args[0] + [ | ||||
"-avaproof={}".format(proof), | "-avaproof={}".format(proof), | ||||
"-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", | "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", | ||||
]) | ]) | ||||
self.log.info("Test the avahello signature") | self.log.info("Test the avahello signature") | ||||
quorum = get_quorum() | poll_node = get_node() | ||||
poll_node = quorum[0] | |||||
avahello = poll_node.wait_for_avahello().hello | avahello = poll_node.wait_for_avahello().hello | ||||
avakey.set(bytes.fromhex(node.getavalanchekey())) | avakey.set(bytes.fromhex(node.getavalanchekey())) | ||||
assert avakey.verify_schnorr( | assert avakey.verify_schnorr( | ||||
avahello.sig, avahello.get_sighash(poll_node)) | avahello.sig, avahello.get_sighash(poll_node)) | ||||
self.log.info("Test banning behavior on invalid avahello signature") | |||||
poll_node = get_node() | |||||
with self.nodes[0].assert_debug_log( | |||||
['Misbehaving', | |||||
'(0 -> 100) BAN THRESHOLD EXCEEDED: invalid-avalanche-handshake']): | |||||
# We use the same avahello that the node previously sent to | |||||
# another p2p interface. The signature will not correspond to | |||||
# the expected message for this peer. | |||||
poll_node.send_avahello(avahello) | |||||
# The signature is checked when the delegation can be checked, | |||||
# after receiving a proof. | |||||
proof_obj = AvalancheProof() | |||||
proof_obj.deserialize(BytesIO(bytes.fromhex(proof))) | |||||
poll_node.send_avaproof(proof_obj) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
AvalancheTest().main() | AvalancheTest().main() |