Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_rpc_getavalancheinfo.py
Show All 26 Lines | |||||
) | ) | ||||
from test_framework.wallet_util import bytes_to_wif | from test_framework.wallet_util import bytes_to_wif | ||||
class GetAvalancheInfoTest(BitcoinTestFramework): | class GetAvalancheInfoTest(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}', | [ | ||||
'-avacooldown=0', | f"-avalancheconflictingproofcooldown={self.conflicting_proof_cooldown}", | ||||
'-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, expiry=2000000000) | privkey, proof = gen_proof(self, node, expiry=2000000000) | ||||
def assert_avalancheinfo(expected): | def assert_avalancheinfo(expected): | ||||
assert_equal(node.getavalancheinfo(), expected) | assert_equal(node.getavalancheinfo(), expected) | ||||
coinbase_amount = Decimal('25000000.00') | coinbase_amount = Decimal("25000000.00") | ||||
self.log.info("The test node has no proof") | self.log.info("The test node has no proof") | ||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
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] | ||||
'-avaproofstakeutxoconfirmations=1', | + [ | ||||
]) | f"-avaproof={proof.serialize().hex()}", | ||||
f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", | |||||
"-avaproofstakeutxoconfirmations=1", | |||||
], | |||||
) | |||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": False, | "verified": False, | ||||
"verification_status": "pending", | "verification_status": "pending", | ||||
"sharing": False, | "sharing": False, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
# 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()) | ||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": False, | "verified": False, | ||||
"verification_status": "pending", | "verification_status": "pending", | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
# Make sure receiving our own proof from the network before validating | # Make sure receiving our own proof from the network before validating | ||||
# the local proof doesn't change our proof count. | # the local proof doesn't change our proof count. | ||||
sender = get_ava_p2p_interface_no_handshake(node) | sender = get_ava_p2p_interface_no_handshake(node) | ||||
sender.send_avaproof(proof) | sender.send_avaproof(proof) | ||||
# Make sure getting the proof via RPC doesn't change our proof count | # Make sure getting the proof via RPC doesn't change our proof count | ||||
# either. | # either. | ||||
node.sendavalancheproof(proof.serialize().hex()) | node.sendavalancheproof(proof.serialize().hex()) | ||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": False, | "verified": False, | ||||
"verification_status": "pending", | "verification_status": "pending", | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
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] | ||||
'-avaproofstakeutxoconfirmations=3', | + [ | ||||
]) | f"-avaproof={proof.serialize().hex()}", | ||||
f"-avamasterkey={bytes_to_wif(privkey.get_bytes())}", | |||||
"-avaproofstakeutxoconfirmations=3", | |||||
], | |||||
) | |||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": False, | "verified": False, | ||||
"verification_status": "pending", | "verification_status": "pending", | ||||
"sharing": False, | "sharing": False, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
# 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()) | ||||
self.log.info( | self.log.info("Mine a block to trigger proof validation, check it is immature") | ||||
"Mine a block to trigger proof validation, check it is immature") | |||||
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: node.getavalancheinfo() == { | lambda: node.getavalancheinfo() | ||||
== { | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": False, | "verified": False, | ||||
"verification_status": "immature-proof", | "verification_status": "immature-proof", | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 0, | "proof_count": 0, | ||||
"connected_proof_count": 0, | "connected_proof_count": 0, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 1, | "immature_proof_count": 1, | ||||
"total_stake_amount": Decimal('0.00'), | "total_stake_amount": Decimal("0.00"), | ||||
"connected_stake_amount": Decimal('0.00'), | "connected_stake_amount": Decimal("0.00"), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": coinbase_amount, | "immature_stake_amount": coinbase_amount, | ||||
"node_count": 0, | "node_count": 0, | ||||
"connected_node_count": 0, | "connected_node_count": 0, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
} | }, | ||||
} | } | ||||
) | ) | ||||
self.log.info("Mine another block to mature the local proof") | self.log.info("Mine another block to mature the local proof") | ||||
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: node.getavalancheinfo() == { | lambda: node.getavalancheinfo() | ||||
== { | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": True, | "verified": True, | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": 1, | "proof_count": 1, | ||||
"connected_proof_count": 1, | "connected_proof_count": 1, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": coinbase_amount, | "total_stake_amount": coinbase_amount, | ||||
"connected_stake_amount": coinbase_amount, | "connected_stake_amount": coinbase_amount, | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 1, | "node_count": 1, | ||||
"connected_node_count": 1, | "connected_node_count": 1, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
} | }, | ||||
} | } | ||||
) | ) | ||||
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, 2, sync_fun=self.no_op) | self.generate(node, 2, 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: node.getavalancheinfo() == { | lambda: node.getavalancheinfo() | ||||
== { | |||||
"ready_to_poll": True, | "ready_to_poll": True, | ||||
"local": { | "local": { | ||||
"verified": True, | "verified": True, | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": N + 1, | "proof_count": N + 1, | ||||
"connected_proof_count": N + 1, | "connected_proof_count": N + 1, | ||||
"dangling_proof_count": 0, | "dangling_proof_count": 0, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": N, | "conflicting_proof_count": N, | ||||
"immature_proof_count": 1, | "immature_proof_count": 1, | ||||
"total_stake_amount": coinbase_amount * (N + 1), | "total_stake_amount": coinbase_amount * (N + 1), | ||||
"connected_stake_amount": coinbase_amount * (N + 1), | "connected_stake_amount": coinbase_amount * (N + 1), | ||||
"dangling_stake_amount": Decimal('0.00'), | "dangling_stake_amount": Decimal("0.00"), | ||||
"immature_stake_amount": coinbase_amount, | "immature_stake_amount": coinbase_amount, | ||||
"node_count": N + 1, | "node_count": N + 1, | ||||
"connected_node_count": N + 1, | "connected_node_count": N + 1, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
} | }, | ||||
} | } | ||||
) | ) | ||||
self.log.info("Disconnect some nodes") | self.log.info("Disconnect some nodes") | ||||
D = 3 | D = 3 | ||||
for _ in range(D): | for _ in range(D): | ||||
n = node.p2ps.pop() | n = node.p2ps.pop() | ||||
n.peer_disconnect() | n.peer_disconnect() | ||||
n.wait_for_disconnect() | n.wait_for_disconnect() | ||||
self.wait_until( | self.wait_until( | ||||
lambda: node.getavalancheinfo() == { | lambda: node.getavalancheinfo() | ||||
== { | |||||
"ready_to_poll": True, | "ready_to_poll": True, | ||||
"local": { | "local": { | ||||
"verified": True, | "verified": True, | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": N + 1, | "proof_count": N + 1, | ||||
"connected_proof_count": N - D + 1, | "connected_proof_count": N - D + 1, | ||||
"dangling_proof_count": D, | "dangling_proof_count": D, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": N, | "conflicting_proof_count": N, | ||||
"immature_proof_count": 1, | "immature_proof_count": 1, | ||||
"total_stake_amount": coinbase_amount * (N + 1), | "total_stake_amount": coinbase_amount * (N + 1), | ||||
"connected_stake_amount": coinbase_amount * (N + 1 - D), | "connected_stake_amount": coinbase_amount * (N + 1 - D), | ||||
"dangling_stake_amount": coinbase_amount * D, | "dangling_stake_amount": coinbase_amount * D, | ||||
"immature_stake_amount": coinbase_amount, | "immature_stake_amount": coinbase_amount, | ||||
"node_count": N + 1 - D, | "node_count": N + 1 - D, | ||||
"connected_node_count": N + 1 - D, | "connected_node_count": N + 1 - D, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
} | }, | ||||
} | } | ||||
) | ) | ||||
self.log.info("Add some pending nodes") | self.log.info("Add some pending nodes") | ||||
P = 3 | P = 3 | ||||
for _ in range(P): | for _ in range(P): | ||||
dg_priv = ECKey() | dg_priv = ECKey() | ||||
dg_priv.generate() | dg_priv.generate() | ||||
dg_pub = dg_priv.get_pubkey().get_bytes().hex() | dg_pub = dg_priv.get_pubkey().get_bytes().hex() | ||||
_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) | ||||
delegation = node.delegateavalancheproof( | delegation = node.delegateavalancheproof( | ||||
uint256_hex(_proof.limited_proofid), | uint256_hex(_proof.limited_proofid), | ||||
bytes_to_wif(_privkey.get_bytes()), | bytes_to_wif(_privkey.get_bytes()), | ||||
dg_pub, | dg_pub, | ||||
None | None, | ||||
) | ) | ||||
# It would be much simpler to just use get_ava_p2p_interface here | # It would be much simpler to just use get_ava_p2p_interface here | ||||
# but the node would be able to download the proof, so the node | # but the node would be able to download the proof, so the node | ||||
# won't be pending. | # won't be pending. | ||||
n = get_ava_p2p_interface_no_handshake(node) | n = get_ava_p2p_interface_no_handshake(node) | ||||
n.send_avahello(delegation, dg_priv) | n.send_avahello(delegation, dg_priv) | ||||
# Make sure we completed at least one time the ProcessMessage or we | # Make sure we completed at least one time the ProcessMessage or we | ||||
# might miss the last pending node for the following assert | # might miss the last pending node for the following assert | ||||
n.sync_with_ping() | n.sync_with_ping() | ||||
# Immature became mature | # Immature became mature | ||||
proofs.append(immature_proof) | proofs.append(immature_proof) | ||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": True, | "ready_to_poll": True, | ||||
"local": { | "local": { | ||||
"verified": True, | "verified": True, | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": N + 2, | "proof_count": N + 2, | ||||
"connected_proof_count": N + 1 - D, | "connected_proof_count": N + 1 - D, | ||||
"dangling_proof_count": D + 1, | "dangling_proof_count": D + 1, | ||||
"finalized_proof_count": 0, | "finalized_proof_count": 0, | ||||
"conflicting_proof_count": N, | "conflicting_proof_count": N, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": coinbase_amount * (N + 2), | "total_stake_amount": coinbase_amount * (N + 2), | ||||
"connected_stake_amount": coinbase_amount * (N + 1 - D), | "connected_stake_amount": coinbase_amount * (N + 1 - D), | ||||
"dangling_stake_amount": coinbase_amount * (D + 1), | "dangling_stake_amount": coinbase_amount * (D + 1), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": N + 1 - D + P, | "node_count": N + 1 - D + P, | ||||
"connected_node_count": N + 1 - D, | "connected_node_count": N + 1 - D, | ||||
"pending_node_count": P, | "pending_node_count": P, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
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) | ||||
expected_logs = [] | expected_logs = [] | ||||
for p in proofs: | for p in proofs: | ||||
expected_logs.append( | expected_logs.append(f"Avalanche finalized proof {uint256_hex(p.proofid)}") | ||||
f"Avalanche finalized proof {uint256_hex(p.proofid)}") | |||||
with node.assert_debug_log(expected_logs): | with node.assert_debug_log(expected_logs): | ||||
self.wait_until(lambda: vote_for_all_proofs()) | self.wait_until(lambda: vote_for_all_proofs()) | ||||
self.log.info( | self.log.info( | ||||
"Disconnect all the nodes, so we are the only node left on the network") | "Disconnect all the nodes, so we are the only node left on the network" | ||||
) | |||||
node.disconnect_p2ps() | node.disconnect_p2ps() | ||||
assert_avalancheinfo({ | assert_avalancheinfo( | ||||
{ | |||||
"ready_to_poll": False, | "ready_to_poll": False, | ||||
"local": { | "local": { | ||||
"verified": True, | "verified": True, | ||||
"sharing": True, | "sharing": True, | ||||
"proofid": uint256_hex(proof.proofid), | "proofid": uint256_hex(proof.proofid), | ||||
"limited_proofid": uint256_hex(proof.limited_proofid), | "limited_proofid": uint256_hex(proof.limited_proofid), | ||||
"master": privkey.get_pubkey().get_bytes().hex(), | "master": privkey.get_pubkey().get_bytes().hex(), | ||||
"stake_amount": coinbase_amount, | "stake_amount": coinbase_amount, | ||||
"payout_address": ADDRESS_ECREG_UNSPENDABLE, | "payout_address": ADDRESS_ECREG_UNSPENDABLE, | ||||
}, | }, | ||||
"network": { | "network": { | ||||
"proof_count": N + 2, | "proof_count": N + 2, | ||||
"connected_proof_count": 1, | "connected_proof_count": 1, | ||||
"dangling_proof_count": N + 1, | "dangling_proof_count": N + 1, | ||||
"finalized_proof_count": N + 2, | "finalized_proof_count": N + 2, | ||||
"conflicting_proof_count": 0, | "conflicting_proof_count": 0, | ||||
"immature_proof_count": 0, | "immature_proof_count": 0, | ||||
"total_stake_amount": coinbase_amount * (N + 2), | "total_stake_amount": coinbase_amount * (N + 2), | ||||
"connected_stake_amount": coinbase_amount, | "connected_stake_amount": coinbase_amount, | ||||
"dangling_stake_amount": coinbase_amount * (N + 1), | "dangling_stake_amount": coinbase_amount * (N + 1), | ||||
"immature_stake_amount": Decimal('0.00'), | "immature_stake_amount": Decimal("0.00"), | ||||
"node_count": 1, | "node_count": 1, | ||||
"connected_node_count": 1, | "connected_node_count": 1, | ||||
"pending_node_count": 0, | "pending_node_count": 0, | ||||
}, | |||||
} | } | ||||
}) | ) | ||||
self.log.info( | self.log.info( | ||||
"Expire the local proof and check the verification status is now invalid") | "Expire the local proof and check the verification status is now invalid" | ||||
) | |||||
node.setmocktime(proof.expiration + 1) | node.setmocktime(proof.expiration + 1) | ||||
# Expiry is based on MTP, so we have to generate 6 blocks | # Expiry is based on MTP, so we have to generate 6 blocks | ||||
self.generate(node, 6, sync_fun=self.no_op) | self.generate(node, 6, sync_fun=self.no_op) | ||||
# Check the proof status is what we expect | # Check the proof status is what we expect | ||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-8, | -8, | ||||
"expired-proof", | "expired-proof", | ||||
node.verifyavalancheproof, | node.verifyavalancheproof, | ||||
proof.serialize().hex(), | proof.serialize().hex(), | ||||
) | ) | ||||
# We ignore the network status as cleanup might happen due to the big | # We ignore the network status as cleanup might happen due to the big | ||||
# mocked time jump. | # mocked time jump. | ||||
def local_status_invalid(): | def local_status_invalid(): | ||||
local_info = node.getavalancheinfo()["local"] | local_info = node.getavalancheinfo()["local"] | ||||
return local_info["verified"] is False and local_info["verification_status"] == "invalid-proof" | return ( | ||||
local_info["verified"] is False | |||||
and local_info["verification_status"] == "invalid-proof" | |||||
) | |||||
self.wait_until(local_status_invalid) | self.wait_until(local_status_invalid) | ||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
GetAvalancheInfoTest().main() | GetAvalancheInfoTest().main() |