def process_rewards_and_penalties( state: BeaconState, config: Eth2Config ) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) if current_epoch == config.GENESIS_EPOCH: return state rewards_for_attestations, penalties_for_attestations = get_attestation_deltas( state, config ) rewards_for_crosslinks, penalties_for_crosslinks = get_crosslink_deltas( state, config ) for index in range(len(state.validators)): index = ValidatorIndex(index) state = increase_balance( state, index, Gwei(rewards_for_attestations[index] + rewards_for_crosslinks[index]), ) state = decrease_balance( state, index, Gwei(penalties_for_attestations[index] + penalties_for_crosslinks[index]), ) return state
def process_transfers(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: if len(block.body.transfers) > config.MAX_TRANSFERS: raise ValidationError( f"The block ({block}) has too many transfers:\n" f"\tFound {len(block.body.transfers)} transfers, " f"maximum: {config.MAX_TRANSFERS}") for transfer in block.body.transfers: validate_transfer( state, transfer, config, ) state = decrease_balance( state, transfer.sender, transfer.amount + transfer.fee, ) state = increase_balance( state, transfer.recipient, transfer.amount, ) state = increase_balance( state, get_beacon_proposer_index( state, CommitteeConfig(config), ), transfer.fee, ) return state
def slash_validator(state: BeaconState, index: ValidatorIndex, config: Eth2Config, whistleblower_index: ValidatorIndex = None) -> BeaconState: """ Slash the validator with index ``index``. Exit the validator, penalize the validator, and reward the whistleblower. """ # NOTE: remove in phase 1 assert whistleblower_index is None slots_per_epoch = config.SLOTS_PER_EPOCH current_epoch = state.current_epoch(slots_per_epoch) state = initiate_validator_exit(state, index, config) state = state.update_validator_with_fn( index, _set_validator_slashed, current_epoch, config.EPOCHS_PER_SLASHINGS_VECTOR, ) slashed_balance = state.validators[index].effective_balance slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR state = state.copy(slashings=update_tuple_item_with_fn( state.slashings, slashed_epoch, lambda balance, slashed_balance: Gwei(balance + slashed_balance), slashed_balance, )) state = decrease_balance( state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT) proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config)) if whistleblower_index is None: whistleblower_index = proposer_index whistleblower_reward = Gwei(slashed_balance // config.WHISTLEBLOWER_REWARD_QUOTIENT) proposer_reward = Gwei(whistleblower_reward // config.PROPOSER_REWARD_QUOTIENT) state = increase_balance(state, proposer_index, proposer_reward) state = increase_balance( state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward), ) return state
def slash_validator( state: BeaconState, index: ValidatorIndex, config: Eth2Config, whistleblower_index: ValidatorIndex = None, ) -> BeaconState: """ Slash the validator with index ``index``. Exit the validator, penalize the validator, and reward the whistleblower. """ # NOTE: remove in phase 1 assert whistleblower_index is None slots_per_epoch = config.SLOTS_PER_EPOCH current_epoch = state.current_epoch(slots_per_epoch) state = initiate_validator_exit(state, index, config) state = state.transform( ("validators", index), partial( _set_validator_slashed, current_epoch=current_epoch, epochs_per_slashings_vector=config.EPOCHS_PER_SLASHINGS_VECTOR, ), ) slashed_balance = state.validators[index].effective_balance slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR state = state.transform(("slashings", slashed_epoch), lambda balance: Gwei(balance + slashed_balance)) state = decrease_balance( state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT) proposer_index = get_beacon_proposer_index(state, config) if whistleblower_index is None: whistleblower_index = proposer_index whistleblower_reward = Gwei(slashed_balance // config.WHISTLEBLOWER_REWARD_QUOTIENT) proposer_reward = Gwei(whistleblower_reward // config.PROPOSER_REWARD_QUOTIENT) state = increase_balance(state, proposer_index, proposer_reward) state = increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward)) return state
def process_slashings(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) total_balance = get_total_active_balance(state, config) slashing_period = config.EPOCHS_PER_SLASHINGS_VECTOR // 2 for index, validator in enumerate(state.validators): index = ValidatorIndex(index) if validator.slashed and current_epoch + slashing_period == validator.withdrawable_epoch: penalty = _determine_slashing_penalty( Gwei(sum(state.slashings)), total_balance, validator.effective_balance, config.EFFECTIVE_BALANCE_INCREMENT, ) state = decrease_balance(state, index, penalty) return state
def process_slashings(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) total_balance = get_total_active_balance(state, config) start_index = (current_epoch + 1) % config.EPOCHS_PER_SLASHED_BALANCES_VECTOR total_at_start = state.slashed_balances[start_index] end_index = current_epoch % config.EPOCHS_PER_SLASHED_BALANCES_VECTOR total_at_end = state.slashed_balances[end_index] total_penalties = total_at_end - total_at_start slashing_period = config.EPOCHS_PER_SLASHED_BALANCES_VECTOR // 2 for index, validator in enumerate(state.validators): index = ValidatorIndex(index) if validator.slashed and current_epoch == validator.withdrawable_epoch - slashing_period: penalty = _determine_slashing_penalty( total_penalties, total_balance, validator.effective_balance, config.MIN_SLASHING_PENALTY_QUOTIENT, ) state = decrease_balance(state, index, penalty) return state
def test_decrease_balance(genesis_state, delta): index = random.sample(range(len(genesis_state.validators)), 1)[0] prior_balance = genesis_state.balances[index] state = decrease_balance(genesis_state, index, delta) assert state.balances[index] == Gwei(max(prior_balance - delta, 0))