---
# System prepended metadata

title: 'RESEARCH: Rewards and Penalties'
tags: [rewards]

---

---
tags: rewards
---

# RESEARCH: Rewards and Penalties

~~__Phase0__~~ и ~~__Belatrix__~~ - скипаем как неактуальные
делаем ресерч для __ALTAIR__


Начисление Наград и Штрафов выполняется в результате вычисления стейта.
Выполняется в 3-х основных случаях:
1. __computeStateRoot__: Расчет рута при создании блока Пропозером (предварительный расчет стейта). Есть еще апи валидаторов, но назначение не совсем понятно (см. `GetValidatorPerformance`(proto/prysm/v1alpha1/beacon_chain.proto:215) -> `ProcessRewardsAndPenaltiesPrecompute`) 
2. __onBlock__: Обработка нового блока. Получен по сети (Пропагейт), либо создан локально (Пропозинг).
3. __ReplayProcessSlots__: Синхронизация (ИнитСинк)





## Aggregator: награда за агрегацию аттестаций

Функционал отсутствует


## Attestator:  награда (и штраф) за аттестацию

Cрабатывает в конце эпохи.

`ProcessEpoch` -> `ProcessRewardsAndPenaltiesPrecompute`


````go
// ProcessEpoch describes the per epoch operations that are performed on the beacon state.
// It's optimized by pre computing validator attested info and epoch total/attested balances upfront.
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconStateAltair, error) {
        ...
	// New in Altair.
	state, err = ProcessRewardsAndPenaltiesPrecompute(state, bp, vp)
        ...
}
````



````go
// ProcessRewardsAndPenaltiesPrecompute processes the rewards and penalties of individual validator.
// This is an optimized version by passing in precomputed validator attesting records and and total epoch balances.
func ProcessRewardsAndPenaltiesPrecompute(...) ... {
    ...
	attsRewards, attsPenalties, err := AttestationsDelta(beaconState, bal, vals)
        // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...
	balances := beaconState.Balances()
	for i := 0; i < numOfVals; i++ {
		// Compute the post balance of the validator after accounting for the
		// attester and proposer rewards and penalties.
		balances[i], err = helpers.IncreaseBalanceWithVal(balances[i], attsRewards[i])
        ...
		balances[i] = helpers.DecreaseBalanceWithVal(balances[i], attsPenalties[i])
        ...
	}
    if err := beaconState.SetBalances(balances); err != nil {...}
    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...
}
````


````go
// AttestationsDelta computes and returns the rewards and penalties differences for individual validators based on the
// voting records.
func AttestationsDelta(beaconState state.BeaconState, bal *precompute.Balance, vals []*precompute.Validator) (rewards, penalties []uint64, err error) {
	numOfVals := beaconState.NumValidators()
	rewards = make([]uint64, numOfVals)
	penalties = make([]uint64, numOfVals)

	cfg := params.BeaconConfig()
	prevEpoch := time.PrevEpoch(beaconState)
	finalizedEpoch := beaconState.FinalizedCheckpointEpoch()
        /*
        EffectiveBalanceIncrement: 1 * 1e9,
        */
	increment := cfg.EffectiveBalanceIncrement
        /*
        BaseRewardFactor:               64,
        */
	factor := cfg.BaseRewardFactor
	baseRewardMultiplier := increment * factor / math.IntegerSquareRoot(bal.ActiveCurrentEpoch)
	/* 
        IsInInactivityLeak returns true if the state is experiencing inactivity leak. 
        
        leak := prevEpoch - finalizedEpoch > cfg.MinEpochsToInactivityPenalty
        где 
        cfg.MinEpochsToInactivityPenalty = 4

        Наверное фиксирует момент того, что чекпоинт Финалайзед перестал обновляться 
        */
        leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)

	// Modified in Altair and Bellatrix.
	var inactivityDenominator uint64
	bias := cfg.InactivityScoreBias
	switch beaconState.Version() {
	case version.Altair:
                /*
                InactivityPenaltyQuotientAltair:         3 * 1 << 24, //50331648
                */
		inactivityDenominator = bias * cfg.InactivityPenaltyQuotientAltair
	case version.Bellatrix:
		inactivityDenominator = bias * cfg.InactivityPenaltyQuotientBellatrix
	default:
		return nil, nil, errors.Errorf("invalid state type version: %T", beaconState.Version())
	}

	for i, v := range vals {
		rewards[i], penalties[i], err = attestationDelta(bal, v, baseRewardMultiplier, inactivityDenominator, leak)
		if err != nil {
			return nil, nil, err
		}
	}

	return rewards, penalties, nil
}

func attestationDelta(
	bal *precompute.Balance,
	val *precompute.Validator,
	baseRewardMultiplier, inactivityDenominator uint64,
	inactivityLeak bool) (reward, penalty uint64, err error) {
	eligible := val.IsActivePrevEpoch || (val.IsSlashed && !val.IsWithdrawableCurrentEpoch)
	// Per spec `ActiveCurrentEpoch` can't be 0 to process attestation delta.
	if !eligible || bal.ActiveCurrentEpoch == 0 {
		return 0, 0, nil
	}

	cfg := params.BeaconConfig()
	increment := cfg.EffectiveBalanceIncrement
	effectiveBalance := val.CurrentEpochEffectiveBalance
	baseReward := (effectiveBalance / increment) * baseRewardMultiplier
	activeIncrement := bal.ActiveCurrentEpoch / increment

	weightDenominator := cfg.WeightDenominator
	srcWeight := cfg.TimelySourceWeight
	tgtWeight := cfg.TimelyTargetWeight
	headWeight := cfg.TimelyHeadWeight
	reward, penalty = uint64(0), uint64(0)
    
        /*
        activeIncrement=8256 
        baseReward=712736 
        effectiveBalance=32000000000 
        headWeight=14 
        inactivityLeak=false 
        increment=1000000000 
        srcWeight=14 
        tgtWeight=26 
        val.IsPrevEpochHeadAttester=true 
        val.IsPrevEpochSourceAttester=true 
        val.IsPrevEpochTargetAttester=true 
        val.IsSlashed=false 
        weightDenominator=64
        */
    
	// Process source reward / penalty
	if val.IsPrevEpochSourceAttester && !val.IsSlashed {
		if !inactivityLeak {
			n := baseReward * srcWeight * (bal.PrevEpochAttested / increment)
			reward += n / (activeIncrement * weightDenominator)
		}
	} else {
		penalty += baseReward * srcWeight / weightDenominator
	}
        /*
        penalty=0 
        reward=155911
        */
	// Process target reward / penalty
	if val.IsPrevEpochTargetAttester && !val.IsSlashed {
		if !inactivityLeak {
			n := baseReward * tgtWeight * (bal.PrevEpochTargetAttested / increment)
			reward += n / (activeIncrement * weightDenominator)
		}
	} else {
		penalty += baseReward * tgtWeight / weightDenominator
	}
        /*
        penalty=0 
        reward=445460
        */
	// Process head reward / penalty
	if val.IsPrevEpochHeadAttester && !val.IsSlashed {
		if !inactivityLeak {
			n := baseReward * headWeight * (bal.PrevEpochHeadAttested / increment)
			reward += n / (activeIncrement * weightDenominator)
		}
	}
        /*
        penalty=0 
        reward=601371
        */
	// Process finality delay penalty
	// Apply an additional penalty to validators that did not vote on the correct target or slashed
	if !val.IsPrevEpochTargetAttester || val.IsSlashed {
		n, err := math.Mul64(effectiveBalance, val.InactivityScore)
		if err != nil {
			return 0, 0, err
		}
		penalty += n / inactivityDenominator
	}
        /*
        penalty=0 
        reward=601371
        */
	return reward, penalty, nil
}

````



##  Proposer: награда за создание блока

срабатывает на каждом слоте

Похоже, что это начисление выполняется за каждую аттестацию включенную в блок.
Причем, по каждой аттестации может быть три позиции по которым выполняется начисление:
1. голосование за таргет-эпоху
2. голосование за сорс-эпоху
3. голосование за хед


###### Обработка Блока (выполняется нодой при обработке блока)

```
Function
    ProcessBlockForStateRoot
/home/mezin/go/src/tesseract/beacon-chain/core/transition
transition_no_verify_sig.go
    CalculateStateRoot
        state, err = ProcessBlockForStateRoot(ctx, state, signed)
    ProcessBlockNoVerifyAnySig
        state, err := ProcessBlockForStateRoot(ctx, state, signed)
/home/mezin/go/src/tesseract/beacon-chain/state/stategen
replay.go
    executeStateTransitionStateGen
        state, err = transition.ProcessBlockForStateRoot(ctx, state, signed)
```

````go
// ProcessBlockForStateRoot processes the state for state root computation. func ProcessBlockForStateRoot(...) ... {
        ...
	state, err = ProcessOperationsNoVerifyAttsSigs(ctx, state, signed)
        ...
}


// ProcessOperationsNoVerifyAttsSigs processes the operations in the beacon block and updates beacon state
// with the operations in block. It does not verify attestation signatures.
//
// WARNING: This method does not verify attestation signatures.
// This is used to perform the block operations as fast as possible.
func ProcessOperationsNoVerifyAttsSigs(...) ... {
    ...
	case version.Altair, version.Bellatrix:
		state, err = altairOperations(ctx, state, signedBeaconBlock)
                //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...
}



func altairOperations(...)...{
    ...
	state, err = altair.ProcessAttestationsNoVerifySignature(ctx, state, signedBeaconBlock)
    ...
}
````

````go
// ProcessAttestationsNoVerifySignature applies processing operations to a block's inner attestation
// records. The only difference would be that the attestation signature would not be verified.
func ProcessAttestationsNoVerifySignature(
	ctx context.Context,
	beaconState state.BeaconState,
	b block.SignedBeaconBlock,
) (state.BeaconState, error) {
    ...
	for idx, attestation := range body.Attestations() {
		beaconState, err = ProcessAttestationNoVerifySignature(ctx, beaconState, attestation, totalBalance)
                    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		if err != nil {
			return nil, errors.Wrapf(err, "could not verify attestation at index %d in block", idx)
		}
	}

	return beaconState, nil
}
````

###### RPC (выполняется пропозером при создании блока)
````go
// Build data required for creating a new beacon block, so this method can be shared across forks.
func (vs *Server) buildPhase0BlockData(...) ... {
    ...
	deposits, atts, err := vs.packDepositsAndAttestations(ctx, head, eth1Data)
    
    ...
	return &blockData{...}, nil
}

func (vs *Server) optimizedPackDepositsAndAttestations(...) ... {
		// Pack aggregated attestations which have not been included in the beacon chain.
		localAtts, err := vs.packAttestations(egctx, head)

}


func (vs *Server) packAttestations(...) ... {
    ...
	uAtts, err = vs.validateAndDeleteAttsInPool(ctx, latestState, uAtts)
    ...
}


// This filters the input attestations to return a list of valid attestations to be packaged inside a beacon block.
func (vs *Server) validateAndDeleteAttsInPool(...) (...) {
    ...
	validAtts, invalidAtts := proposerAtts(atts).filter(ctx, st)
    ...
}


// filter separates attestation list into two groups: valid and invalid attestations.
// The first group passes the all the required checks for attestation to be considered for proposing.
// And attestations from the second group should be deleted.
func (a proposerAtts) filter(ctx context.Context, st state.BeaconState) (proposerAtts, proposerAtts) {
	validAtts := make([]*ethpb.Attestation, 0, len(a))
	invalidAtts := make([]*ethpb.Attestation, 0, len(a))
	var attestationProcessor func(context.Context, state.BeaconState, *ethpb.Attestation) (state.BeaconState, error)

	switch st.Version() {
	case version.Phase0:
		attestationProcessor = blocks.ProcessAttestationNoVerifySignature
	case version.Altair, version.Bellatrix:
		// Use a wrapper here, as go needs strong typing for the function signature.
		attestationProcessor = func(ctx context.Context, st state.BeaconState, attestation *ethpb.Attestation) (state.BeaconState, error) {
			totalBalance, err := helpers.TotalActiveBalance(st)
            ...
			return altair.ProcessAttestationNoVerifySignature(ctx, st, attestation, totalBalance)
                        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		}
	default:
		// Exit early if there is an unknown state type.
		return validAtts, invalidAtts
	}
	for _, att := range a {
		if _, err := attestationProcessor(ctx, st, att); err == nil {
                    //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			validAtts = append(validAtts, att)
			continue
		}
		invalidAtts = append(invalidAtts, att)
	}
	return validAtts, invalidAtts
}
````







````go
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
// method is used to validate attestations whose signatures have already been verified or will be verified later.
func ProcessAttestationNoVerifySignature(
	ctx context.Context,
	beaconState state.BeaconStateAltair,
	att *ethpb.Attestation,
	totalBalance uint64,
) (state.BeaconStateAltair, error) {
    ...
	return SetParticipationAndRewardProposer(ctx, beaconState, att.Data.Target.Epoch, indices, participatedFlags, totalBalance)
}
````


````go

// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
// the proposer in state.
//
//    # Reward proposer
//    proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
//    proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
//    increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
func SetParticipationAndRewardProposer(
	ctx context.Context,
	beaconState state.BeaconState,
	targetEpoch types.Epoch,
	indices []uint64,
	participatedFlags map[uint8]bool, totalBalance uint64) (state.BeaconState, error) {
	var proposerRewardNumerator uint64
    ...

    	if targetEpoch == currentEpoch {
		stateErr = beaconState.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) {
			propRewardNum, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
            ...
			proposerRewardNumerator = propRewardNum
			return epochParticipation, nil
		})
	} else {
		stateErr = beaconState.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) {
			propRewardNum, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
            ...
			proposerRewardNumerator = propRewardNum
			return epochParticipation, nil
		})
	}
    
    
	if err := RewardProposer(ctx, beaconState, proposerRewardNumerator); err != nil {
            //^^^^^^^^^^^^^^^^^^^^^^^^^^^^
		return nil, err
	}

	return beaconState, nil
}
````

````go
// EpochParticipation sets and returns the proposer reward numerator and epoch participation.
//
// Spec code:
//    proposer_reward_numerator = 0
//    for index in get_attesting_indices(state, data, attestation.aggregation_bits):
//        for flag_index, weight in enumerate(PARTICIPATION_FLAG_WEIGHTS):
//            if flag_index in participation_flag_indices and not has_flag(epoch_participation[index], flag_index):
//                epoch_participation[index] = add_flag(epoch_participation[index], flag_index)
//                proposer_reward_numerator += get_base_reward(state, index) * weight
func EpochParticipation(beaconState state.BeaconState, indices []uint64, epochParticipation []byte, participatedFlags map[uint8]bool, totalBalance uint64) (uint64, []byte, error) {
	cfg := params.BeaconConfig()
	sourceFlagIndex := cfg.TimelySourceFlagIndex
	targetFlagIndex := cfg.TimelyTargetFlagIndex
	headFlagIndex := cfg.TimelyHeadFlagIndex
	proposerRewardNumerator := uint64(0)
	for _, index := range indices {
		if index >= uint64(len(epochParticipation)) {
			return 0, nil, fmt.Errorf("index %d exceeds participation length %d", index, len(epochParticipation))
		}
		br, err := BaseRewardWithTotalBalance(beaconState, types.ValidatorIndex(index), totalBalance)
		if err != nil {
			return 0, nil, err
		}
		has, err := HasValidatorFlag(epochParticipation[index], sourceFlagIndex)
		if err != nil {
			return 0, nil, err
		}
		if participatedFlags[sourceFlagIndex] && !has {
			epochParticipation[index], err = AddValidatorFlag(epochParticipation[index], sourceFlagIndex)
			if err != nil {
				return 0, nil, err
			}
			proposerRewardNumerator += br * cfg.TimelySourceWeight
		}
		has, err = HasValidatorFlag(epochParticipation[index], targetFlagIndex)
		if err != nil {
			return 0, nil, err
		}
		if participatedFlags[targetFlagIndex] && !has {
			epochParticipation[index], err = AddValidatorFlag(epochParticipation[index], targetFlagIndex)
			if err != nil {
				return 0, nil, err
			}
			proposerRewardNumerator += br * cfg.TimelyTargetWeight
		}
		has, err = HasValidatorFlag(epochParticipation[index], headFlagIndex)
        if participatedFlags[headFlagIndex] && !has {
			epochParticipation[index], err = AddValidatorFlag(epochParticipation[index], headFlagIndex)
            ...
			proposerRewardNumerator += br * cfg.TimelyHeadWeight
		}
	}

	return proposerRewardNumerator, epochParticipation, nil
}
````


````go
// RewardProposer rewards proposer by increasing proposer's balance with input reward numerator and calculated reward denominator.
//
// Spec code:
//    proposer_reward_denominator = (WEIGHT_DENOMINATOR - PROPOSER_WEIGHT) * WEIGHT_DENOMINATOR // PROPOSER_WEIGHT
//    proposer_reward = Gwei(proposer_reward_numerator // proposer_reward_denominator)
//    increase_balance(state, get_beacon_proposer_index(state), proposer_reward)
func RewardProposer(ctx context.Context, beaconState state.BeaconState, proposerRewardNumerator uint64) error {
	cfg := params.BeaconConfig()
	d := (cfg.WeightDenominator - cfg.ProposerWeight) * cfg.WeightDenominator / cfg.ProposerWeight
	proposerReward := proposerRewardNumerator / d
        /*
        cfg.ProposerWeight=8 
        cfg.WeightDenominator=64 
        d=448 
        proposerReward=687281 
        proposerRewardNumerator=307901952
        */
	i, err := helpers.BeaconProposerIndex(ctx, beaconState)
	if err != nil {
		return err
	}

	return helpers.IncreaseBalance(beaconState, i, proposerReward)
}
````



## SyncCommitteeAggregator 
ничего не получает

Аггрегирует SyncCommittee см. ниже.


## SyncCommittee: награда и штраф

срабатывает на каждом слоте

Служит для поддержки работы __Лайт-Клиента__.
Делает аттестацию рута стейта предшествующего слота __(currentSlot - 1)__


````go
func (vs *Server) buildAltairBeaconBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BeaconBlockAltair, error) {
    ...
	syncAggregate, err := vs.getSyncAggregate(ctx, req.Slot-1, bytesutil.ToBytes32(blkData.ParentRoot))
    ...
	return &ethpb.BeaconBlockAltair{
        ...
		Body: &ethpb.BeaconBlockBodyAltair{
                    ...
                    SyncAggregate:     syncAggregate,
                    //^^^^^^^^^^^^
		},
	}, nil
}
````


````go
Function
    ProcessBlockForStateRoot
/home/mezin/go/src/tesseract/beacon-chain/core/transition
transition_no_verify_sig.go (Вызов в /beacon-chain/rpc/prysm/v1alpha1/validator/proposer.go:computeStateRoot)
    CalculateStateRoot
        state, err = ProcessBlockForStateRoot(ctx, state, signed)
    ProcessBlockNoVerifyAnySig
        state, err := ProcessBlockForStateRoot(ctx, state, signed)
/home/mezin/go/src/tesseract/beacon-chain/state/stategen
replay.go
    executeStateTransitionStateGen
        state, err = transition.ProcessBlockForStateRoot(ctx, state, signed)


// ProcessBlockForStateRoot processes the state for state root computation.
func ProcessBlockForStateRoot(...) ... {
    ...
	state, err = altair.ProcessSyncAggregate(ctx, state, sa)
    ...
	return state, nil
}

````




````go
Function
    ProcessSyncAggregate
/home/mezin/go/src/tesseract/beacon-chain/core/transition
transition_no_verify_sig.go
    ProcessBlockForStateRoot
        state, err = altair.ProcessSyncAggregate(ctx, state, sa)

/*
Function
    ProcessSyncAggregate
/home/mezin/go/src/tesseract/beacon-chain/core/transition
transition_no_verify_sig.go
    ProcessBlockForStateRoot
        state, err = altair.ProcessSyncAggregate(ctx, state, sa)
*/
// ProcessSyncAggregate verifies sync committee aggregate signature signing over the previous slot block root.
func ProcessSyncAggregate(ctx context.Context, s state.BeaconStateAltair, sync *ethpb.SyncAggregate) (state.BeaconStateAltair, error) {
	votedKeys, votedIndices, didntVoteIndices, err := FilterSyncCommitteeVotes(s, sync)
        ...
	if err := VerifySyncCommitteeSig(s, votedKeys, sync.SyncCommitteeSignature); err != nil {
		return nil, err
	}

	return ApplySyncRewardsPenalties(ctx, s, votedIndices, didntVoteIndices)
        //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}

````

````go
// ApplySyncRewardsPenalties applies rewards and penalties for proposer and sync committee participants.
func ApplySyncRewardsPenalties(ctx context.Context, s state.BeaconStateAltair, votedIndices, didntVoteIndices []types.ValidatorIndex) (state.BeaconStateAltair, error) {
	activeBalance, err := helpers.TotalActiveBalance(s)
        ...
	proposerReward, participantReward, err := SyncRewards(activeBalance)
	    ...
        // Apply sync committee rewards.
	earnedProposerReward := uint64(0)
	for _, index := range votedIndices {
            /*
            index=118 
            participantReward=350
            */
		if err := helpers.IncreaseBalance(s, index, participantReward); err != nil {
                //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			return nil, err
		}
		earnedProposerReward += proposerReward
            //^^^^^^^^^^^^^^^^^^^^
	}
	// Apply proposer rewards.
    /*
    Получить пропозера по стейту
    */
	proposerIndex, err := helpers.BeaconProposerIndex(ctx, s)
        ...
        /*
        earnedProposerReward=25600 
        proposerIndex=7
        */
	if err := helpers.IncreaseBalance(s, proposerIndex, earnedProposerReward); err != nil {
		return nil, err
	}
	// Apply sync committee penalties.
	for _, index := range didntVoteIndices {
		if err := helpers.DecreaseBalance(s, index, participantReward); err != nil {
                //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
			return nil, err
		}
	}

	return s, nil
}



// SyncRewards returns the proposer reward and the sync participant reward given the total active balance in state.
func SyncRewards(activeBalance uint64) (proposerReward, participantReward uint64, err error) {
	cfg := params.BeaconConfig()
	totalActiveIncrements := activeBalance / cfg.EffectiveBalanceIncrement
	baseRewardPerInc, err := BaseRewardPerIncrement(activeBalance)
	if err != nil {
		return 0, 0, err
	}
	totalBaseRewards := baseRewardPerInc * totalActiveIncrements
	maxParticipantRewards := totalBaseRewards * cfg.SyncRewardWeight / cfg.WeightDenominator / uint64(cfg.SlotsPerEpoch)
	participantReward = maxParticipantRewards / cfg.SyncCommitteeSize
	proposerReward = participantReward * cfg.ProposerWeight / (cfg.WeightDenominator - cfg.ProposerWeight)
	return
}


// BaseRewardPerIncrement of the beacon state
//
// Spec code:
// def get_base_reward_per_increment(state: BeaconState) -> Gwei:
//    return Gwei(EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR // integer_squareroot(get_total_active_balance(state)))
func BaseRewardPerIncrement(activeBalance uint64) (uint64, error) {
	if activeBalance == 0 {
		return 0, errors.New("active balance can't be 0")
	}
	cfg := params.BeaconConfig()
	return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / math.IntegerSquareRoot(activeBalance), nil
}

````


## Slash

### SlashValidator


````go
// SlashValidator slashes the malicious validator's balance and awards
// the whistleblower's balance.
//
// Spec pseudocode definition:
//  def slash_validator(state: BeaconState,
//                    slashed_index: ValidatorIndex,
//                    whistleblower_index: ValidatorIndex=None) -> None:
//    """
//    Slash the validator with index ``slashed_index``.
//    """
//    epoch = get_current_epoch(state)
//    initiate_validator_exit(state, slashed_index)
//    validator = state.validators[slashed_index]
//    validator.slashed = True
//    validator.withdrawable_epoch = max(validator.withdrawable_epoch, Epoch(epoch + EPOCHS_PER_SLASHINGS_VECTOR))
//    state.slashings[epoch % EPOCHS_PER_SLASHINGS_VECTOR] += validator.effective_balance
//    decrease_balance(state, slashed_index, validator.effective_balance // MIN_SLASHING_PENALTY_QUOTIENT)
//
//    # Apply proposer and whistleblower rewards
//    proposer_index = get_beacon_proposer_index(state)
//    if whistleblower_index is None:
//        whistleblower_index = proposer_index
//    whistleblower_reward = Gwei(validator.effective_balance // WHISTLEBLOWER_REWARD_QUOTIENT)
//    proposer_reward = Gwei(whistleblower_reward // PROPOSER_REWARD_QUOTIENT)
//    increase_balance(state, proposer_index, proposer_reward)
//    increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward))
func SlashValidator(
	ctx context.Context,
	s state.BeaconState,
	slashedIdx types.ValidatorIndex,
	penaltyQuotient uint64,
	proposerRewardQuotient uint64) (state.BeaconState, error) {
	s, err := InitiateValidatorExit(ctx, s, slashedIdx)
	if err != nil {
		return nil, errors.Wrapf(err, "could not initiate validator %d exit", slashedIdx)
	}
	currentEpoch := slots.ToEpoch(s.Slot())
	validator, err := s.ValidatorAtIndex(slashedIdx)
            ...
	validator.Slashed = true
	maxWithdrawableEpoch := types.MaxEpoch(validator.WithdrawableEpoch, currentEpoch+params.BeaconConfig().EpochsPerSlashingsVector)
	validator.WithdrawableEpoch = maxWithdrawableEpoch

	if err := s.UpdateValidatorAtIndex(slashedIdx, validator); err != nil {
		return nil, err
	}

	// The slashing amount is represented by epochs per slashing vector. The validator's effective balance is then applied to that amount.
	slashings := s.Slashings()
	currentSlashing := slashings[currentEpoch%params.BeaconConfig().EpochsPerSlashingsVector]
	if err := s.UpdateSlashingsAtIndex(
		uint64(currentEpoch%params.BeaconConfig().EpochsPerSlashingsVector),
		currentSlashing+validator.EffectiveBalance,
	); err != nil {
		return nil, err
	}
	if err := helpers.DecreaseBalance(s, slashedIdx, validator.EffectiveBalance/penaltyQuotient); err != nil {
		return nil, err
	}

	proposerIdx, err := helpers.BeaconProposerIndex(ctx, s)
	if err != nil {
		return nil, errors.Wrap(err, "could not get proposer idx")
	}
	// In phase 0, the proposer is the whistleblower.
	whistleBlowerIdx := proposerIdx
	whistleblowerReward := validator.EffectiveBalance / params.BeaconConfig().WhistleBlowerRewardQuotient
	proposerReward := whistleblowerReward / proposerRewardQuotient
	err = helpers.IncreaseBalance(s, proposerIdx, proposerReward)
	if err != nil {
		return nil, err
	}
	err = helpers.IncreaseBalance(s, whistleBlowerIdx, whistleblowerReward-proposerReward)
	if err != nil {
		return nil, err
	}
	return s, nil
}

````

### ProcessSlashings

````go
// ProcessSlashings processes the slashed validators during epoch processing,
//
//  def process_slashings(state: BeaconState) -> None:
//    epoch = get_current_epoch(state)
//    total_balance = get_total_active_balance(state)
//    adjusted_total_slashing_balance = min(sum(state.slashings) * PROPORTIONAL_SLASHING_MULTIPLIER, total_balance)
//    for index, validator in enumerate(state.validators):
//        if validator.slashed and epoch + EPOCHS_PER_SLASHINGS_VECTOR // 2 == validator.withdrawable_epoch:
//            increment = EFFECTIVE_BALANCE_INCREMENT  # Factored out from penalty numerator to avoid uint64 overflow
//            penalty_numerator = validator.effective_balance // increment * adjusted_total_slashing_balance
//            penalty = penalty_numerator // total_balance * increment
//            decrease_balance(state, ValidatorIndex(index), penalty)
func ProcessSlashings(state state.BeaconState, slashingMultiplier uint64) (state.BeaconState, error) {
	currentEpoch := time.CurrentEpoch(state)
	totalBalance, err := helpers.TotalActiveBalance(state)
	if err != nil {
		return nil, errors.Wrap(err, "could not get total active balance")
	}

	// Compute slashed balances in the current epoch
	exitLength := params.BeaconConfig().EpochsPerSlashingsVector

	// Compute the sum of state slashings
	slashings := state.Slashings()
	totalSlashing := uint64(0)
	for _, slashing := range slashings {
		totalSlashing, err = math.Add64(totalSlashing, slashing)
		if err != nil {
			return nil, err
		}
	}

	// a callback is used here to apply the following actions  to all validators
	// below equally.
	increment := params.BeaconConfig().EffectiveBalanceIncrement
	minSlashing := math.Min(totalSlashing*slashingMultiplier, totalBalance)
	err = state.ApplyToEveryValidator(func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
		correctEpoch := (currentEpoch + exitLength/2) == val.WithdrawableEpoch
		if val.Slashed && correctEpoch {
			penaltyNumerator := val.EffectiveBalance / increment * minSlashing
			penalty := penaltyNumerator / totalBalance * increment
			if err := helpers.DecreaseBalance(state, types.ValidatorIndex(idx), penalty); err != nil {
				return false, val, err
			}
			return true, val, nil
		}
		return false, val, nil
	})
	return state, err
}
````


### ProcessSlashingsPrecompute

````go
// ProcessSlashingsPrecompute processes the slashed validators during epoch processing.
// This is an optimized version by passing in precomputed total epoch balances.
func ProcessSlashingsPrecompute(s state.BeaconState, pBal *Balance) error {
	currentEpoch := time.CurrentEpoch(s)
	exitLength := params.BeaconConfig().EpochsPerSlashingsVector

	// Compute the sum of state slashings
	slashings := s.Slashings()
	totalSlashing := uint64(0)
	for _, slashing := range slashings {
		totalSlashing += slashing
	}

	minSlashing := math.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, pBal.ActiveCurrentEpoch)
	epochToWithdraw := currentEpoch + exitLength/2

	var hasSlashing bool
	// Iterate through validator list in state, stop until a validator satisfies slashing condition of current epoch.
	err := s.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
		correctEpoch := epochToWithdraw == val.WithdrawableEpoch()
		if val.Slashed() && correctEpoch {
			hasSlashing = true
		}
		return nil
	})
	if err != nil {
		return err
	}
	// Exit early if there's no meaningful slashing to process.
	if !hasSlashing {
		return nil
	}

	increment := params.BeaconConfig().EffectiveBalanceIncrement
	validatorFunc := func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
		correctEpoch := epochToWithdraw == val.WithdrawableEpoch
		if val.Slashed && correctEpoch {
			penaltyNumerator := val.EffectiveBalance / increment * minSlashing
			penalty := penaltyNumerator / pBal.ActiveCurrentEpoch * increment
			if err := helpers.DecreaseBalance(s, types.ValidatorIndex(idx), penalty); err != nil {
				return false, val, err
			}
			return true, val, nil
		}
		return false, val, nil
	}

	return s.ApplyToEveryValidator(validatorFunc)
}
````


## Методы обновления баланса валидатора

Используются только эти методы

### IncreaseBalance

````go
Function
    IncreaseBalance
Usages in Project and Libraries
Unclassified
.workspace
/home/mezin/go/src/tesseract/beacon-chain/core/altair
attestation.go
RewardProposer
	return helpers.IncreaseBalance(beaconState, i, proposerReward)
block.go
ApplySyncRewardsPenalties
		if err := helpers.IncreaseBalance(s, index, participantReward); err != nil {
	if err := helpers.IncreaseBalance(s, proposerIndex, earnedProposerReward); err != nil {
/home/mezin/go/src/tesseract/beacon-chain/core/blocks
deposit.go
ProcessDeposit
	} else if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
/home/mezin/go/src/tesseract/beacon-chain/core/helpers
rewards_penalties_test.go
TestIncreaseBadBalance_NotOK
		require.ErrorContains(t, "addition overflows", IncreaseBalance(state, test.i, test.nb))
TestIncreaseBalance_OK
		require.NoError(t, IncreaseBalance(state, test.i, test.nb))
/home/mezin/go/src/tesseract/beacon-chain/core/validators
validator.go
SlashValidator
	err = helpers.IncreaseBalance(s, proposerIdx, proposerReward)
	err = helpers.IncreaseBalance(s, whistleBlowerIdx, whistleblowerReward-proposerReward)
        
````

### DecreaseBalance

````go
Function
    DecreaseBalance
Usages in Project and Libraries
Unclassified
.workspace
/home/mezin/go/src/tesseract/beacon-chain/core/altair
block.go
ApplySyncRewardsPenalties
		if err := helpers.DecreaseBalance(s, index, participantReward); err != nil {
/home/mezin/go/src/tesseract/beacon-chain/core/epoch
epoch_processing.go
ProcessSlashings
			if err := helpers.DecreaseBalance(state, types.ValidatorIndex(idx), penalty); err != nil {
/home/mezin/go/src/tesseract/beacon-chain/core/epoch/precompute
slashing.go
ProcessSlashingsPrecompute
			if err := helpers.DecreaseBalance(s, types.ValidatorIndex(idx), penalty); err != nil {
/home/mezin/go/src/tesseract/beacon-chain/core/helpers
rewards_penalties_test.go
TestDecreaseBalance_OK
		require.NoError(t, DecreaseBalance(state, test.i, test.nb))
/home/mezin/go/src/tesseract/beacon-chain/core/validators
validator.go
SlashValidator
	if err := helpers.DecreaseBalance(s, slashedIdx, validator.EffectiveBalance/penaltyQuotient); err != nil {
````


### Balance struct

````go
// Balance stores the pre computation of the total participated balances for a given epoch
// Pre computing and storing such record is essential for process epoch optimizations.
type Balance struct {
	// ActiveCurrentEpoch is the total effective balance of all active validators during current epoch.
	ActiveCurrentEpoch uint64
	// ActivePrevEpoch is the total effective balance of all active validators during prev epoch.
	ActivePrevEpoch uint64
	// CurrentEpochAttested is the total effective balance of all validators who attested during current epoch.
	CurrentEpochAttested uint64
	// CurrentEpochTargetAttested is the total effective balance of all validators who attested
	// for epoch boundary block during current epoch.
	CurrentEpochTargetAttested uint64
	// PrevEpochAttested is the total effective balance of all validators who attested during prev epoch.
	PrevEpochAttested uint64
	// PrevEpochTargetAttested is the total effective balance of all validators who attested
	// for epoch boundary block during prev epoch.
	PrevEpochTargetAttested uint64
	// PrevEpochHeadAttested is the total effective balance of all validators who attested
	// correctly for head block during prev epoch.
	PrevEpochHeadAttested uint64
}
````


