add tests for proposer slashing
This commit is contained in:
parent
64e3db09d4
commit
e313c5ba5a
|
@ -0,0 +1,97 @@
|
|||
from copy import deepcopy
|
||||
import pytest
|
||||
|
||||
import build.phase0.spec as spec
|
||||
from build.phase0.spec import (
|
||||
get_balance,
|
||||
get_current_epoch,
|
||||
process_proposer_slashing,
|
||||
)
|
||||
from tests.phase0.helpers import (
|
||||
get_valid_proposer_slashing,
|
||||
)
|
||||
|
||||
# mark entire file as 'header'
|
||||
pytestmark = pytest.mark.proposer_slashings
|
||||
|
||||
|
||||
def run_proposer_slashing_processing(state, proposer_slashing, valid=True):
|
||||
"""
|
||||
Run ``process_proposer_slashing`` returning the pre and post state.
|
||||
If ``valid == False``, run expecting ``AssertionError``
|
||||
"""
|
||||
post_state = deepcopy(state)
|
||||
|
||||
if not valid:
|
||||
with pytest.raises(AssertionError):
|
||||
process_proposer_slashing(post_state, proposer_slashing)
|
||||
return state, None
|
||||
|
||||
process_proposer_slashing(post_state, proposer_slashing)
|
||||
|
||||
slashed_validator = post_state.validator_registry[proposer_slashing.proposer_index]
|
||||
assert not slashed_validator.initiated_exit
|
||||
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(post_state, proposer_slashing.proposer_index) <
|
||||
get_balance(state, proposer_slashing.proposer_index)
|
||||
)
|
||||
|
||||
return state, post_state
|
||||
|
||||
|
||||
def test_success(state):
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
||||
pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing)
|
||||
|
||||
return pre_state, proposer_slashing, post_state
|
||||
|
||||
|
||||
def test_epochs_are_different(state):
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
||||
# set slots to be in different epochs
|
||||
proposer_slashing.header_2.slot += spec.SLOTS_PER_EPOCH
|
||||
|
||||
pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False)
|
||||
|
||||
return pre_state, proposer_slashing, post_state
|
||||
|
||||
|
||||
def test_headers_are_same(state):
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
||||
# set headers to be the same
|
||||
proposer_slashing.header_2 = proposer_slashing.header_1
|
||||
|
||||
pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False)
|
||||
|
||||
return pre_state, proposer_slashing, post_state
|
||||
|
||||
|
||||
def test_proposer_is_slashed(state):
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
||||
# set proposer to slashed
|
||||
state.validator_registry[proposer_slashing.proposer_index].slashed = True
|
||||
|
||||
pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False)
|
||||
|
||||
return pre_state, proposer_slashing, post_state
|
||||
|
||||
|
||||
def test_proposer_is_withdrawn(state):
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
|
||||
# set proposer withdrawable_epoch in past
|
||||
current_epoch = get_current_epoch(state)
|
||||
proposer_index = proposer_slashing.proposer_index
|
||||
state.validator_registry[proposer_index].withdrawable_epoch = current_epoch - 1
|
||||
|
||||
pre_state, post_state = run_proposer_slashing_processing(state, proposer_slashing, False)
|
||||
|
||||
return pre_state, proposer_slashing, post_state
|
|
@ -7,14 +7,18 @@ from build.phase0.utils.minimal_ssz import signed_root
|
|||
from build.phase0.spec import (
|
||||
# constants
|
||||
EMPTY_SIGNATURE,
|
||||
ZERO_HASH,
|
||||
# SSZ
|
||||
AttestationData,
|
||||
BeaconBlockHeader,
|
||||
Deposit,
|
||||
DepositInput,
|
||||
DepositData,
|
||||
Eth1Data,
|
||||
ProposerSlashing,
|
||||
VoluntaryExit,
|
||||
# functions
|
||||
get_active_validator_indices,
|
||||
get_block_root,
|
||||
get_current_epoch,
|
||||
get_domain,
|
||||
|
@ -199,3 +203,43 @@ def build_deposit(state,
|
|||
)
|
||||
|
||||
return deposit, root, deposit_data_leaves
|
||||
|
||||
|
||||
def get_valid_proposer_slashing(state):
|
||||
current_epoch = get_current_epoch(state)
|
||||
validator_index = get_active_validator_indices(state.validator_registry, current_epoch)[-1]
|
||||
privkey = pubkey_to_privkey[state.validator_registry[validator_index].pubkey]
|
||||
slot = state.slot
|
||||
|
||||
header_1 = BeaconBlockHeader(
|
||||
slot=slot,
|
||||
previous_block_root=ZERO_HASH,
|
||||
state_root=ZERO_HASH,
|
||||
block_body_root=ZERO_HASH,
|
||||
signature=EMPTY_SIGNATURE,
|
||||
)
|
||||
header_2 = deepcopy(header_1)
|
||||
header_2.previous_block_root = b'\x02' * 32
|
||||
header_2.slot = slot + 1
|
||||
|
||||
domain = get_domain(
|
||||
fork=state.fork,
|
||||
epoch=get_current_epoch(state),
|
||||
domain_type=spec.DOMAIN_BEACON_BLOCK,
|
||||
)
|
||||
header_1.signature = bls.sign(
|
||||
message_hash=signed_root(header_1),
|
||||
privkey=privkey,
|
||||
domain=domain,
|
||||
)
|
||||
header_2.signature = bls.sign(
|
||||
message_hash=signed_root(header_2),
|
||||
privkey=privkey,
|
||||
domain=domain,
|
||||
)
|
||||
|
||||
return ProposerSlashing(
|
||||
proposer_index=validator_index,
|
||||
header_1=header_1,
|
||||
header_2=header_2,
|
||||
)
|
||||
|
|
|
@ -46,6 +46,7 @@ from tests.phase0.helpers import (
|
|||
build_deposit_data,
|
||||
build_empty_block_for_next_slot,
|
||||
force_registry_change_at_next_epoch,
|
||||
get_valid_proposer_slashing,
|
||||
)
|
||||
|
||||
|
||||
|
@ -117,42 +118,8 @@ def test_empty_epoch_transition_not_finalizing(state):
|
|||
|
||||
def test_proposer_slashing(state, pubkeys, privkeys):
|
||||
test_state = deepcopy(state)
|
||||
current_epoch = get_current_epoch(test_state)
|
||||
validator_index = get_active_validator_indices(test_state.validator_registry, current_epoch)[-1]
|
||||
privkey = privkeys[validator_index]
|
||||
slot = spec.GENESIS_SLOT
|
||||
header_1 = BeaconBlockHeader(
|
||||
slot=slot,
|
||||
previous_block_root=ZERO_HASH,
|
||||
state_root=ZERO_HASH,
|
||||
block_body_root=ZERO_HASH,
|
||||
signature=EMPTY_SIGNATURE,
|
||||
)
|
||||
header_2 = deepcopy(header_1)
|
||||
header_2.previous_block_root = b'\x02' * 32
|
||||
header_2.slot = slot + 1
|
||||
|
||||
domain = get_domain(
|
||||
fork=test_state.fork,
|
||||
epoch=get_current_epoch(test_state),
|
||||
domain_type=spec.DOMAIN_BEACON_BLOCK,
|
||||
)
|
||||
header_1.signature = bls.sign(
|
||||
message_hash=signed_root(header_1),
|
||||
privkey=privkey,
|
||||
domain=domain,
|
||||
)
|
||||
header_2.signature = bls.sign(
|
||||
message_hash=signed_root(header_2),
|
||||
privkey=privkey,
|
||||
domain=domain,
|
||||
)
|
||||
|
||||
proposer_slashing = ProposerSlashing(
|
||||
proposer_index=validator_index,
|
||||
header_1=header_1,
|
||||
header_2=header_2,
|
||||
)
|
||||
proposer_slashing = get_valid_proposer_slashing(state)
|
||||
validator_index = proposer_slashing.proposer_index
|
||||
|
||||
#
|
||||
# Add to state via block transition
|
||||
|
|
Loading…
Reference in New Issue