Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_getavaaddr.py
Show First 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | |||||
class AllYesAvaP2PInterface(MutedAvaP2PInterface): | class AllYesAvaP2PInterface(MutedAvaP2PInterface): | ||||
def __init__(self, test_framework=None, node=None): | def __init__(self, test_framework=None, node=None): | ||||
super().__init__(test_framework, node) | super().__init__(test_framework, node) | ||||
self.is_responding = True | self.is_responding = True | ||||
def on_avapoll(self, message): | def on_avapoll(self, message): | ||||
self.send_avaresponse( | self.send_avaresponse( | ||||
message.poll.round, [ | message.poll.round, | ||||
AvalancheVote( | [ | ||||
AvalancheVoteError.ACCEPTED, inv.hash) for inv in message.poll.invs], | AvalancheVote(AvalancheVoteError.ACCEPTED, inv.hash) | ||||
self.master_privkey if self.delegation is None else self.delegated_privkey) | for inv in message.poll.invs | ||||
], | |||||
self.master_privkey if self.delegation is None else self.delegated_privkey, | |||||
) | |||||
super().on_avapoll(message) | super().on_avapoll(message) | ||||
class AvaHelloInterface(AvaP2PInterface): | class AvaHelloInterface(AvaP2PInterface): | ||||
def __init__(self): | def __init__(self): | ||||
super().__init__() | super().__init__() | ||||
def on_version(self, message): | def on_version(self, message): | ||||
self.send_message(msg_verack()) | self.send_message(msg_verack()) | ||||
self.send_message(msg_avahello()) | self.send_message(msg_avahello()) | ||||
class AvaAddrTest(BitcoinTestFramework): | class AvaAddrTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.setup_clean_chain = False | self.setup_clean_chain = False | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.extra_args = [ | self.extra_args = [ | ||||
[ | [ | ||||
'-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', | "-whitelist=noban@127.0.0.1", | ||||
] | ] | ||||
] | ] | ||||
def check_all_peers_received_getavaaddr_once(self, avapeers): | def check_all_peers_received_getavaaddr_once(self, avapeers): | ||||
def received_all_getavaaddr(avapeers): | def received_all_getavaaddr(avapeers): | ||||
with p2p_lock: | with p2p_lock: | ||||
return all(p.last_message.get("getavaaddr") | return all(p.last_message.get("getavaaddr") for p in avapeers) | ||||
for p in avapeers) | |||||
self.wait_until(lambda: received_all_getavaaddr(avapeers)) | self.wait_until(lambda: received_all_getavaaddr(avapeers)) | ||||
with p2p_lock: | with p2p_lock: | ||||
assert all(p.message_count.get( | assert all(p.message_count.get("getavaaddr", 0) == 1 for p in avapeers) | ||||
"getavaaddr", 0) == 1 for p in avapeers) | |||||
def getavaaddr_interval_test(self): | def getavaaddr_interval_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Init mock time | # Init mock time | ||||
mock_time = int(time.time()) | mock_time = int(time.time()) | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
# Add some avalanche peers to the node | # Add some avalanche peers to the node | ||||
for _ in range(10): | for _ in range(10): | ||||
node.add_p2p_connection(AllYesAvaP2PInterface(self, node)) | node.add_p2p_connection(AllYesAvaP2PInterface(self, node)) | ||||
# Build some statistics to ensure some addresses will be returned | # Build some statistics to ensure some addresses will be returned | ||||
def all_peers_received_poll(): | def all_peers_received_poll(): | ||||
with p2p_lock: | with p2p_lock: | ||||
return all(avanode.poll_received > | return all(avanode.poll_received > 0 for avanode in node.p2ps) | ||||
0 for avanode in node.p2ps) | |||||
self.wait_until(all_peers_received_poll) | self.wait_until(all_peers_received_poll) | ||||
node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | ||||
requester = node.add_p2p_connection(AddrReceiver()) | requester = node.add_p2p_connection(AddrReceiver()) | ||||
requester.send_message(msg_getavaaddr()) | requester.send_message(msg_getavaaddr()) | ||||
# Remember the time we sent the getavaaddr message | # Remember the time we sent the getavaaddr message | ||||
getavaddr_time = mock_time | getavaddr_time = mock_time | ||||
# Spamming more get getavaaddr has no effect | # Spamming more get getavaaddr has no effect | ||||
for _ in range(2): | for _ in range(2): | ||||
with node.assert_debug_log( | with node.assert_debug_log( | ||||
["Ignoring repeated getavaaddr from peer"], | ["Ignoring repeated getavaaddr from peer"], timeout=10 | ||||
timeout=10): | ): | ||||
requester.send_message(msg_getavaaddr()) | requester.send_message(msg_getavaaddr()) | ||||
# Move the time so we get an addr response | # Move the time so we get an addr response | ||||
mock_time += MAX_ADDR_SEND_DELAY | mock_time += MAX_ADDR_SEND_DELAY | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
requester.wait_until(requester.addr_received) | requester.wait_until(requester.addr_received) | ||||
# Check our message is now accepted again now that the getavaaddr | # Check our message is now accepted again now that the getavaaddr | ||||
# interval is elapsed | # interval is elapsed | ||||
assert mock_time >= getavaddr_time + GETAVAADDR_INTERVAL | assert mock_time >= getavaddr_time + GETAVAADDR_INTERVAL | ||||
requester.send_message(msg_getavaaddr()) | requester.send_message(msg_getavaaddr()) | ||||
# We can get an addr message again | # We can get an addr message again | ||||
mock_time += MAX_ADDR_SEND_DELAY | mock_time += MAX_ADDR_SEND_DELAY | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
requester.wait_until(requester.addr_received) | requester.wait_until(requester.addr_received) | ||||
def address_test(self, maxaddrtosend, num_proof, num_avanode): | def address_test(self, maxaddrtosend, num_proof, num_avanode): | ||||
self.restart_node( | self.restart_node( | ||||
0, | 0, extra_args=self.extra_args[0] + [f"-maxaddrtosend={maxaddrtosend}"] | ||||
extra_args=self.extra_args[0] + | ) | ||||
[f'-maxaddrtosend={maxaddrtosend}']) | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Init mock time | # Init mock time | ||||
mock_time = int(time.time()) | mock_time = int(time.time()) | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
# Create a bunch of proofs and associate each a bunch of nodes. | # Create a bunch of proofs and associate each a bunch of nodes. | ||||
avanodes = [] | avanodes = [] | ||||
for _ in range(num_proof): | for _ in range(num_proof): | ||||
master_privkey, proof = gen_proof(self, node) | master_privkey, proof = gen_proof(self, node) | ||||
for n in range(num_avanode): | for n in range(num_avanode): | ||||
avanode = AllYesAvaP2PInterface() if n % 2 else MutedAvaP2PInterface() | avanode = AllYesAvaP2PInterface() if n % 2 else MutedAvaP2PInterface() | ||||
avanode.master_privkey = master_privkey | avanode.master_privkey = master_privkey | ||||
avanode.proof = proof | avanode.proof = proof | ||||
node.add_p2p_connection(avanode) | node.add_p2p_connection(avanode) | ||||
peerinfo = node.getpeerinfo()[-1] | peerinfo = node.getpeerinfo()[-1] | ||||
avanode.set_addr(peerinfo["addr"]) | avanode.set_addr(peerinfo["addr"]) | ||||
avanodes.append(avanode) | avanodes.append(avanode) | ||||
responding_addresses = [ | responding_addresses = [ | ||||
avanode.addr for avanode in avanodes if avanode.is_responding] | avanode.addr for avanode in avanodes if avanode.is_responding | ||||
] | |||||
assert_equal(len(responding_addresses), num_proof * num_avanode // 2) | assert_equal(len(responding_addresses), num_proof * num_avanode // 2) | ||||
# Check we have what we expect | # Check we have what we expect | ||||
def all_nodes_connected(): | def all_nodes_connected(): | ||||
avapeers = node.getavalanchepeerinfo() | avapeers = node.getavalanchepeerinfo() | ||||
if len(avapeers) != num_proof: | if len(avapeers) != num_proof: | ||||
return False | return False | ||||
for avapeer in avapeers: | for avapeer in avapeers: | ||||
if avapeer['nodecount'] != num_avanode: | if avapeer["nodecount"] != num_avanode: | ||||
return False | return False | ||||
return True | return True | ||||
self.wait_until(all_nodes_connected) | self.wait_until(all_nodes_connected) | ||||
# Force the availability score to diverge between the responding and the | # Force the availability score to diverge between the responding and the | ||||
# muted nodes. | # muted nodes. | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
def poll_all_for_block(): | def poll_all_for_block(): | ||||
with p2p_lock: | with p2p_lock: | ||||
return all(avanode.poll_received > ( | return all( | ||||
10 if avanode.is_responding else 0) for avanode in avanodes) | avanode.poll_received > (10 if avanode.is_responding else 0) | ||||
for avanode in avanodes | |||||
) | |||||
self.wait_until(poll_all_for_block) | self.wait_until(poll_all_for_block) | ||||
# Move the scheduler time 10 minutes forward so that so that our peers | # Move the scheduler time 10 minutes forward so that so that our peers | ||||
# get an availability score computed. | # get an availability score computed. | ||||
node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | ||||
requester = node.add_p2p_connection(AddrReceiver()) | requester = node.add_p2p_connection(AddrReceiver()) | ||||
requester.send_and_ping(msg_getavaaddr()) | requester.send_and_ping(msg_getavaaddr()) | ||||
# Sanity check that the availability score is set up as expected | # Sanity check that the availability score is set up as expected | ||||
peerinfo = node.getpeerinfo() | peerinfo = node.getpeerinfo() | ||||
muted_addresses = [ | muted_addresses = [ | ||||
avanode.addr for avanode in avanodes if not avanode.is_responding] | avanode.addr for avanode in avanodes if not avanode.is_responding | ||||
assert all(p['availability_score'] < 0 | ] | ||||
for p in peerinfo if p["addr"] in muted_addresses) | assert all( | ||||
assert all(p['availability_score'] > 0 | p["availability_score"] < 0 | ||||
for p in peerinfo if p["addr"] in responding_addresses) | for p in peerinfo | ||||
if p["addr"] in muted_addresses | |||||
) | |||||
assert all( | |||||
p["availability_score"] > 0 | |||||
for p in peerinfo | |||||
if p["addr"] in responding_addresses | |||||
) | |||||
# Requester has no availability_score because it's not an avalanche | # Requester has no availability_score because it's not an avalanche | ||||
# peer | # peer | ||||
assert 'availability_score' not in peerinfo[-1].keys() | assert "availability_score" not in peerinfo[-1].keys() | ||||
mock_time += MAX_ADDR_SEND_DELAY | mock_time += MAX_ADDR_SEND_DELAY | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
requester.wait_until(requester.addr_received) | requester.wait_until(requester.addr_received) | ||||
addresses = requester.get_received_addrs() | addresses = requester.get_received_addrs() | ||||
assert_equal(len(addresses), | assert_equal(len(addresses), min(maxaddrtosend, len(responding_addresses))) | ||||
min(maxaddrtosend, len(responding_addresses))) | |||||
# Check all the addresses belong to responding peer | # Check all the addresses belong to responding peer | ||||
assert all(address in responding_addresses for address in addresses) | assert all(address in responding_addresses for address in addresses) | ||||
def getavaaddr_outbound_test(self): | def getavaaddr_outbound_test(self): | ||||
self.log.info( | self.log.info( | ||||
"Check we send a getavaaddr message to our avalanche outbound peers") | "Check we send a getavaaddr message to our avalanche outbound peers" | ||||
) | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Get rid of previously connected nodes | # Get rid of previously connected nodes | ||||
node.disconnect_p2ps() | node.disconnect_p2ps() | ||||
avapeers = [] | avapeers = [] | ||||
for i in range(16): | for i in range(16): | ||||
avapeer = AvaP2PInterface() | avapeer = AvaP2PInterface() | ||||
Show All 11 Lines | def getavaaddr_outbound_test(self): | ||||
# Because none of the avalanche peers is responding, our node should | # Because none of the avalanche peers is responding, our node should | ||||
# fail out of option shortly and send a getavaaddr message to its | # fail out of option shortly and send a getavaaddr message to its | ||||
# outbound avalanche peers. | # outbound avalanche peers. | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
def all_peers_received_getavaaddr(): | def all_peers_received_getavaaddr(): | ||||
with p2p_lock: | with p2p_lock: | ||||
return all(p.message_count.get("getavaaddr", 0) > 1 for p in avapeers) | return all(p.message_count.get("getavaaddr", 0) > 1 for p in avapeers) | ||||
self.wait_until(all_peers_received_getavaaddr) | self.wait_until(all_peers_received_getavaaddr) | ||||
def getavaaddr_manual_test(self): | def getavaaddr_manual_test(self): | ||||
self.log.info( | self.log.info( | ||||
"Check we send a getavaaddr message to our manually connected peers that support avalanche") | "Check we send a getavaaddr message to our manually connected peers that" | ||||
" support avalanche" | |||||
) | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Get rid of previously connected nodes | # Get rid of previously connected nodes | ||||
node.disconnect_p2ps() | node.disconnect_p2ps() | ||||
def added_node_connected(ip_port): | def added_node_connected(ip_port): | ||||
added_node_info = node.getaddednodeinfo(ip_port) | added_node_info = node.getaddednodeinfo(ip_port) | ||||
return len( | return len(added_node_info) == 1 and added_node_info[0]["connected"] | ||||
added_node_info) == 1 and added_node_info[0]['connected'] | |||||
def connect_callback(address, port): | def connect_callback(address, port): | ||||
self.log.debug(f"Connecting to {address}:{port}") | self.log.debug(f"Connecting to {address}:{port}") | ||||
p = AvaP2PInterface() | p = AvaP2PInterface() | ||||
p2p_idx = 1 | p2p_idx = 1 | ||||
p.peer_accept_connection( | p.peer_accept_connection( | ||||
connect_cb=connect_callback, | connect_cb=connect_callback, | ||||
connect_id=p2p_idx, | connect_id=p2p_idx, | ||||
net=node.chain, | net=node.chain, | ||||
timeout_factor=node.timeout_factor, | timeout_factor=node.timeout_factor, | ||||
)() | )() | ||||
ip_port = f"127.0.0.1:{p2p_port(MAX_NODES - p2p_idx)}" | ip_port = f"127.0.0.1:{p2p_port(MAX_NODES - p2p_idx)}" | ||||
node.addnode(node=ip_port, command="add") | node.addnode(node=ip_port, command="add") | ||||
self.wait_until(lambda: added_node_connected(ip_port)) | self.wait_until(lambda: added_node_connected(ip_port)) | ||||
assert_equal(node.getpeerinfo()[-1]['addr'], ip_port) | assert_equal(node.getpeerinfo()[-1]["addr"], ip_port) | ||||
assert_equal(node.getpeerinfo()[-1]['connection_type'], 'manual') | assert_equal(node.getpeerinfo()[-1]["connection_type"], "manual") | ||||
# Make sure p.is_connected is set, otherwise the last_message check | # Make sure p.is_connected is set, otherwise the last_message check | ||||
# below will assert. | # below will assert. | ||||
p.wait_for_connect() | p.wait_for_connect() | ||||
p.wait_until(lambda: p.last_message.get("getavaaddr")) | p.wait_until(lambda: p.last_message.get("getavaaddr")) | ||||
# Generate some block to poll for | # Generate some block to poll for | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
# Because our avalanche peer is not responding, our node should fail | # Because our avalanche peer is not responding, our node should fail | ||||
# out of option shortly and send another getavaaddr message. | # out of option shortly and send another getavaaddr message. | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
p.wait_until(lambda: p.message_count.get("getavaaddr", 0) > 1) | p.wait_until(lambda: p.message_count.get("getavaaddr", 0) > 1) | ||||
def getavaaddr_noquorum(self): | def getavaaddr_noquorum(self): | ||||
self.log.info( | self.log.info( | ||||
"Check we send a getavaaddr message while our quorum is not established") | "Check we send a getavaaddr message while our quorum is not established" | ||||
) | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
self.restart_node(0, extra_args=self.extra_args[0] + [ | self.restart_node( | ||||
'-avaminquorumstake=500000000', | 0, | ||||
'-avaminquorumconnectedstakeratio=0.8', | extra_args=self.extra_args[0] | ||||
]) | + [ | ||||
"-avaminquorumstake=500000000", | |||||
"-avaminquorumconnectedstakeratio=0.8", | |||||
], | |||||
) | |||||
avapeers = [] | avapeers = [] | ||||
for i in range(16): | for i in range(16): | ||||
avapeer = AllYesAvaP2PInterface(self, node) | avapeer = AllYesAvaP2PInterface(self, node) | ||||
node.add_outbound_p2p_connection( | node.add_outbound_p2p_connection( | ||||
avapeer, | avapeer, | ||||
p2p_idx=i, | p2p_idx=i, | ||||
connection_type="avalanche", | connection_type="avalanche", | ||||
services=NODE_NETWORK | NODE_AVALANCHE, | services=NODE_NETWORK | NODE_AVALANCHE, | ||||
) | ) | ||||
avapeers.append(avapeer) | avapeers.append(avapeer) | ||||
peerinfo = node.getpeerinfo()[-1] | peerinfo = node.getpeerinfo()[-1] | ||||
avapeer.set_addr(peerinfo["addr"]) | avapeer.set_addr(peerinfo["addr"]) | ||||
self.check_all_peers_received_getavaaddr_once(avapeers) | self.check_all_peers_received_getavaaddr_once(avapeers) | ||||
def total_getavaaddr_msg(): | def total_getavaaddr_msg(): | ||||
with p2p_lock: | with p2p_lock: | ||||
return sum([p.message_count.get("getavaaddr", 0) | return sum([p.message_count.get("getavaaddr", 0) for p in avapeers]) | ||||
for p in avapeers]) | |||||
# Because we have not enough stake to start polling, we keep requesting | # Because we have not enough stake to start polling, we keep requesting | ||||
# more addresses from all our peers | # more addresses from all our peers | ||||
total_getavaaddr = total_getavaaddr_msg() | total_getavaaddr = total_getavaaddr_msg() | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
self.wait_until(lambda: total_getavaaddr_msg() == | self.wait_until( | ||||
total_getavaaddr + len(avapeers)) | lambda: total_getavaaddr_msg() == total_getavaaddr + len(avapeers) | ||||
) | |||||
# Move the schedulter time forward to make sure we get statistics | # Move the schedulter time forward to make sure we get statistics | ||||
# computed. But since we did not start polling yet it should remain all | # computed. But since we did not start polling yet it should remain all | ||||
# zero. | # zero. | ||||
node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | node.mockscheduler(AVALANCHE_STATISTICS_INTERVAL) | ||||
def wait_for_availability_score(): | def wait_for_availability_score(): | ||||
peerinfo = node.getpeerinfo() | peerinfo = node.getpeerinfo() | ||||
return all(p.get('availability_score', None) == Decimal(0) | return all( | ||||
for p in peerinfo) | p.get("availability_score", None) == Decimal(0) for p in peerinfo | ||||
) | |||||
self.wait_until(wait_for_availability_score) | self.wait_until(wait_for_availability_score) | ||||
requester = node.add_p2p_connection(AddrReceiver()) | requester = node.add_p2p_connection(AddrReceiver()) | ||||
requester.send_and_ping(msg_getavaaddr()) | requester.send_and_ping(msg_getavaaddr()) | ||||
node.setmocktime(int(time.time() + MAX_ADDR_SEND_DELAY)) | node.setmocktime(int(time.time() + MAX_ADDR_SEND_DELAY)) | ||||
# Check all the peers addresses are returned. | # Check all the peers addresses are returned. | ||||
requester.wait_until(requester.addr_received) | requester.wait_until(requester.addr_received) | ||||
addresses = requester.get_received_addrs() | addresses = requester.get_received_addrs() | ||||
assert_equal(len(addresses), len(avapeers)) | assert_equal(len(addresses), len(avapeers)) | ||||
expected_addresses = [avapeer.addr for avapeer in avapeers] | expected_addresses = [avapeer.addr for avapeer in avapeers] | ||||
assert all(address in expected_addresses for address in addresses) | assert all(address in expected_addresses for address in addresses) | ||||
# Add more nodes so we reach the mininum quorum stake amount. | # Add more nodes so we reach the mininum quorum stake amount. | ||||
for _ in range(4): | for _ in range(4): | ||||
avapeer = AllYesAvaP2PInterface(self, node) | avapeer = AllYesAvaP2PInterface(self, node) | ||||
node.add_p2p_connection(avapeer) | node.add_p2p_connection(avapeer) | ||||
self.wait_until(lambda: node.getavalancheinfo() | self.wait_until(lambda: node.getavalancheinfo()["ready_to_poll"] is True) | ||||
['ready_to_poll'] is True) | |||||
def is_vote_finalized(proof): | def is_vote_finalized(proof): | ||||
return node.getrawavalancheproof( | return node.getrawavalancheproof(uint256_hex(proof.proofid)).get( | ||||
uint256_hex(proof.proofid)).get("finalized", False) | "finalized", False | ||||
) | |||||
# Wait until all proofs are finalized | # Wait until all proofs are finalized | ||||
self.wait_until(lambda: all(is_vote_finalized(p.proof) | self.wait_until( | ||||
for p in node.p2ps if isinstance(p, AvaP2PInterface))) | lambda: all( | ||||
is_vote_finalized(p.proof) | |||||
for p in node.p2ps | |||||
if isinstance(p, AvaP2PInterface) | |||||
) | |||||
) | |||||
# Go through several rounds of getavaaddr requests. We don't know for | # Go through several rounds of getavaaddr requests. We don't know for | ||||
# sure how many will be sent as it depends on whether the peers | # sure how many will be sent as it depends on whether the peers | ||||
# responded fast enough during the polling phase, but at some point a | # responded fast enough during the polling phase, but at some point a | ||||
# single outbound peer will be requested and no more. | # single outbound peer will be requested and no more. | ||||
def sent_single_getavaaddr(): | def sent_single_getavaaddr(): | ||||
total_getavaaddr = total_getavaaddr_msg() | total_getavaaddr = total_getavaaddr_msg() | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
self.wait_until(lambda: total_getavaaddr_msg() | self.wait_until(lambda: total_getavaaddr_msg() >= total_getavaaddr + 1) | ||||
>= total_getavaaddr + 1) | |||||
for p in avapeers: | for p in avapeers: | ||||
p.sync_send_with_ping() | p.sync_send_with_ping() | ||||
return total_getavaaddr_msg() == total_getavaaddr + 1 | return total_getavaaddr_msg() == total_getavaaddr + 1 | ||||
self.wait_until(sent_single_getavaaddr) | self.wait_until(sent_single_getavaaddr) | ||||
def test_send_inbound_getavaaddr_until_quorum_is_established(self): | def test_send_inbound_getavaaddr_until_quorum_is_established(self): | ||||
self.log.info( | self.log.info( | ||||
"Check we also request the inbounds until the quorum is established") | "Check we also request the inbounds until the quorum is established" | ||||
) | |||||
node = self.nodes[0] | node = self.nodes[0] | ||||
self.restart_node( | self.restart_node( | ||||
0, | 0, extra_args=self.extra_args[0] + ["-avaminquorumstake=1000000"] | ||||
extra_args=self.extra_args[0] + | ) | ||||
['-avaminquorumstake=1000000']) | |||||
assert_equal(node.getavalancheinfo()['ready_to_poll'], False) | assert_equal(node.getavalancheinfo()["ready_to_poll"], False) | ||||
outbound = MutedAvaP2PInterface() | outbound = MutedAvaP2PInterface() | ||||
node.add_outbound_p2p_connection(outbound, p2p_idx=0) | node.add_outbound_p2p_connection(outbound, p2p_idx=0) | ||||
inbound = MutedAvaP2PInterface() | inbound = MutedAvaP2PInterface() | ||||
node.add_p2p_connection(inbound) | node.add_p2p_connection(inbound) | ||||
inbound.nodeid = node.getpeerinfo()[-1]['id'] | inbound.nodeid = node.getpeerinfo()[-1]["id"] | ||||
def count_getavaaddr(peers): | def count_getavaaddr(peers): | ||||
with p2p_lock: | with p2p_lock: | ||||
return sum([peer.message_count.get("getavaaddr", 0) | return sum([peer.message_count.get("getavaaddr", 0) for peer in peers]) | ||||
for peer in peers]) | |||||
# Upon connection only the outbound gets a getavaaddr message | # Upon connection only the outbound gets a getavaaddr message | ||||
assert_equal(count_getavaaddr([inbound]), 0) | assert_equal(count_getavaaddr([inbound]), 0) | ||||
self.wait_until(lambda: count_getavaaddr([outbound]) == 1) | self.wait_until(lambda: count_getavaaddr([outbound]) == 1) | ||||
# Periodic send will include the inbound as well | # Periodic send will include the inbound as well | ||||
current_total = count_getavaaddr([inbound, outbound]) | current_total = count_getavaaddr([inbound, outbound]) | ||||
while count_getavaaddr([inbound]) == 0: | while count_getavaaddr([inbound]) == 0: | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
self.wait_until(lambda: count_getavaaddr( | self.wait_until( | ||||
[inbound, outbound]) > current_total) | lambda: count_getavaaddr([inbound, outbound]) > current_total | ||||
) | |||||
current_total = count_getavaaddr([inbound, outbound]) | current_total = count_getavaaddr([inbound, outbound]) | ||||
# Connect the minimum amount of stake and nodes | # Connect the minimum amount of stake and nodes | ||||
for _ in range(8): | for _ in range(8): | ||||
node.add_p2p_connection(AvaP2PInterface(self, node)) | node.add_p2p_connection(AvaP2PInterface(self, node)) | ||||
self.wait_until(lambda: node.getavalancheinfo() | self.wait_until(lambda: node.getavalancheinfo()["ready_to_poll"] is True) | ||||
['ready_to_poll'] is True) | |||||
# From now only the outbound is requested | # From now only the outbound is requested | ||||
count_inbound = count_getavaaddr([inbound]) | count_inbound = count_getavaaddr([inbound]) | ||||
for _ in range(10): | for _ in range(10): | ||||
# Trigger a poll | # Trigger a poll | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
inbound.sync_send_with_ping() | inbound.sync_send_with_ping() | ||||
node.mockscheduler(MAX_GETAVAADDR_DELAY) | node.mockscheduler(MAX_GETAVAADDR_DELAY) | ||||
self.wait_until(lambda: count_getavaaddr( | self.wait_until( | ||||
[inbound, outbound]) > current_total) | lambda: count_getavaaddr([inbound, outbound]) > current_total | ||||
) | |||||
current_total = count_getavaaddr([inbound, outbound]) | current_total = count_getavaaddr([inbound, outbound]) | ||||
assert_equal(count_getavaaddr([inbound]), count_inbound) | assert_equal(count_getavaaddr([inbound]), count_inbound) | ||||
def test_addr_requests_order(self): | def test_addr_requests_order(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Get rid of previously connected nodes | # Get rid of previously connected nodes | ||||
node.disconnect_p2ps() | node.disconnect_p2ps() | ||||
def check_addr_requests(p): | def check_addr_requests(p): | ||||
p.wait_until(lambda: p.last_message.get("getavaaddr")) | p.wait_until(lambda: p.last_message.get("getavaaddr")) | ||||
p.wait_until(lambda: p.message_count.get("getavaaddr", 0) == 1) | p.wait_until(lambda: p.message_count.get("getavaaddr", 0) == 1) | ||||
p.wait_until(lambda: p.last_message.get("getaddr")) | p.wait_until(lambda: p.last_message.get("getaddr")) | ||||
p.wait_until(lambda: p.message_count.get("getaddr", 0) == 1) | p.wait_until(lambda: p.message_count.get("getaddr", 0) == 1) | ||||
# Test getaddr is sent first | # Test getaddr is sent first | ||||
requester1 = node.add_outbound_p2p_connection( | requester1 = node.add_outbound_p2p_connection(AvaHelloInterface(), p2p_idx=0) | ||||
AvaHelloInterface(), p2p_idx=0) | |||||
requester1.send_message(msg_getaddr()) | requester1.send_message(msg_getaddr()) | ||||
requester1.send_message(msg_getavaaddr()) | requester1.send_message(msg_getavaaddr()) | ||||
check_addr_requests(requester1) | check_addr_requests(requester1) | ||||
# Test getavaaddr is sent first | # Test getavaaddr is sent first | ||||
requester2 = node.add_outbound_p2p_connection( | requester2 = node.add_outbound_p2p_connection(AvaHelloInterface(), p2p_idx=1) | ||||
AvaHelloInterface(), p2p_idx=1) | |||||
requester2.send_message(msg_getavaaddr()) | requester2.send_message(msg_getavaaddr()) | ||||
requester2.send_message(msg_getaddr()) | requester2.send_message(msg_getaddr()) | ||||
check_addr_requests(requester2) | check_addr_requests(requester2) | ||||
def run_test(self): | def run_test(self): | ||||
self.getavaaddr_interval_test() | self.getavaaddr_interval_test() | ||||
# Limited by maxaddrtosend | # Limited by maxaddrtosend | ||||
self.address_test(maxaddrtosend=3, num_proof=2, num_avanode=8) | self.address_test(maxaddrtosend=3, num_proof=2, num_avanode=8) | ||||
# Limited by the number of good nodes | # Limited by the number of good nodes | ||||
self.address_test(maxaddrtosend=100, num_proof=2, num_avanode=8) | self.address_test(maxaddrtosend=100, num_proof=2, num_avanode=8) | ||||
self.getavaaddr_outbound_test() | self.getavaaddr_outbound_test() | ||||
self.getavaaddr_manual_test() | self.getavaaddr_manual_test() | ||||
self.getavaaddr_noquorum() | self.getavaaddr_noquorum() | ||||
self.test_send_inbound_getavaaddr_until_quorum_is_established() | self.test_send_inbound_getavaaddr_until_quorum_is_established() | ||||
self.test_addr_requests_order() | self.test_addr_requests_order() | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
AvaAddrTest().main() | AvaAddrTest().main() |