clean up proposer slashing tests and add a couple
This commit is contained in:
parent
45ad270f76
commit
ee7d11d18f
|
@ -1,18 +1,49 @@
|
|||
from eth2spec.test.helpers.block_header import sign_block_header
|
||||
from eth2spec.test.helpers.keys import pubkey_to_privkey
|
||||
from eth2spec.test.helpers.state import get_balance
|
||||
|
||||
|
||||
def check_proposer_slashing_effect(spec, pre_state, state, slashed_index):
|
||||
slashed_validator = state.validators[slashed_index]
|
||||
assert slashed_validator.slashed
|
||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
|
||||
|
||||
proposer_index = spec.get_beacon_proposer_index(state)
|
||||
slash_penalty = state.validators[slashed_index].effective_balance // spec.MIN_SLASHING_PENALTY_QUOTIENT
|
||||
whistleblower_reward = state.validators[slashed_index].effective_balance // spec.WHISTLEBLOWER_REWARD_QUOTIENT
|
||||
if proposer_index != slashed_index:
|
||||
# slashed validator lost initial slash penalty
|
||||
assert (
|
||||
get_balance(state, slashed_index)
|
||||
== get_balance(pre_state, slashed_index) - slash_penalty
|
||||
)
|
||||
# block proposer gained whistleblower reward
|
||||
# >= becase proposer could have reported multiple
|
||||
assert (
|
||||
get_balance(state, proposer_index)
|
||||
>= get_balance(pre_state, proposer_index) + whistleblower_reward
|
||||
)
|
||||
else:
|
||||
# proposer reported themself so get penalty and reward
|
||||
# >= becase proposer could have reported multiple
|
||||
assert (
|
||||
get_balance(state, slashed_index)
|
||||
>= get_balance(pre_state, slashed_index) - slash_penalty + whistleblower_reward
|
||||
)
|
||||
|
||||
|
||||
def get_valid_proposer_slashing(spec, state, random_root=b'\x99' * 32,
|
||||
validator_index=None, signed_1=False, signed_2=False):
|
||||
if validator_index is None:
|
||||
slashed_index=None, signed_1=False, signed_2=False):
|
||||
if slashed_index is None:
|
||||
current_epoch = spec.get_current_epoch(state)
|
||||
validator_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
||||
privkey = pubkey_to_privkey[state.validators[validator_index].pubkey]
|
||||
slashed_index = spec.get_active_validator_indices(state, current_epoch)[-1]
|
||||
privkey = pubkey_to_privkey[state.validators[slashed_index].pubkey]
|
||||
slot = state.slot
|
||||
|
||||
header_1 = spec.BeaconBlockHeader(
|
||||
slot=slot,
|
||||
proposer_index=validator_index,
|
||||
proposer_index=slashed_index,
|
||||
parent_root=b'\x33' * 32,
|
||||
state_root=b'\x44' * 32,
|
||||
body_root=b'\x55' * 32,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
from eth2spec.test.context import spec_state_test, expect_assertion_error, always_bls, with_all_phases
|
||||
from eth2spec.test.helpers.block import build_empty_block_for_next_slot
|
||||
from eth2spec.test.helpers.block_header import sign_block_header
|
||||
from eth2spec.test.helpers.keys import privkeys
|
||||
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
|
||||
from eth2spec.test.helpers.state import get_balance, next_epoch
|
||||
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect
|
||||
from eth2spec.test.helpers.state import next_epoch
|
||||
|
||||
|
||||
def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True):
|
||||
|
@ -14,6 +15,8 @@ def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True)
|
|||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
|
||||
pre_state = state.copy()
|
||||
|
||||
yield 'pre', state
|
||||
yield 'proposer_slashing', proposer_slashing
|
||||
|
||||
|
@ -22,25 +25,31 @@ def run_proposer_slashing_processing(spec, state, proposer_slashing, valid=True)
|
|||
yield 'post', None
|
||||
return
|
||||
|
||||
proposer_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
pre_proposer_balance = get_balance(state, proposer_index)
|
||||
|
||||
spec.process_proposer_slashing(state, proposer_slashing)
|
||||
yield 'post', state
|
||||
|
||||
# check if slashed
|
||||
slashed_validator = state.validators[proposer_index]
|
||||
assert slashed_validator.slashed
|
||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
|
||||
|
||||
# lost whistleblower reward
|
||||
assert get_balance(state, proposer_index) < pre_proposer_balance
|
||||
slashed_proposer_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
check_proposer_slashing_effect(spec, pre_state, state, slashed_proposer_index)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_success(spec, state):
|
||||
# Get proposer for next slot
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
proposer_index = block.proposer_index
|
||||
|
||||
# Create slashing for same proposer
|
||||
proposer_slashing = get_valid_proposer_slashing(spec, state,
|
||||
slashed_index=proposer_index,
|
||||
signed_1=True, signed_2=True)
|
||||
|
||||
yield from run_proposer_slashing_processing(spec, state, proposer_slashing)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_success_slashed_and_proposer_index_the_same(spec, state):
|
||||
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||
|
||||
yield from run_proposer_slashing_processing(spec, state, proposer_slashing)
|
||||
|
|
|
@ -5,7 +5,7 @@ from eth2spec.test.helpers.block import build_empty_block_for_next_slot, build_e
|
|||
transition_unsigned_block
|
||||
from eth2spec.test.helpers.keys import privkeys, pubkeys
|
||||
from eth2spec.test.helpers.attester_slashings import get_valid_attester_slashing, get_indexed_attestation_participants
|
||||
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing
|
||||
from eth2spec.test.helpers.proposer_slashings import get_valid_proposer_slashing, check_proposer_slashing_effect
|
||||
from eth2spec.test.helpers.attestations import get_valid_attestation
|
||||
from eth2spec.test.helpers.deposits import prepare_state_and_deposit
|
||||
|
||||
|
@ -228,9 +228,9 @@ def test_proposer_slashing(spec, state):
|
|||
# copy for later balance lookups.
|
||||
pre_state = state.copy()
|
||||
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||
validator_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
|
||||
assert not state.validators[validator_index].slashed
|
||||
assert not state.validators[slashed_index].slashed
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
|
@ -245,21 +245,15 @@ def test_proposer_slashing(spec, state):
|
|||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
# check if slashed
|
||||
slashed_validator = state.validators[validator_index]
|
||||
assert slashed_validator.slashed
|
||||
assert slashed_validator.exit_epoch < spec.FAR_FUTURE_EPOCH
|
||||
assert slashed_validator.withdrawable_epoch < spec.FAR_FUTURE_EPOCH
|
||||
# lost whistleblower reward
|
||||
assert get_balance(state, validator_index) < get_balance(pre_state, validator_index)
|
||||
check_proposer_slashing_effect(spec, pre_state, state, slashed_index)
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_double_same_proposer_slashings_same_block(spec, state):
|
||||
proposer_slashing = get_valid_proposer_slashing(spec, state, signed_1=True, signed_2=True)
|
||||
validator_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
assert not state.validators[validator_index].slashed
|
||||
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
assert not state.validators[slashed_index].slashed
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
|
@ -274,16 +268,16 @@ def test_double_same_proposer_slashings_same_block(spec, state):
|
|||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_double_similar_proposer_slashings_same_block(spec, state):
|
||||
validator_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
|
||||
slashed_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[-1]
|
||||
|
||||
# Same validator, but different slashable offences in the same block
|
||||
proposer_slashing_1 = get_valid_proposer_slashing(spec, state, random_root=b'\xaa' * 32,
|
||||
validator_index=validator_index,
|
||||
slashed_index=slashed_index,
|
||||
signed_1=True, signed_2=True)
|
||||
proposer_slashing_2 = get_valid_proposer_slashing(spec, state, random_root=b'\xbb' * 32,
|
||||
validator_index=validator_index,
|
||||
slashed_index=slashed_index,
|
||||
signed_1=True, signed_2=True)
|
||||
assert not state.validators[validator_index].slashed
|
||||
assert not state.validators[slashed_index].slashed
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
|
@ -295,6 +289,40 @@ def test_double_similar_proposer_slashings_same_block(spec, state):
|
|||
yield 'post', None
|
||||
|
||||
|
||||
@with_all_phases
|
||||
@spec_state_test
|
||||
def test_multiple_different_proposer_slashings_same_block(spec, state):
|
||||
pre_state = state.copy()
|
||||
|
||||
num_slashings = 3
|
||||
proposer_slashings = []
|
||||
for i in range(num_slashings):
|
||||
slashed_index = spec.get_active_validator_indices(state, spec.get_current_epoch(state))[i]
|
||||
assert not state.validators[slashed_index].slashed
|
||||
|
||||
proposer_slashing = get_valid_proposer_slashing(spec, state,
|
||||
slashed_index=slashed_index,
|
||||
signed_1=True, signed_2=True)
|
||||
proposer_slashings.append(proposer_slashing)
|
||||
|
||||
yield 'pre', state
|
||||
|
||||
#
|
||||
# Add to state via block transition
|
||||
#
|
||||
block = build_empty_block_for_next_slot(spec, state)
|
||||
block.body.proposer_slashings = proposer_slashings
|
||||
|
||||
signed_block = state_transition_and_sign_block(spec, state, block)
|
||||
|
||||
yield 'blocks', [signed_block]
|
||||
yield 'post', state
|
||||
|
||||
for proposer_slashing in proposer_slashings:
|
||||
slashed_index = proposer_slashing.signed_header_1.message.proposer_index
|
||||
check_proposer_slashing_effect(spec, pre_state, state, slashed_index)
|
||||
|
||||
|
||||
def check_attester_slashing_effect(spec, pre_state, state, validator_index):
|
||||
slashed_validator = state.validators[validator_index]
|
||||
assert slashed_validator.slashed
|
||||
|
@ -335,7 +363,7 @@ def test_attester_slashing(spec, state):
|
|||
check_attester_slashing_effect(spec, pre_state, state, validator_index)
|
||||
|
||||
# TODO: currently mainnet limits attester-slashings per block to 1.
|
||||
# When this is increased, it should be tested to cover varrious combinations
|
||||
# When this is increased, it should be tested to cover various combinations
|
||||
# of duplicate slashings and overlaps of slashed attestations within the same block
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue