Changeset View
Changeset View
Standalone View
Standalone View
test/functional/abc_p2p_avalanche_policy_minerfund.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2023 The Bitcoin developers | # Copyright (c) 2023 The Bitcoin developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test the resolution of miner fund changes via avalanche.""" | """Test the resolution of miner fund changes via avalanche.""" | ||||
import random | import random | ||||
from test_framework.avatools import get_ava_p2p_interface | from test_framework.avatools import can_find_inv_in_poll, get_ava_p2p_interface | ||||
from test_framework.blocktools import create_block, create_coinbase | from test_framework.blocktools import create_block, create_coinbase | ||||
from test_framework.cashaddr import decode | from test_framework.cashaddr import decode | ||||
from test_framework.messages import ( | from test_framework.messages import ( | ||||
XEC, | XEC, | ||||
AvalancheVote, | AvalancheVote, | ||||
AvalancheVoteError, | AvalancheVoteError, | ||||
CTxOut, | CTxOut, | ||||
ToHex, | ToHex, | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
WELLINGTON_ACTIVATION_TIME) | WELLINGTON_ACTIVATION_TIME) | ||||
# Get block reward | # Get block reward | ||||
coinbase = node.getblock(node.getbestblockhash(), 2)['tx'][0] | coinbase = node.getblock(node.getbestblockhash(), 2)['tx'][0] | ||||
block_reward = sum([vout['value'] for vout in coinbase['vout']]) | block_reward = sum([vout['value'] for vout in coinbase['vout']]) | ||||
policy_miner_fund_amount = int( | policy_miner_fund_amount = int( | ||||
block_reward * XEC * MINER_FUND_RATIO / 100) | block_reward * XEC * MINER_FUND_RATIO / 100) | ||||
def can_find_block_in_poll(hash, resp=AvalancheVoteError.ACCEPTED): | |||||
found_hash = False | |||||
for n in quorum: | |||||
poll = n.get_avapoll_if_available() | |||||
# That node has not received a poll | |||||
if poll is None: | |||||
continue | |||||
# We got a poll, check for the hash and repond | |||||
votes = [] | |||||
for inv in poll.invs: | |||||
# Vote yes to everything | |||||
r = AvalancheVoteError.ACCEPTED | |||||
# Look for what we expect | |||||
if inv.hash == hash: | |||||
r = resp | |||||
found_hash = True | |||||
votes.append(AvalancheVote(r, inv.hash)) | |||||
n.send_avaresponse(poll.round, votes, n.delegated_privkey) | |||||
return found_hash | |||||
def has_accepted_tip(tip_expected): | def has_accepted_tip(tip_expected): | ||||
hash_tip_final = int(tip_expected, 16) | hash_tip_final = int(tip_expected, 16) | ||||
can_find_block_in_poll(hash_tip_final) | can_find_inv_in_poll(quorum, hash_tip_final) | ||||
return node.getbestblockhash() == tip_expected | return node.getbestblockhash() == tip_expected | ||||
def has_finalized_tip(tip_expected): | def has_finalized_tip(tip_expected): | ||||
hash_tip_final = int(tip_expected, 16) | hash_tip_final = int(tip_expected, 16) | ||||
can_find_block_in_poll(hash_tip_final) | can_find_inv_in_poll(quorum, hash_tip_final) | ||||
return node.isfinalblock(tip_expected) | return node.isfinalblock(tip_expected) | ||||
def create_cb_pay_to_address(address, miner_fund_amount): | def create_cb_pay_to_address(address, miner_fund_amount): | ||||
# Build a coinbase with no miner fund | # Build a coinbase with no miner fund | ||||
cb = create_coinbase(node.getblockcount() + 1) | cb = create_coinbase(node.getblockcount() + 1) | ||||
# Keep only the block reward output | # Keep only the block reward output | ||||
cb.vout = cb.vout[:1] | cb.vout = cb.vout[:1] | ||||
# Change the block reward to account for the miner fund | # Change the block reward to account for the miner fund | ||||
▲ Show 20 Lines • Show All 76 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
self.log.info("Miner fund rejection test case") | self.log.info("Miner fund rejection test case") | ||||
reject = new_block( | reject = new_block( | ||||
tip, | tip, | ||||
OTHER_MINER_FUND_ADDR, | OTHER_MINER_FUND_ADDR, | ||||
policy_miner_fund_amount).hash | policy_miner_fund_amount).hash | ||||
reject_hash = int(reject, 16) | reject_hash = int(reject, 16) | ||||
with node.wait_for_debug_log( | with node.wait_for_debug_log( | ||||
[f"Avalanche invalidated block {reject}".encode()], | [f"Avalanche invalidated block {reject}".encode()], | ||||
chatty_callable=lambda: can_find_block_in_poll(reject_hash, AvalancheVoteError.PARKED)): | chatty_callable=lambda: can_find_inv_in_poll(quorum, reject_hash, AvalancheVoteError.PARKED)): | ||||
pass | pass | ||||
# Build a block on the accepted tip and the chain continues as normal | # Build a block on the accepted tip and the chain continues as normal | ||||
tip = new_block(tip, MINER_FUND_ADDR, policy_miner_fund_amount).hash | tip = new_block(tip, MINER_FUND_ADDR, policy_miner_fund_amount).hash | ||||
assert_equal(node.getbestblockhash(), tip) | assert_equal(node.getbestblockhash(), tip) | ||||
# Tip should finalize | # Tip should finalize | ||||
self.wait_until(lambda: has_finalized_tip(tip)) | self.wait_until(lambda: has_finalized_tip(tip)) | ||||
Show All 12 Lines |