def test_update_validator(sample_beacon_state_params, sample_validator_record_params, max_deposit): state = BeaconState(**sample_beacon_state_params).copy( validator_registry=[ mock_validator_record( pubkey, ) for pubkey in range(10) ], validator_balances=( max_deposit for _ in range(10) ) ) new_pubkey = 100 validator_index = 5 balance = 5566 validator = state.validator_registry[validator_index].copy( pubkey=new_pubkey, ) result_state = state.update_validator( validator_index=validator_index, validator=validator, balance=balance, ) assert result_state.validator_balances[validator_index] == balance assert result_state.validator_registry[validator_index].pubkey == new_pubkey assert state.validator_registry[validator_index].pubkey != new_pubkey
def test_verify_slashable_vote_data_signature( num_validators, privkeys, sample_beacon_state_params, activated_genesis_validators, genesis_balances, sample_slashable_vote_data_params, sample_fork_data_params): state = BeaconState(**sample_beacon_state_params).copy( validator_registry=activated_genesis_validators, validator_balances=genesis_balances, fork_data=ForkData(**sample_fork_data_params), ) # NOTE: we can do this before "correcting" the params as they # touch disjoint subsets of the provided params messages = _create_slashable_vote_data_messages( sample_slashable_vote_data_params) valid_params = _correct_slashable_vote_data_params( num_validators, sample_slashable_vote_data_params, messages, privkeys, state.fork_data, ) valid_votes = SlashableVoteData(**valid_params) assert verify_slashable_vote_data_signature(state, valid_votes) invalid_params = _corrupt_signature(valid_params, state.fork_data) invalid_votes = SlashableVoteData(**invalid_params) assert not verify_slashable_vote_data_signature(state, invalid_votes)
def test_verify_slashable_vote_data( num_validators, param_mapper, should_succeed, needs_fork_data, privkeys, sample_beacon_state_params, activated_genesis_validators, genesis_balances, sample_slashable_vote_data_params, sample_fork_data_params, max_casper_votes): state = BeaconState(**sample_beacon_state_params).copy( validator_registry=activated_genesis_validators, validator_balances=genesis_balances, fork_data=ForkData(**sample_fork_data_params), ) # NOTE: we can do this before "correcting" the params as they # touch disjoint subsets of the provided params messages = _create_slashable_vote_data_messages( sample_slashable_vote_data_params) params = _correct_slashable_vote_data_params( num_validators, sample_slashable_vote_data_params, messages, privkeys, state.fork_data, ) if needs_fork_data: params = param_mapper(params, state.fork_data) else: params = param_mapper(params) _run_verify_slashable_vote(params, state, max_casper_votes, should_succeed)
def test_add_pending_validator(monkeypatch, sample_beacon_state_params, sample_validator_record_params, validator_registry_len, min_empty_validator_index_result, expected_index): from eth.beacon import deposit_helpers def mock_get_min_empty_validator_index(validators, validator_balances, current_slot, zero_balance_validator_ttl): if min_empty_validator_index_result is None: raise MinEmptyValidatorIndexNotFound() else: return min_empty_validator_index_result monkeypatch.setattr(deposit_helpers, 'get_min_empty_validator_index', mock_get_min_empty_validator_index) state = BeaconState(**sample_beacon_state_params).copy( validator_registry=[ ValidatorRecord(**sample_validator_record_params) for _ in range(validator_registry_len) ], validator_balances=[100 for _ in range(validator_registry_len)], ) validator = ValidatorRecord(**sample_validator_record_params) deposit = 5566 state, index = add_pending_validator( state, validator, deposit, zero_balance_validator_ttl=0, # it's for `get_min_empty_validator_index` ) assert index == expected_index assert state.validator_registry[index] == validator
def empty_beacon_state(): return BeaconState( slot=0, genesis_time=0, fork_data=ForkData( pre_fork_version=0, post_fork_version=0, fork_slot=0, ), validator_registry=(), validator_registry_latest_change_slot=10, validator_registry_exit_count=10, validator_registry_delta_chain_tip=b'\x55' * 32, latest_randao_mixes=(), latest_vdf_outputs=(), shard_committees_at_slots=(), persistent_committees=(), persistent_committee_reassignments=(), previous_justified_slot=0, justified_slot=0, justification_bitfield=0, finalized_slot=0, latest_crosslinks=(), latest_block_roots=(), latest_penalized_exit_balances=(), latest_attestations=(), batched_block_roots=(), processed_pow_receipt_root=b'\x55' * 32, candidate_pow_receipt_roots=(), )
def test_demo(base_db, sample_beacon_block_params, sample_beacon_state_params, fixture_sm_class): chaindb = BeaconChainDB(base_db) block = BaseBeaconBlock(**sample_beacon_block_params) state = BeaconState(**sample_beacon_state_params) sm = fixture_sm_class(chaindb, block, state) result_state, result_block = sm.import_block(block) assert state.slot == 0 assert result_state.slot == sm.config.ZERO_BALANCE_VALIDATOR_TTL
def test_validate_proposer_signature( proposer_privkey, proposer_pubkey, is_valid_signature, sample_beacon_block_params, sample_beacon_state_params, sample_shard_committee_params, beacon_chain_shard_number, epoch_length): state = BeaconState(**sample_beacon_state_params).copy( validator_registry=[ mock_validator_record(proposer_pubkey) for _ in range(10) ], shard_committees_at_slots=get_sample_shard_committees_at_slots( num_slot=128, num_shard_committee_per_slot=10, sample_shard_committee_params=sample_shard_committee_params, ), ) default_block = BaseBeaconBlock(**sample_beacon_block_params) empty_signature_block_root = default_block.block_without_signature_root proposal_root = ProposalSignedData( state.slot, beacon_chain_shard_number, empty_signature_block_root, ).root proposed_block = BaseBeaconBlock(**sample_beacon_block_params).copy( signature=bls.sign( message=proposal_root, privkey=proposer_privkey, domain=SignatureDomain.DOMAIN_PROPOSAL, ), ) if is_valid_signature: validate_proposer_signature( state, proposed_block, beacon_chain_shard_number, epoch_length, ) else: with pytest.raises(ValidationError): validate_proposer_signature( state, proposed_block, beacon_chain_shard_number, epoch_length, )
def test_update_validator(sample_beacon_state_params, sample_validator_record_params, max_deposit): state = BeaconState(**sample_beacon_state_params).copy(validator_registry=[ mock_validator_record( pubkey, max_deposit, ) for pubkey in range(10) ]) new_pubkey = 100 validator_index = 5 validator = state.validator_registry[validator_index].copy( pubkey=new_pubkey, ) result_state = state.update_validator(validator_index=validator_index, validator=validator) assert result_state.validator_registry[ validator_index].pubkey == new_pubkey assert state.validator_registry[validator_index].pubkey != new_pubkey
def test_validate_proof_of_possession(sample_beacon_state_params, pubkeys, privkeys, expected): state = BeaconState(**sample_beacon_state_params) privkey = privkeys[0] pubkey = pubkeys[0] withdrawal_credentials = b'\x34' * 32 custody_commitment = b'\x12' * 32 randao_commitment = b'\x56' * 32 domain = get_domain( state.fork_data, state.slot, SignatureDomain.DOMAIN_DEPOSIT, ) deposit_input = make_deposit_input( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) if expected is True: proof_of_possession = sign_proof_of_possession(deposit_input, privkey, domain) validate_proof_of_possession( state=state, pubkey=pubkey, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) else: proof_of_possession = b'\x11' * 32 with pytest.raises(ValidationError): validate_proof_of_possession( state=state, pubkey=pubkey, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, )
def test_add_pending_validator(sample_beacon_state_params, sample_validator_record_params): validator_registry_len = 2 state = BeaconState(**sample_beacon_state_params).copy( validator_registry=[ ValidatorRecord(**sample_validator_record_params) for _ in range(validator_registry_len) ], validator_balances=(100, ) * validator_registry_len, ) validator = ValidatorRecord(**sample_validator_record_params) amount = 5566 state = add_pending_validator( state, validator, amount, ) assert state.validator_registry[-1] == validator
def test_verify_slashable_vote_data(param_mapper, should_succeed, privkeys, sample_beacon_state_params, genesis_validators, sample_slashable_vote_data_params, max_casper_votes): sample_beacon_state_params["validator_registry"] = genesis_validators state = BeaconState(**sample_beacon_state_params) # NOTE: we can do this before "correcting" the params as they # touch disjoint subsets of the provided params messages = _create_slashable_vote_data_messages( sample_slashable_vote_data_params) params = _correct_slashable_vote_data_params( sample_slashable_vote_data_params, genesis_validators, messages, privkeys, ) params = param_mapper(params) _run_verify_slashable_vote(params, state, max_casper_votes, should_succeed)
def genesis_state(sample_beacon_state_params, genesis_validators, epoch_length, target_committee_size, initial_slot_number, shard_count, latest_block_roots_length): initial_shuffling = get_new_shuffling( seed=ZERO_HASH32, validators=genesis_validators, crosslinking_start_shard=0, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count) return BeaconState(**sample_beacon_state_params).copy( validator_registry=genesis_validators, shard_committees_at_slots=initial_shuffling + initial_shuffling, latest_block_roots=tuple(ZERO_HASH32 for _ in range(latest_block_roots_length)), latest_crosslinks=tuple( CrosslinkRecord( slot=initial_slot_number, shard_block_root=ZERO_HASH32, ) for _ in range(shard_count)))
def test_verify_slashable_vote_data_signature( privkeys, sample_beacon_state_params, genesis_validators, sample_slashable_vote_data_params): sample_beacon_state_params["validator_registry"] = genesis_validators state = BeaconState(**sample_beacon_state_params) # NOTE: we can do this before "correcting" the params as they # touch disjoint subsets of the provided params messages = _create_slashable_vote_data_messages( sample_slashable_vote_data_params) valid_params = _correct_slashable_vote_data_params( sample_slashable_vote_data_params, genesis_validators, messages, privkeys, ) valid_votes = SlashableVoteData(**valid_params) assert verify_slashable_vote_data_signature(state, valid_votes) invalid_params = _corrupt_signature(valid_params) invalid_votes = SlashableVoteData(**invalid_params) assert not verify_slashable_vote_data_signature(state, invalid_votes)
def test_validator_registry_and_balances_length(sample_beacon_state_params): # When len(BeaconState.validator_registry) != len(BeaconState.validtor_balances) with pytest.raises(ValueError): BeaconState(**sample_beacon_state_params).copy( validator_registry=tuple( mock_validator_record(pubkey) for pubkey in range(10)), )
def test_hash(sample_beacon_state_params): state = BeaconState(**sample_beacon_state_params) assert state.hash == blake(rlp.encode(state))
def test_process_deposit(sample_beacon_state_params, zero_balance_validator_ttl, privkeys, pubkeys): state = BeaconState(**sample_beacon_state_params).copy( slot=zero_balance_validator_ttl + 1, validator_registry=(), ) privkey_1 = privkeys[0] pubkey_1 = pubkeys[0] deposit = 32 * denoms.gwei withdrawal_credentials = b'\x34' * 32 custody_commitment = b'\x11' * 32 randao_commitment = b'\x56' * 32 domain = get_domain( state.fork_data, state.slot, SignatureDomain.DOMAIN_DEPOSIT, ) deposit_input = make_deposit_input( pubkey=pubkey_1, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) proof_of_possession = sign_proof_of_possession(deposit_input, privkey_1, domain) # Add the first validator result_state, index = process_deposit( state=state, pubkey=pubkey_1, deposit=deposit, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, zero_balance_validator_ttl=zero_balance_validator_ttl, ) assert len(result_state.validator_registry) == 1 index = 0 assert result_state.validator_registry[0].pubkey == pubkey_1 assert result_state.validator_registry[ index].withdrawal_credentials == withdrawal_credentials assert result_state.validator_registry[ index].randao_commitment == randao_commitment assert result_state.validator_balances[index] == deposit # test immutable assert len(state.validator_registry) == 0 # Add the second validator privkey_2 = privkeys[1] pubkey_2 = pubkeys[1] deposit_input = make_deposit_input( pubkey=pubkey_2, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) proof_of_possession = sign_proof_of_possession(deposit_input, privkey_2, domain) result_state, index = process_deposit( state=result_state, pubkey=pubkey_2, deposit=deposit, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, zero_balance_validator_ttl=zero_balance_validator_ttl, ) assert len(result_state.validator_registry) == 2 assert result_state.validator_registry[1].pubkey == pubkey_2 # Force the first validator exited -> a empty slot in state.validator_registry. result_state = result_state.copy(validator_registry=( result_state.validator_registry[0].copy(latest_status_change_slot=0, ), result_state.validator_registry[1], ), validator_balances=(0, ) + result_state.validator_balances[1:]) # Add the third validator. # Should overwrite previously exited validator. privkey_3 = privkeys[2] pubkey_3 = pubkeys[2] deposit_input = make_deposit_input( pubkey=pubkey_3, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) proof_of_possession = sign_proof_of_possession(deposit_input, privkey_3, domain) result_state, index = process_deposit( state=result_state, pubkey=pubkey_3, deposit=deposit, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, zero_balance_validator_ttl=zero_balance_validator_ttl, ) # Overwrite the second validator. assert len(result_state.validator_registry) == 2 assert result_state.validator_registry[0].pubkey == pubkey_3
def sample_state(sample_beacon_state_params): return BeaconState(**sample_beacon_state_params)
def test_defaults(sample_beacon_state_params): state = BeaconState(**sample_beacon_state_params) assert state.validator_registry == sample_beacon_state_params['validator_registry'] assert state.validator_registry_latest_change_slot == sample_beacon_state_params['validator_registry_latest_change_slot'] # noqa: E501
def test_hash(sample_beacon_state_params): state = BeaconState(**sample_beacon_state_params) assert state.root == hash_eth2(rlp.encode(state))
def test_process_deposit(sample_beacon_state_params, privkeys, pubkeys, max_deposit): state = BeaconState(**sample_beacon_state_params).copy( slot=1, validator_registry=(), ) privkey_1 = privkeys[0] pubkey_1 = pubkeys[0] amount = max_deposit * GWEI_PER_ETH withdrawal_credentials = b'\x34' * 32 custody_commitment = b'\x11' * 32 randao_commitment = b'\x56' * 32 deposit_input = make_deposit_input( pubkey=pubkey_1, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) proof_of_possession = sign_proof_of_possession( deposit_input, privkey_1, state.fork_data, state.slot, ) # Add the first validator result_state = process_deposit( state=state, pubkey=pubkey_1, amount=amount, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) assert len(result_state.validator_registry) == 1 index = 0 assert result_state.validator_registry[0].pubkey == pubkey_1 assert result_state.validator_registry[ index].withdrawal_credentials == withdrawal_credentials assert result_state.validator_registry[ index].randao_commitment == randao_commitment assert result_state.validator_balances[index] == amount # test immutable assert len(state.validator_registry) == 0 # Add the second validator privkey_2 = privkeys[1] pubkey_2 = pubkeys[1] deposit_input = make_deposit_input( pubkey=pubkey_2, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) proof_of_possession = sign_proof_of_possession( deposit_input, privkey_2, state.fork_data, state.slot, ) result_state = process_deposit( state=result_state, pubkey=pubkey_2, amount=amount, proof_of_possession=proof_of_possession, withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ) assert len(result_state.validator_registry) == 2 assert result_state.validator_registry[1].pubkey == pubkey_2