Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche_voting.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 | ||||
from test_framework.avatools import ( | from test_framework.avatools import get_ava_p2p_interface | ||||
create_coinbase_stakes, | from test_framework.key import ECPubKey | ||||
get_ava_p2p_interface, | |||||
) | |||||
from test_framework.key import ECKey, ECPubKey | |||||
from test_framework.messages import AvalancheVote, AvalancheVoteError | from test_framework.messages import AvalancheVote, AvalancheVoteError | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import assert_equal, uint256_hex | from test_framework.util import assert_equal, uint256_hex | ||||
from test_framework.wallet_util import bytes_to_wif | |||||
QUORUM_NODE_COUNT = 16 | QUORUM_NODE_COUNT = 16 | ||||
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 = [ | ||||
[ | [ | ||||
'-avalanche=1', | '-avalanche=1', | ||||
'-avaproofstakeutxodustthreshold=1000000', | '-avaproofstakeutxodustthreshold=1000000', | ||||
'-avaproofstakeutxoconfirmations=1', | '-avaproofstakeutxoconfirmations=1', | ||||
'-avacooldown=0', | '-avacooldown=0', | ||||
'-avaminquorumstake=0', | '-avaminquorumstake=0', | ||||
'-avaminavaproofsnodecount=0', | '-avaminavaproofsnodecount=0', | ||||
'-whitelist=noban@127.0.0.1', | |||||
], | ], | ||||
[ | [ | ||||
'-avalanche=1', | '-avalanche=1', | ||||
'-avaproofstakeutxoconfirmations=1', | '-avaproofstakeutxoconfirmations=1', | ||||
'-avacooldown=0', | '-avacooldown=0', | ||||
'-avaminquorumstake=0', | '-avaminquorumstake=0', | ||||
'-avaminavaproofsnodecount=0', | '-avaminavaproofsnodecount=0', | ||||
'-noparkdeepreorg', | '-noparkdeepreorg', | ||||
'-maxreorgdepth=-1' | '-maxreorgdepth=-1', | ||||
'-whitelist=noban@127.0.0.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_quorum(): | def get_quorum(): | ||||
return [get_ava_p2p_interface(node) | return [get_ava_p2p_interface(node) | ||||
for _ in range(0, QUORUM_NODE_COUNT)] | for _ in range(0, QUORUM_NODE_COUNT)] | ||||
# Pick on node from the quorum for polling. | # Pick on node from the quorum for polling. | ||||
quorum = get_quorum() | quorum = get_quorum() | ||||
poll_node = quorum[0] | poll_node = quorum[0] | ||||
# Generate many block and poll for them. | assert node.getavalancheinfo()['ready_to_poll'] is True | ||||
addrkey0 = node.get_deterministic_priv_key() | |||||
blockhashes = node.generatetoaddress(100, addrkey0.address) | |||||
# Use the first coinbase to create a stake | |||||
stakes = create_coinbase_stakes(node, [blockhashes[0]], addrkey0.key) | |||||
# duplicate the deterministic sig test from src/test/key_tests.cpp | |||||
privkey = ECKey() | |||||
privkey.set(bytes.fromhex( | |||||
"12b004fff7f4b69ef8650e767f18f11ede158148b425660723b9f9a66e61f747"), True) | |||||
proof_sequence = 11 | |||||
proof_expiration = 0 | |||||
proof = node.buildavalancheproof( | |||||
proof_sequence, proof_expiration, bytes_to_wif( | |||||
privkey.get_bytes()), | |||||
stakes) | |||||
# Activate the quorum. | # Generate many block and poll for them. | ||||
for n in quorum: | node.generate(100 - node.getblockcount()) | ||||
success = node.addavalanchenode( | |||||
n.nodeid, privkey.get_pubkey().get_bytes().hex(), proof) | |||||
assert success is True | |||||
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]) | ||||
# Get the key so we can verify signatures. | # Get the key so we can verify signatures. | ||||
avakey = ECPubKey() | avakey = ECPubKey() | ||||
avakey.set(bytes.fromhex(node.getavalanchekey())) | avakey.set(bytes.fromhex(node.getavalanchekey())) | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
# Look for what we expect | # Look for what we expect | ||||
if inv.hash == hash: | if inv.hash == hash: | ||||
r = resp | r = resp | ||||
found_hash = True | found_hash = True | ||||
votes.append(AvalancheVote(r, inv.hash)) | votes.append(AvalancheVote(r, inv.hash)) | ||||
n.send_avaresponse(poll.round, votes, privkey) | n.send_avaresponse(poll.round, votes, n.delegated_privkey) | ||||
return found_hash | return found_hash | ||||
# Now that we have a peer, we should start polling for the tip. | # Now that we have a peer, we should start polling for the tip. | ||||
hash_tip = int(node.getbestblockhash(), 16) | hash_tip = int(node.getbestblockhash(), 16) | ||||
self.wait_until(lambda: can_find_block_in_poll(hash_tip), timeout=5) | self.wait_until(lambda: can_find_block_in_poll(hash_tip), timeout=5) | ||||
# Make sure the fork node has synced the blocks | # Make sure the fork node has synced the blocks | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
assert_equal(node.getbestblockhash(), fork_tip) | assert_equal(node.getbestblockhash(), fork_tip) | ||||
self.log.info( | self.log.info( | ||||
"Check the node is discouraging unexpected avaresponses.") | "Check the node is discouraging unexpected avaresponses.") | ||||
with node.assert_debug_log( | with node.assert_debug_log( | ||||
['Misbehaving', 'peer=1 (0 -> 2): unexpected-ava-response']): | ['Misbehaving', 'peer=1 (0 -> 2): unexpected-ava-response']): | ||||
# unknown voting round | # unknown voting round | ||||
poll_node.send_avaresponse( | poll_node.send_avaresponse( | ||||
round=2**32 - 1, votes=[], privkey=privkey) | round=2**32 - 1, votes=[], privkey=poll_node.delegated_privkey) | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
AvalancheTest().main() | AvalancheTest().main() |