From 3b744b5f16676bde3ef626e1b7f167c7bdeedf1c Mon Sep 17 00:00:00 2001 From: Jannik Luhn Date: Tue, 30 Apr 2019 09:54:29 +0200 Subject: [PATCH 1/2] add amounts option to create_deposits --- test_generators/operations/genesis.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test_generators/operations/genesis.py b/test_generators/operations/genesis.py index decb822f8e..ddee405588 100644 --- a/test_generators/operations/genesis.py +++ b/test_generators/operations/genesis.py @@ -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)) ] From 4ffa3f2b223f0ffdd4a433487de7cf2123c83758 Mon Sep 17 00:00:00 2001 From: Jannik Luhn Date: Tue, 30 Apr 2019 09:55:07 +0200 Subject: [PATCH 2/2] Add proposer slashing tests --- test_generators/operations/main.py | 5 +- .../operations/proposer_slashing.py | 219 ++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 test_generators/operations/proposer_slashing.py diff --git a/test_generators/operations/main.py b/test_generators/operations/main.py index 8b0a2a6d83..84cfd0eaba 100644 --- a/test_generators/operations/main.py +++ b/test_generators/operations/main.py @@ -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, ]) diff --git a/test_generators/operations/proposer_slashing.py b/test_generators/operations/proposer_slashing.py new file mode 100644 index 0000000000..5e2946feda --- /dev/null +++ b/test_generators/operations/proposer_slashing.py @@ -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()))