Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposer slashing tests #1010

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions test_generators/operations/genesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,21 @@ def create_genesis_state(deposits: List[spec.Deposit]) -> spec.BeaconState:
)


def create_deposits(pubkeys: List[spec.BLSPubkey], withdrawal_cred: List[spec.Bytes32]) -> List[spec.Deposit]:
def create_deposits(pubkeys: List[spec.BLSPubkey],
withdrawal_cred: List[spec.Bytes32],
amounts: List[int] = None) -> List[spec.Deposit]:

# Mock proof of possession
proof_of_possession = b'\x33' * 96

if amounts is None:
amounts = [spec.MAX_EFFECTIVE_BALANCE for _ in range(len(pubkeys))]

deposit_data = [
spec.DepositData(
pubkey=pubkeys[i],
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + withdrawal_cred[i][1:],
amount=spec.MAX_DEPOSIT_AMOUNT,
amount=amounts[i],
proof_of_possession=proof_of_possession,
) for i in range(len(pubkeys))
]
Expand Down
5 changes: 4 additions & 1 deletion test_generators/operations/main.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
from gen_base import gen_runner

from deposits import mini_deposits_suite, full_deposits_suite
from proposer_slashing import mini_proposer_slashing_suite, full_proposer_slashing_suite

if __name__ == "__main__":
gen_runner.run_generator("operations", [
mini_deposits_suite,
full_deposits_suite
full_deposits_suite,
mini_proposer_slashing_suite,
full_proposer_slashing_suite,
])
219 changes: 219 additions & 0 deletions test_generators/operations/proposer_slashing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
from eth_utils import (
to_dict,
to_tuple,
)

from eth2spec.phase0.spec import (
BeaconBlockHeader,
BeaconState,
ProposerSlashing,
apply_constants_preset,
get_epoch_start_slot,
process_proposer_slashing,
MIN_DEPOSIT_AMOUNT,
MAX_EFFECTIVE_BALANCE,
)
from eth2spec.debug.encode import encode

from gen_base import (
gen_suite,
gen_typing,
)

from preset_loader import loader

import keys
import genesis


NUM_VALIDATORS = 100


@to_dict
def valid():
yield 'description', 'valid proposer slashing'

deposits = genesis.create_deposits(
keys.pubkeys[:NUM_VALIDATORS],
keys.withdrawal_creds[:NUM_VALIDATORS],
)
state = genesis.create_genesis_state(deposits)
yield 'pre', encode(state, BeaconState)

header_1 = BeaconBlockHeader(state_root=b"\x00" * 32)
header_2 = BeaconBlockHeader(state_root=b"\x11" * 32)
proposer_slashing = ProposerSlashing(
proposer_index=3,
header_1=header_1,
header_2=header_2,
)
yield 'proposer_slashing', encode(proposer_slashing, ProposerSlashing)

process_proposer_slashing(state, proposer_slashing)
yield 'post', encode(state, BeaconState)


@to_dict
def invalid_wrong_index():
yield 'description', 'slashing validator with index out of bounds'

deposits = genesis.create_deposits(
keys.pubkeys[:NUM_VALIDATORS],
keys.withdrawal_creds[:NUM_VALIDATORS],
)
state = genesis.create_genesis_state(deposits)
yield 'pre', encode(state, BeaconState)

header_1 = BeaconBlockHeader(state_root=b"\x00" * 32)
header_2 = BeaconBlockHeader(state_root=b"\x11" * 32)
proposer_slashing = ProposerSlashing(
proposer_index=NUM_VALIDATORS,
header_1=header_1,
header_2=header_2,
)
yield 'proposer_slashing', encode(proposer_slashing, ProposerSlashing)

try:
process_proposer_slashing(state, proposer_slashing)
except IndexError:
pass
else:
assert False
yield 'post', None


@to_dict
def invalid_different_epoch():
yield 'description', 'slashing validator for headers from two different epochs'
deposits = genesis.create_deposits(
keys.pubkeys[:NUM_VALIDATORS],
keys.withdrawal_creds[:NUM_VALIDATORS],
)
state = genesis.create_genesis_state(deposits)
yield 'pre', encode(state, BeaconState)

header_1 = BeaconBlockHeader(
state_root=b"\x00" * 32,
slot=get_epoch_start_slot(0),
)
header_2 = BeaconBlockHeader(
state_root=b"\x11" * 32,
slot=get_epoch_start_slot(1),
)
proposer_slashing = ProposerSlashing(
proposer_index=3,
header_1=header_1,
header_2=header_2,
)
yield 'proposer_slashing', encode(proposer_slashing, ProposerSlashing)

try:
process_proposer_slashing(state, proposer_slashing)
except AssertionError:
pass
else:
assert False
yield 'post', None


@to_dict
def invalid_same_headers():
yield 'description', 'slashing validator with only one header'

deposits = genesis.create_deposits(
keys.pubkeys[:NUM_VALIDATORS],
keys.withdrawal_creds[:NUM_VALIDATORS],
)
state = genesis.create_genesis_state(deposits)
yield 'pre', encode(state, BeaconState)

header_1 = BeaconBlockHeader(
state_root=b"\x00" * 32,
)
proposer_slashing = ProposerSlashing(
proposer_index=3,
header_1=header_1,
header_2=header_1,
)
yield 'proposer_slashing', encode(proposer_slashing, ProposerSlashing)

try:
process_proposer_slashing(state, proposer_slashing)
except AssertionError:
pass
else:
assert False
yield 'post', None


@to_dict
def invalid_not_active():
yield 'description', 'slashing validator who is not active yet'

deposits = genesis.create_deposits(
keys.pubkeys[:NUM_VALIDATORS],
keys.withdrawal_creds[:NUM_VALIDATORS],
amounts=[MIN_DEPOSIT_AMOUNT] + [MAX_EFFECTIVE_BALANCE] * (NUM_VALIDATORS - 1)
)
state = genesis.create_genesis_state(deposits)
yield 'pre', encode(state, BeaconState)

header_1 = BeaconBlockHeader(
state_root=b"\x00" * 32,
)
header_2 = BeaconBlockHeader(
state_root=b"\x11" * 32,
)
proposer_slashing = ProposerSlashing(
proposer_index=0,
header_1=header_1,
header_2=header_2,
)
yield 'proposer_slashing', encode(proposer_slashing, ProposerSlashing)

try:
process_proposer_slashing(state, proposer_slashing)
except AssertionError:
pass
else:
assert False
yield 'post', None


@to_tuple
def proposer_slashing_cases():
yield valid()
yield invalid_wrong_index()
yield invalid_different_epoch()
yield invalid_same_headers()
yield invalid_not_active()


def mini_proposer_slashing_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'minimal')
apply_constants_preset(presets)

return ("proposer_slashing_minimal", "proposer_slashing", gen_suite.render_suite(
title="proposer slashing operation",
summary="Test suite for proposer slashing operation processing",
forks_timeline="testing",
forks=["phase0"],
config="minimal",
runner="operations",
handler="proposer_slashing",
test_cases=proposer_slashing_cases()))


def full_proposer_slashing_suite(configs_path: str) -> gen_typing.TestSuiteOutput:
presets = loader.load_presets(configs_path, 'mainnet')
apply_constants_preset(presets)

return ("proposer_slashing_full", "proposer_slashing", gen_suite.render_suite(
title="proposer slashing operation",
summary="Test suite for proposer slashing operation processing",
forks_timeline="mainnet",
forks=["phase0"],
config="mainnet",
runner="operations",
handler="proposer_slashing",
test_cases=proposer_slashing_cases()))