Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche_proof_voting.py
Show First 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
addrkey0 = node.get_deterministic_priv_key() | addrkey0 = node.get_deterministic_priv_key() | ||||
blockhash = node.generatetoaddress(10, addrkey0.address) | blockhash = node.generatetoaddress(10, addrkey0.address) | ||||
self.conflicting_stakes = create_coinbase_stakes( | self.conflicting_stakes = create_coinbase_stakes( | ||||
node, blockhash[5:], addrkey0.key) | node, blockhash[5:], addrkey0.key) | ||||
self.poll_tests(node) | self.poll_tests(node) | ||||
self.update_tests(node) | self.update_tests(node) | ||||
self.vote_tests(node) | self.vote_tests(node) | ||||
# If majority votes are inconclusive, the proof should eventually | |||||
# invalidate | |||||
self.inconclusive_proof_tests( | |||||
node, "invalidated", AvalancheProofVoteResponse.INCONCLUSIVE) | |||||
# If majority votes are accepted when some node votes inconclusive, the | |||||
# proof should still eventually finalize | |||||
self.inconclusive_proof_tests( | |||||
node, "finalized", AvalancheProofVoteResponse.ACTIVE) | |||||
def poll_tests(self, node): | def poll_tests(self, node): | ||||
proof_seq10 = self.build_conflicting_proof(node, 10) | proof_seq10 = self.build_conflicting_proof(node, 10) | ||||
proof_seq20 = self.build_conflicting_proof(node, 20) | proof_seq20 = self.build_conflicting_proof(node, 20) | ||||
proof_seq30 = self.build_conflicting_proof(node, 30) | proof_seq30 = self.build_conflicting_proof(node, 30) | ||||
proof_seq40 = self.build_conflicting_proof(node, 40) | proof_seq40 = self.build_conflicting_proof(node, 40) | ||||
orphan = node.buildavalancheproof( | orphan = node.buildavalancheproof( | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | def poll_tests(self, node): | ||||
peer.send_avaproof(avalanche_proof_from_hex(proof_seq10)) | peer.send_avaproof(avalanche_proof_from_hex(proof_seq10)) | ||||
self.log.info("Check we don't poll for invalid proofs and get banned") | self.log.info("Check we don't poll for invalid proofs and get banned") | ||||
with node.assert_debug_log(["Misbehaving", "invalid-proof"]): | with node.assert_debug_log(["Misbehaving", "invalid-proof"]): | ||||
peer.send_avaproof(avalanche_proof_from_hex(no_stake)) | peer.send_avaproof(avalanche_proof_from_hex(no_stake)) | ||||
peer.wait_for_disconnect() | peer.wait_for_disconnect() | ||||
def update_tests(self, node): | def update_tests(self, node): | ||||
# Restart the node to get rid og in-flight requests | # Restart the node to get rid of in-flight requests | ||||
self.restart_node(0) | self.restart_node(0) | ||||
mock_time = int(time.time()) | mock_time = int(time.time()) | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
self.quorum = self.get_quorum(node) | self.quorum = self.get_quorum(node) | ||||
peer = get_ava_p2p_interface(node) | peer = get_ava_p2p_interface(node) | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | def vote_tests(self, node): | ||||
ava_node.send_proof(avalanche_proof_from_hex(proof_4)) | ava_node.send_proof(avalanche_proof_from_hex(proof_4)) | ||||
poll_assert_response([ | poll_assert_response([ | ||||
AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), | AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_0_id), | ||||
AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), | AvalancheVote(AvalancheProofVoteResponse.ACTIVE, proof_1_id), | ||||
AvalancheVote(AvalancheProofVoteResponse.ORPHAN, proof_2_id), | AvalancheVote(AvalancheProofVoteResponse.ORPHAN, proof_2_id), | ||||
AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), | AvalancheVote(AvalancheProofVoteResponse.CONFLICT, proof_3_id), | ||||
AvalancheVote(AvalancheProofVoteResponse.REJECTED, proof_4_id)]) | AvalancheVote(AvalancheProofVoteResponse.REJECTED, proof_4_id)]) | ||||
def inconclusive_proof_tests(self, node, expectedLog, quorumResponse): | |||||
# Restart the node to get rid of in-flight requests | |||||
self.restart_node(0) | |||||
mock_time = int(time.time()) | |||||
node.setmocktime(mock_time) | |||||
self.quorum = self.get_quorum(node) | |||||
peer = get_ava_p2p_interface(node) | |||||
proof_seq1 = self.build_conflicting_proof(node, 1) | |||||
proof_seq2 = self.build_conflicting_proof(node, 2) | |||||
proofid_seq1 = avalanche_proof_from_hex(proof_seq1).proofid | |||||
proofid_seq2 = avalanche_proof_from_hex(proof_seq2).proofid | |||||
node.sendavalancheproof(proof_seq2) | |||||
self.wait_until(lambda: proofid_seq2 in get_proof_ids(node)) | |||||
assert proofid_seq2 in get_proof_ids(node) | |||||
assert proofid_seq1 not in get_proof_ids(node) | |||||
mock_time += self.conflicting_proof_cooldown | |||||
node.setmocktime(mock_time) | |||||
def poll_and_check(proofid, expected): | |||||
peer.send_poll([proofid], MSG_AVA_PROOF) | |||||
response = peer.wait_for_avaresponse() | |||||
r = response.response | |||||
return repr(r.votes[0]) == repr(AvalancheVote(expected, proofid)) | |||||
assert poll_and_check(proofid_seq1, AvalancheProofVoteResponse.UNKNOWN) | |||||
peer.send_avaproof(avalanche_proof_from_hex(proof_seq1)) | |||||
def reciprocate_poll(proofid, pollResponse, expected): | |||||
self.can_find_proof_in_poll(proofid, response=pollResponse) | |||||
return poll_and_check(proofid, expected) | |||||
assert reciprocate_poll( | |||||
proofid_seq1, | |||||
AvalancheProofVoteResponse.UNKNOWN, | |||||
AvalancheProofVoteResponse.CONFLICT) | |||||
# Wait until proof_seq1 becomes inconclusive | |||||
self.wait_until( | |||||
lambda: reciprocate_poll( | |||||
proofid_seq1, | |||||
AvalancheProofVoteResponse.UNKNOWN, | |||||
AvalancheProofVoteResponse.INCONCLUSIVE)) | |||||
# Wait until proof_seq1 voting is completed. We start responding to polls as if the quorum nodes | |||||
# have come to the same conclusion as each other. | |||||
retry = 5 | |||||
while retry > 0: | |||||
try: | |||||
with node.assert_debug_log([f"Avalanche {expectedLog} proof {proofid_seq1:0{64}x}"]): | |||||
self.wait_until(lambda: not self.can_find_proof_in_poll( | |||||
proofid_seq1, response=quorumResponse)) | |||||
break | |||||
except AssertionError: | |||||
retry -= 1 | |||||
assert_greater_than(retry, 0) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
AvalancheProofVotingTest().main() | AvalancheProofVotingTest().main() |