# Tokenomics: Development

# <font color="red">TODO</font>
1. Продумать использование значенией с плавающей точкой
> скорее всего использование `big.Int` или `big.Float`
# Константы
1. Определить в файле `config/params/config.go`
2. Задать значения в файле `config/params/mainnet_config.go`
### стейк для одного координатора
(*уже определен*)
> s = 32000
````go
MaxEffectiveBalance: 32 * 1e9 * 1000,
````
### time of i-th slot in the Coordinating network (sec),
(*уже определен*)
> $t_i^с$ – the time of i-th slot in the Coordinating network (sec), initial value = 4;
````go
SecondsPerSlot: 4,
````
### current optimal number of Coordinators
> 
````go
optimalCoordinatorsNr: 8196
````
### maximum annualized return rate with N<sub>0</sub> Coordinators
> 
````go
optimalMaxAnnualizedRate: 0.20
````
### Shares of Base Slot Reward by roles
Константы пропорций распределения Базовой Награды за слот (BaseSlotReward ) по ролям участников
````go
BsrShareAgregatator: 1/3,
BsrShareProposer: 1/3,
BsrShareAttesters: 1/3,
````
share
# Вычисляемые значения
*Реализовать в хелперах*
### N – the current number of Workers;
уже реализовано, см. `beacon-chain/core/helpers/validators.go:145`
````go
// ActiveValidatorCount returns the number of active validators in the state
// at the given epoch.
func ActiveValidatorCount(ctx context.Context, s state.ReadOnlyBeaconState, epoch types.Epoch) (uint64, error)
````
### maximum annualized return rate with N Coordinators
> $R = {R_0 * \sqrt{N_0 \over N}}$
````go
func MaxAnnualizedRate(ctx context.Context, s state.ReadOnlyBeaconState, epoch types.Epoch) (float64, error){
r_0 := params.BeaconConfig().optimalMaxAnnualizedRate
n_0 := params.BeaconConfig().optimalCoordinatorsNr
n := ActiveValidatorCount()
r := r_0 * math.sqrt(n_0/n)
return r
}
````
### the annualized minted amount
> $V = {R_0 * s * \sqrt{N_0 * N}}$
````go
func AnnualizedMintingAmount(ctx context.Context, s state.ReadOnlyBeaconState, epoch types.Epoch) (uint64, error){
r_0 := params.BeaconConfig().optimalMaxAnnualizedRate
s := params.BeaconConfig().MaxEffectiveBalance
n_0 := params.BeaconConfig().optimalCoordinatorsNr
n := ActiveValidatorCount()
v := r_0 * s * math.sqrt(n_0 * n)
return v
}
````
### slots per year
> $B_i^c={60 * 60 * 24 * 365.25 \over t_i^с}$
````go
func SlotsPerYear() (float64){
yearSec := 60 * 60 * 24 * 365.25
t_c := params.BeaconConfig().SecondsPerSlot
return yearSec / t_c
}
````
### reward per i-th block (Base Slot Reward)
Базовая награда за слот - основа расчета всех остальных наград
> $W = W_i^c = {V\over B_i^с}$
````go
func BaseSlotReward() (float64){
yearSec := 60 * 60 * 24 * 365.25
t_c := params.BeaconConfig().SecondsPerSlot
return yearSec / t_c
}
````
### number of members in committee
*посмотреть целесообразность, может можно и без этой обойтись*
$M$ – the number of members in committee.
````go
func CommitteeLen(ctx context.Context, state state.ReadOnlyBeaconState, slot types.Slot, committeeIndex types.CommitteeIndex) (uint64, error){
// validator indexes of committee
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil {
return 0, err
}
return len(committee), nil
}
````
### number of committees
*уже реализовано*
$L$ – the number of committees.
````go
// SlotCommitteeCount returns the number of beacon committees of a slot. The
// active validator count is provided as an argument rather than an imported implementation
// from the spec definition. Having the active validator count as an argument allows for
// cheaper computation, instead of retrieving head state, one can retrieve the validator
// count.
func SlotCommitteeCount(activeValidatorCount uint64) uint64 {
var committeesPerSlot = activeValidatorCount / uint64(params.BeaconConfig().SlotsPerEpoch) / params.BeaconConfig().TargetCommitteeSize
if committeesPerSlot > params.BeaconConfig().MaxCommitteesPerSlot {
return params.BeaconConfig().MaxCommitteesPerSlot
}
if committeesPerSlot == 0 {
return 1
}
return committeesPerSlot
}
````
# награда за создание блока в координирующей сети
>Лидер слота выбирается среди членов комитета.
> $rwd = {W \over 3} * 𝛾_2$
> – the base reward of a slot leader,
> $𝛾_2 \in (0,1]$ - a ratio of included aggregators’ messages.
###### на рассмотрение:
> $𝛾_2$ - расчитываем следующим образом:
> $𝛾_2 = {\sum_{i=0}^n (T_i + S_i + H_i) \over M * 3}$
где:
$T_i$ - таргет-аттестация
$S_i$ - сорс-аттестация
$H_i$ - хед-аттестация
$M$ – the number of members per committee.
$3$ - кол-во типов аттестаций ($T_i, S_i, H_i$) за которые начисляются поинты
Лидер слота - Proposer
Имплементировать в
````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(...) ... {
...
// validator indexes of committee
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.Data.Slot, att.Data.CommitteeIndex)
...
//RM depracated
// return SetParticipationAndRewardProposer(ctx, beaconState, att.Data.Target.Epoch, indices, participatedFlags, totalBalance)
return SetParticipationAndRewardProposer(ctx, beaconState, att.Data.Target.Epoch, indices, committee, participatedFlags, totalBalance)
}
````
````go
// SetParticipationAndRewardProposer retrieves and sets the epoch participation bits in state. Based on the epoch participation, it rewards
// the proposer in state.
func SetParticipationAndRewardProposer(
ctx context.Context,
beaconState state.BeaconState,
targetEpoch types.Epoch,
indices []uint64,
committee []types.ValidatorIndex, // add new param
participatedFlags map[uint8]bool, totalBalance uint64) (state.BeaconState, error) {
// effective attestations count
// io proposerRewardNumerator
var attsCount uint64
// var proposerRewardNumerator uint64
...
if targetEpoch == currentEpoch {
stateErr = beaconState.ModifyCurrentParticipationBits(func(val []byte) ([]byte, error) {
// propRewardNum, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
attCnt, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
...
// proposerRewardNumerator = propRewardNum
attsCount = attCnt
return epochParticipation, nil
})
} else {
stateErr = beaconState.ModifyPreviousParticipationBits(func(val []byte) ([]byte, error) {
// propRewardNum, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
attCnt, epochParticipation, err := EpochParticipation(beaconState, indices, val, participatedFlags, totalBalance)
...
// proposerRewardNumerator = propRewardNum
attsCount = attCnt
return epochParticipation, nil
})
}
/*RM depracated
if err := RewardProposer(ctx, beaconState, proposerRewardNumerator); err != nil {
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return nil, err
}
*/
var attsRewardRate float64 = attsCount/(len(committee) * 3)
if err := RewardProposer(ctx, beaconState, attsRate); err != nil {
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return nil, err
}
return beaconState, nil
}
````
````go
// EpochParticipation sets and returns the proposer reward numerator and epoch participation.
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)
// io proposerRewardNumerator
attCnt := := 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
}
attCnt++
// 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
}
attCnt++
// proposerRewardNumerator += br * cfg.TimelyTargetWeight
}
has, err = HasValidatorFlag(epochParticipation[index], headFlagIndex)
if participatedFlags[headFlagIndex] && !has {
epochParticipation[index], err = AddValidatorFlag(epochParticipation[index], headFlagIndex)
...
attCnt++
// proposerRewardNumerator += br * cfg.TimelyHeadWeight
}
}
//RM depracated
//return proposerRewardNumerator, epochParticipation, nil
return attCnt, epochParticipation, nil
}
````
````go
// RewardProposer rewards proposer by increasing proposer's balance
// func RewardProposer(ctx context.Context, beaconState state.BeaconState, proposerRewardNumerator uint64) error {
func RewardProposer(ctx context.Context, beaconState state.BeaconState uint64, attsRewardRate float64) error {
/* RM depracated
cfg := params.BeaconConfig()
d := (cfg.WeightDenominator - cfg.ProposerWeight) * cfg.WeightDenominator / cfg.ProposerWeight
proposerReward := proposerRewardNumerator / d
*/
bsr := helper.BaseSlotReward()
proposerReward := bsr * params.BeaconConfig().BsrShareProposer * attsRewardRate
i, err := helpers.BeaconProposerIndex(ctx, beaconState)
if err != nil {
return err
}
return helpers.IncreaseBalance(beaconState, i, proposerReward)
}
````
# награда за агрегацию аттестаций в координирующей сети
> $L$ – the number of committees.
Агрегатор выбирается среди членов своего комитета.
W3L1 – the base reward of a committee aggregator, 1(2/3,1], where $1 \in (2/3,1]$ is a ratio of included committee members’ signatures to the committee size M.
Агрегатор - роль агрегатора выполняет Proposer.
````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)
*/
// 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
}
````