Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_rpc_avalancheproof.py
Show First 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | def add_interface_node(test_node) -> str: | ||||
return test_node.getpeerinfo()[-1]['id'] | return test_node.getpeerinfo()[-1]['id'] | ||||
class LegacyAvalancheProofTest(BitcoinTestFramework): | class LegacyAvalancheProofTest(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 = [ | ||||
['-enableavalanche=1', "-avaproofstakeutxoconfirmations=1", '-avacooldown=0', '-legacyavaproof=1']] * self.num_nodes | ['-enableavalanche=1', '-avaproofstakeutxoconfirmations=1', '-avacooldown=0', '-legacyavaproof=1']] * self.num_nodes | ||||
self.supports_cli = False | self.supports_cli = False | ||||
self.rpc_timeout = 120 | self.rpc_timeout = 120 | ||||
def run_test(self): | def run_test(self): | ||||
# Turn off node 1 while node 0 mines blocks to generate stakes, | # Turn off node 1 while node 0 mines blocks to generate stakes, | ||||
# so that we can later try starting node 1 with an orphan proof. | # so that we can later try starting node 1 with an orphan proof. | ||||
self.stop_node(1) | self.stop_node(1) | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.wait_until(lambda: len(node.getavalanchepeerinfo()) == 1, | self.wait_until(lambda: len(node.getavalanchepeerinfo()) == 1, | ||||
timeout=5) | timeout=5) | ||||
# This case will occur for users building proofs with a third party | # This case will occur for users building proofs with a third party | ||||
# tool and then starting a new node that is not yet aware of the | # tool and then starting a new node that is not yet aware of the | ||||
# transactions used for stakes. | # transactions used for stakes. | ||||
self.log.info("Start a node with an orphan proof") | self.log.info("Start a node with an orphan proof") | ||||
self.start_node(1, self.extra_args[0] + [ | stake_age = node.getblockcount() + 2 | ||||
self.restart_node(1, self.extra_args[0] + [ | |||||
"-avaproofstakeutxoconfirmations={}".format(stake_age), | |||||
"-avaproof={}".format(proof), | "-avaproof={}".format(proof), | ||||
"-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", | "-avamasterkey=cND2ZvtabDbJ1gucx9GWH6XT9kgTAqfb6cotPt5Q5CyxVDhid2EN", | ||||
]) | ]) | ||||
# Mine a block to trigger an attempt at registering the proof | # Mine a block to trigger an attempt at registering the proof | ||||
self.connect_nodes(1, node.index) | |||||
self.sync_all() | |||||
self.nodes[1].generate(1) | self.nodes[1].generate(1) | ||||
wait_for_proof(self.nodes[1], proofid_hex, expect_orphan=True) | wait_for_proof(self.nodes[1], proofid_hex, expect_orphan=True) | ||||
self.log.info("Connect to an up-to-date node to unorphan the proof") | # Mine another block to make the orphan mature | ||||
self.connect_nodes(1, node.index) | self.nodes[1].generate(1) | ||||
self.sync_all() | wait_for_proof(self.nodes[0], proofid_hex, expect_orphan=False) | ||||
wait_for_proof(self.nodes[1], proofid_hex, expect_orphan=False) | |||||
self.log.info( | self.log.info( | ||||
"Generate delegations for the proof, verify and decode them") | "Generate delegations for the proof, verify and decode them") | ||||
# Stack up a few delegation levels | # Stack up a few delegation levels | ||||
def gen_privkey(): | def gen_privkey(): | ||||
pk = ECKey() | pk = ECKey() | ||||
pk.generate() | pk.generate() | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
if self.is_wallet_compiled(): | if self.is_wallet_compiled(): | ||||
self.log.info( | self.log.info( | ||||
"Check a proof with the maximum number of UTXO is valid") | "Check a proof with the maximum number of UTXO is valid") | ||||
new_blocks = node.generate(AVALANCHE_MAX_PROOF_STAKES // 10 + 1) | new_blocks = node.generate(AVALANCHE_MAX_PROOF_STAKES // 10 + 1) | ||||
# confirm the coinbase UTXOs | # confirm the coinbase UTXOs | ||||
node.generate(101) | node.generate(101) | ||||
too_many_stakes = create_stakes( | too_many_stakes = create_stakes( | ||||
node, new_blocks, AVALANCHE_MAX_PROOF_STAKES + 1) | node, new_blocks, AVALANCHE_MAX_PROOF_STAKES + 1) | ||||
maximum_stakes = too_many_stakes[:-1] | # Make the newly split UTXOs mature | ||||
node.generate(stake_age) | |||||
maximum_stakes = too_many_stakes[:-1] | |||||
good_proof = node.buildavalancheproof( | good_proof = node.buildavalancheproof( | ||||
proof_sequence, proof_expiration, | proof_sequence, proof_expiration, | ||||
wif_privkey, maximum_stakes) | wif_privkey, maximum_stakes) | ||||
too_many_utxos = node.buildavalancheproof( | too_many_utxos = node.buildavalancheproof( | ||||
proof_sequence, proof_expiration, | proof_sequence, proof_expiration, | ||||
wif_privkey, too_many_stakes) | wif_privkey, too_many_stakes) | ||||
Show All 19 Lines | def run_test(self): | ||||
check_rpc_failure(too_many_utxos, "too-many-utxos") | check_rpc_failure(too_many_utxos, "too-many-utxos") | ||||
conflicting_utxo = node.buildavalancheproof( | conflicting_utxo = node.buildavalancheproof( | ||||
proof_sequence + 1, proof_expiration, wif_privkey, stakes) | proof_sequence + 1, proof_expiration, wif_privkey, stakes) | ||||
assert_raises_rpc_error(-8, "The proof has conflicting utxo with an existing proof", | assert_raises_rpc_error(-8, "The proof has conflicting utxo with an existing proof", | ||||
node.sendavalancheproof, conflicting_utxo) | node.sendavalancheproof, conflicting_utxo) | ||||
# Clear the proof pool | # Clear the proof pool | ||||
self.restart_node(0) | stake_age = node.getblockcount() | ||||
self.restart_node(0, self.extra_args[0] + [ | |||||
"-avaproofstakeutxoconfirmations={}".format(stake_age), | |||||
]) | |||||
# Good proof | # Good proof | ||||
assert node.verifyavalancheproof(proof) | assert node.verifyavalancheproof(proof) | ||||
peer = node.add_p2p_connection(P2PInterface()) | peer = node.add_p2p_connection(P2PInterface()) | ||||
proofid = FromHex(LegacyAvalancheProof(), proof).proofid | proofid = FromHex(LegacyAvalancheProof(), proof).proofid | ||||
node.sendavalancheproof(proof) | node.sendavalancheproof(proof) | ||||
Show All 10 Lines | def run_test(self): | ||||
raw_proof = node.getrawavalancheproof("{:064x}".format(proofid)) | raw_proof = node.getrawavalancheproof("{:064x}".format(proofid)) | ||||
assert_equal(raw_proof['proof'], proof) | assert_equal(raw_proof['proof'], proof) | ||||
assert_equal(raw_proof['orphan'], False) | assert_equal(raw_proof['orphan'], False) | ||||
assert_equal(raw_proof['isBoundToPeer'], True) | assert_equal(raw_proof['isBoundToPeer'], True) | ||||
assert_raises_rpc_error(-8, "Proof not found", | assert_raises_rpc_error(-8, "Proof not found", | ||||
node.getrawavalancheproof, '0' * 64) | node.getrawavalancheproof, '0' * 64) | ||||
# Orphan the proof by sending the stake | # To orphan the proof, we make it immature by switching to a shorter | ||||
raw_tx = node.createrawtransaction( | # chain | ||||
[{"txid": stakes[-1]["txid"], "vout": 0}], | node.invalidateblock(node.getbestblockhash()) | ||||
{ADDRESS_ECREG_UNSPENDABLE: stakes[-1] | # Although the chaintip has changed, updatedBlockTip does not get | ||||
["amount"] - Decimal('10000')} | # called unless new chainwork needs evaluating, so invalidate another | ||||
) | # block and then mine a new one. | ||||
signed_tx = node.signrawtransactionwithkey(raw_tx, [addrkey0.key]) | node.invalidateblock(node.getbestblockhash()) | ||||
node.sendrawtransaction(signed_tx["hex"]) | node.setmocktime( | ||||
node.getblock( | |||||
node.getbestblockhash())['mediantime'] + | |||||
100) | |||||
node.generate(1) | node.generate(1) | ||||
self.wait_until(lambda: proofid not in get_proof_ids(node)) | |||||
raw_proof = node.getrawavalancheproof("{:064x}".format(proofid)) | raw_proof = node.getrawavalancheproof("{:064x}".format(proofid)) | ||||
assert_equal(raw_proof['proof'], proof) | assert_equal(raw_proof['proof'], proof) | ||||
assert_equal(raw_proof['orphan'], True) | assert_equal(raw_proof['orphan'], True) | ||||
assert_equal(raw_proof['isBoundToPeer'], False) | assert_equal(raw_proof['isBoundToPeer'], False) | ||||
self.log.info("Bad proof should be rejected at startup") | self.log.info("Bad proof should be rejected at startup") | ||||
▲ Show 20 Lines • Show All 129 Lines • Show Last 20 Lines |