Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_rpc_getavalancheproofs.py
Show All 17 Lines | |||||
from test_framework.util import assert_equal, try_rpc, uint256_hex | from test_framework.util import assert_equal, try_rpc, uint256_hex | ||||
from test_framework.wallet_util import bytes_to_wif | from test_framework.wallet_util import bytes_to_wif | ||||
class GetAvalancheProofsTest(BitcoinTestFramework): | class GetAvalancheProofsTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
self.conflicting_proof_cooldown = 100 | self.conflicting_proof_cooldown = 100 | ||||
self.extra_args = [[ | self.extra_args = [ | ||||
f'-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}', | [ | ||||
'-avaproofstakeutxoconfirmations=2', | f"-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}", | ||||
'-avacooldown=0', | "-avaproofstakeutxoconfirmations=2", | ||||
'-avaminquorumstake=250000000', | "-avacooldown=0", | ||||
'-avaminquorumconnectedstakeratio=0.9', | "-avaminquorumstake=250000000", | ||||
'-avaproofstakeutxodustthreshold=1000000', | "-avaminquorumconnectedstakeratio=0.9", | ||||
'-avaminavaproofsnodecount=0', | "-avaproofstakeutxodustthreshold=1000000", | ||||
]] | "-avaminavaproofsnodecount=0", | ||||
] | |||||
] | |||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
privkey, proof = gen_proof(self, node) | privkey, proof = gen_proof(self, node) | ||||
# Make the proof mature | # Make the proof mature | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
def avalancheproofs_equals(expected): | def avalancheproofs_equals(expected): | ||||
proofs = node.getavalancheproofs() | proofs = node.getavalancheproofs() | ||||
for key, proof_list in proofs.items(): | for key, proof_list in proofs.items(): | ||||
proof_list.sort() | proof_list.sort() | ||||
for key, proof_list in expected.items(): | for key, proof_list in expected.items(): | ||||
proof_list.sort() | proof_list.sort() | ||||
return proofs == expected | return proofs == expected | ||||
self.log.info("The test node has no proof") | self.log.info("The test node has no proof") | ||||
assert avalancheproofs_equals({ | assert avalancheproofs_equals( | ||||
{ | |||||
"valid": [], | "valid": [], | ||||
"conflicting": [], | "conflicting": [], | ||||
"immature": [], | "immature": [], | ||||
}) | } | ||||
) | |||||
self.log.info("The test node has a proof") | self.log.info("The test node has a proof") | ||||
self.restart_node(0, self.extra_args[0] + [ | self.restart_node( | ||||
f'-avaproof={proof.serialize().hex()}', | 0, | ||||
f'-avamasterkey={bytes_to_wif(privkey.get_bytes())}' | self.extra_args[0] | ||||
]) | + [ | ||||
f"-avaproof={proof.serialize().hex()}", | |||||
f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", | |||||
], | |||||
) | |||||
# Before local proof is validated | # Before local proof is validated | ||||
assert avalancheproofs_equals({ | assert avalancheproofs_equals( | ||||
{ | |||||
"valid": [], | "valid": [], | ||||
"conflicting": [], | "conflicting": [], | ||||
"immature": [], | "immature": [], | ||||
}) | } | ||||
) | |||||
# Add an inbound so the node proof can be registered and advertised | # Add an inbound so the node proof can be registered and advertised | ||||
node.add_p2p_connection(P2PInterface()) | node.add_p2p_connection(P2PInterface()) | ||||
# Mine a block to trigger proof validation | # Mine a block to trigger proof validation | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
self.wait_until( | self.wait_until( | ||||
lambda: avalancheproofs_equals({ | lambda: avalancheproofs_equals( | ||||
{ | |||||
"valid": [uint256_hex(proof.proofid)], | "valid": [uint256_hex(proof.proofid)], | ||||
"conflicting": [], | "conflicting": [], | ||||
"immature": [], | "immature": [], | ||||
}) | } | ||||
) | |||||
) | ) | ||||
self.log.info("Connect a bunch of peers and nodes") | self.log.info("Connect a bunch of peers and nodes") | ||||
mock_time = int(time.time()) | mock_time = int(time.time()) | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
privkeys = [] | privkeys = [] | ||||
proofs = [proof] | proofs = [proof] | ||||
conflicting_proofs = [] | conflicting_proofs = [] | ||||
quorum = [] | quorum = [] | ||||
N = 13 | N = 13 | ||||
for _ in range(N): | for _ in range(N): | ||||
_privkey, _proof = gen_proof(self, node) | _privkey, _proof = gen_proof(self, node) | ||||
proofs.append(_proof) | proofs.append(_proof) | ||||
privkeys.append(_privkey) | privkeys.append(_privkey) | ||||
# For each proof, also make a conflicting one | # For each proof, also make a conflicting one | ||||
stakes = create_coinbase_stakes( | stakes = create_coinbase_stakes( | ||||
node, [node.getbestblockhash()], node.get_deterministic_priv_key().key) | node, [node.getbestblockhash()], node.get_deterministic_priv_key().key | ||||
) | |||||
conflicting_proof_hex = node.buildavalancheproof( | conflicting_proof_hex = node.buildavalancheproof( | ||||
10, 0, bytes_to_wif(_privkey.get_bytes()), stakes) | 10, 0, bytes_to_wif(_privkey.get_bytes()), stakes | ||||
) | |||||
conflicting_proof = avalanche_proof_from_hex(conflicting_proof_hex) | conflicting_proof = avalanche_proof_from_hex(conflicting_proof_hex) | ||||
conflicting_proofs.append(conflicting_proof) | conflicting_proofs.append(conflicting_proof) | ||||
# Make the proof and its conflicting proof mature | # Make the proof and its conflicting proof mature | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
n = AvaP2PInterface() | n = AvaP2PInterface() | ||||
n.proof = _proof | n.proof = _proof | ||||
n.master_privkey = _privkey | n.master_privkey = _privkey | ||||
node.add_p2p_connection(n) | node.add_p2p_connection(n) | ||||
quorum.append(n) | quorum.append(n) | ||||
n.send_avaproof(_proof) | n.send_avaproof(_proof) | ||||
wait_for_proof(node, uint256_hex(_proof.proofid)) | wait_for_proof(node, uint256_hex(_proof.proofid)) | ||||
mock_time += self.conflicting_proof_cooldown | mock_time += self.conflicting_proof_cooldown | ||||
node.setmocktime(mock_time) | node.setmocktime(mock_time) | ||||
n.send_avaproof(conflicting_proof) | n.send_avaproof(conflicting_proof) | ||||
# Generate an immature proof | # Generate an immature proof | ||||
_, immature_proof = gen_proof(self, node) | _, immature_proof = gen_proof(self, node) | ||||
n.send_avaproof(immature_proof) | n.send_avaproof(immature_proof) | ||||
self.wait_until( | self.wait_until( | ||||
lambda: avalancheproofs_equals({ | lambda: avalancheproofs_equals( | ||||
{ | |||||
"valid": [uint256_hex(p.proofid) for p in proofs], | "valid": [uint256_hex(p.proofid) for p in proofs], | ||||
"conflicting": [uint256_hex(p.proofid) for p in conflicting_proofs], | "conflicting": [uint256_hex(p.proofid) for p in conflicting_proofs], | ||||
"immature": [uint256_hex(immature_proof.proofid)], | "immature": [uint256_hex(immature_proof.proofid)], | ||||
}) | } | ||||
) | |||||
) | ) | ||||
assert_equal(node.getavalancheinfo()['ready_to_poll'], True) | assert_equal(node.getavalancheinfo()["ready_to_poll"], True) | ||||
self.log.info("Finalize the proofs for some peers") | self.log.info("Finalize the proofs for some peers") | ||||
def vote_for_all_proofs(): | def vote_for_all_proofs(): | ||||
for i, n in enumerate(quorum): | for i, n in enumerate(quorum): | ||||
if not n.is_connected: | if not n.is_connected: | ||||
continue | continue | ||||
Show All 11 Lines | def run_test(self): | ||||
response = AvalancheProofVoteResponse.REJECTED | response = AvalancheProofVoteResponse.REJECTED | ||||
votes.append(AvalancheVote(response, inv.hash)) | votes.append(AvalancheVote(response, inv.hash)) | ||||
n.send_avaresponse(poll.round, votes, privkeys[i]) | n.send_avaresponse(poll.round, votes, privkeys[i]) | ||||
# Check if all proofs are finalized or invalidated | # Check if all proofs are finalized or invalidated | ||||
return all( | return all( | ||||
[node.getrawavalancheproof(uint256_hex(p.proofid)).get("finalized", False) for p in proofs] + | [ | ||||
[try_rpc(-8, "Proof not found", node.getrawavalancheproof, | node.getrawavalancheproof(uint256_hex(p.proofid)).get( | ||||
uint256_hex(c.proofid)) for c in conflicting_proofs] | "finalized", False | ||||
) | |||||
for p in proofs | |||||
] | |||||
+ [ | |||||
try_rpc( | |||||
-8, | |||||
"Proof not found", | |||||
node.getrawavalancheproof, | |||||
uint256_hex(c.proofid), | |||||
) | |||||
for c in conflicting_proofs | |||||
] | |||||
) | ) | ||||
# Vote until all the proofs have finalized (including ours) | # Vote until all the proofs have finalized (including ours) | ||||
self.wait_until(lambda: vote_for_all_proofs()) | self.wait_until(lambda: vote_for_all_proofs()) | ||||
self.wait_until( | self.wait_until( | ||||
lambda: avalancheproofs_equals({ | lambda: avalancheproofs_equals( | ||||
{ | |||||
"valid": [uint256_hex(p.proofid) for p in proofs], | "valid": [uint256_hex(p.proofid) for p in proofs], | ||||
"conflicting": [], | "conflicting": [], | ||||
"immature": [uint256_hex(immature_proof.proofid)], | "immature": [uint256_hex(immature_proof.proofid)], | ||||
}) | } | ||||
) | |||||
) | ) | ||||
# Make the immature proof mature | # Make the immature proof mature | ||||
self.generate(node, 1, sync_fun=self.no_op) | self.generate(node, 1, sync_fun=self.no_op) | ||||
proofs.append(immature_proof) | proofs.append(immature_proof) | ||||
self.wait_until( | self.wait_until( | ||||
lambda: avalancheproofs_equals({ | lambda: avalancheproofs_equals( | ||||
{ | |||||
"valid": [uint256_hex(p.proofid) for p in proofs], | "valid": [uint256_hex(p.proofid) for p in proofs], | ||||
"conflicting": [], | "conflicting": [], | ||||
"immature": [], | "immature": [], | ||||
}) | } | ||||
) | |||||
) | ) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
GetAvalancheProofsTest().main() | GetAvalancheProofsTest().main() |