Total balance refactor to big.Int

This commit is contained in:
aggris2 2022-11-02 18:16:18 +00:00 committed by Shane Bammel
parent cca294cba1
commit b3b42448a5
56 changed files with 841 additions and 500 deletions

View File

@ -2,6 +2,7 @@ package blockchain
import (
"context"
"strconv"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
@ -353,10 +354,26 @@ func reportEpochMetrics(ctx context.Context, postState, headState state.BeaconSt
return errors.Errorf("invalid state type provided: %T", headState.ToProtoUnsafe())
}
prevEpochActiveBalances.Set(float64(b.ActivePrevEpoch))
prevEpochSourceBalances.Set(float64(b.PrevEpochAttested))
prevEpochTargetBalances.Set(float64(b.PrevEpochTargetAttested))
prevEpochHeadBalances.Set(float64(b.PrevEpochHeadAttested))
parsedActivePrevEpoch, err := strconv.ParseFloat(b.ActivePrevEpoch.String(), 64)
if err != nil {
parsedActivePrevEpoch = float64(0)
}
parsedPrevEpochAttested, err := strconv.ParseFloat(b.PrevEpochAttested.String(), 64)
if err != nil {
parsedPrevEpochAttested = float64(0)
}
parsedPrevEpochTargetAttested, err := strconv.ParseFloat(b.PrevEpochTargetAttested.String(), 64)
if err != nil {
parsedPrevEpochTargetAttested = float64(0)
}
parsedPrevEpochHeadAttested, err := strconv.ParseFloat(b.PrevEpochHeadAttested.String(), 64)
if err != nil {
parsedPrevEpochHeadAttested = float64(0)
}
prevEpochActiveBalances.Set(parsedActivePrevEpoch)
prevEpochSourceBalances.Set(parsedPrevEpochAttested)
prevEpochTargetBalances.Set(parsedPrevEpochTargetAttested)
prevEpochHeadBalances.Set(parsedPrevEpochHeadAttested)
refMap := postState.FieldReferencesCount()
for name, val := range refMap {

View File

@ -5,6 +5,7 @@ package testing
import (
"bytes"
"context"
"math/big"
"sync"
"time"
@ -370,7 +371,7 @@ func (s *ChainService) CurrentSlot() primitives.Slot {
}
// Participation mocks the same method in the chain service.
func (s *ChainService) Participation(_ uint64) *precompute.Balance {
func (s *ChainService) Participation(_ *big.Int) *precompute.Balance {
return s.Balance
}

View File

@ -4,6 +4,7 @@ package cache
import (
"encoding/binary"
"math/big"
"sync"
lru "github.com/hashicorp/golang-lru"
@ -55,7 +56,7 @@ func (c *BalanceCache) Clear() {
}
// AddTotalEffectiveBalance adds a new total effective balance entry for current balance for state `st` into the cache.
func (c *BalanceCache) AddTotalEffectiveBalance(st state.ReadOnlyBeaconState, balance uint64) error {
func (c *BalanceCache) AddTotalEffectiveBalance(st state.ReadOnlyBeaconState, balance *big.Int) error {
key, err := balanceCacheKey(st)
if err != nil {
return err
@ -69,10 +70,11 @@ func (c *BalanceCache) AddTotalEffectiveBalance(st state.ReadOnlyBeaconState, ba
}
// Get returns the current epoch's effective balance for state `st` in cache.
func (c *BalanceCache) Get(st state.ReadOnlyBeaconState) (uint64, error) {
func (c *BalanceCache) Get(st state.ReadOnlyBeaconState) (*big.Int, error) {
key, err := balanceCacheKey(st)
zero := big.NewInt(0)
if err != nil {
return 0, err
return zero, err
}
c.lock.RLock()
@ -81,10 +83,10 @@ func (c *BalanceCache) Get(st state.ReadOnlyBeaconState) (uint64, error) {
value, exists := c.cache.Get(key)
if !exists {
balanceCacheMiss.Inc()
return 0, ErrNotFound
return zero, ErrNotFound
}
balanceCacheHit.Inc()
return value.(uint64), nil
return value.(*big.Int), nil
}
// Given input state `st`, balance key is constructed as:

View File

@ -5,6 +5,7 @@ package cache
import (
"encoding/binary"
"math"
"math/big"
"testing"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
@ -31,7 +32,7 @@ func TestBalanceCache_AddGetBalance(t *testing.T) {
_, err = cache.Get(st)
require.ErrorContains(t, ErrNotFound.Error(), err)
b := uint64(100)
b := big.NewInt(100)
require.NoError(t, cache.AddTotalEffectiveBalance(st, b))
cachedB, err := cache.Get(st)
require.NoError(t, err)
@ -41,7 +42,7 @@ func TestBalanceCache_AddGetBalance(t *testing.T) {
_, err = cache.Get(st)
require.ErrorContains(t, ErrNotFound.Error(), err)
b = uint64(200)
b = big.NewInt(200)
require.NoError(t, cache.AddTotalEffectiveBalance(st, b))
cachedB, err = cache.Get(st)
require.NoError(t, err)
@ -51,7 +52,7 @@ func TestBalanceCache_AddGetBalance(t *testing.T) {
_, err = cache.Get(st)
require.ErrorContains(t, ErrNotFound.Error(), err)
b = uint64(300)
b = big.NewInt(300)
require.NoError(t, cache.AddTotalEffectiveBalance(st, b))
cachedB, err = cache.Get(st)
require.NoError(t, err)

View File

@ -4,6 +4,7 @@ import (
"bytes"
"context"
"fmt"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
@ -49,7 +50,7 @@ func ProcessAttestationNoVerifySignature(
ctx context.Context,
beaconState state.BeaconState,
att *ethpb.Attestation,
totalBalance uint64,
totalBalance *big.Int,
) (state.BeaconState, error) {
ctx, span := trace.StartSpan(ctx, "altair.ProcessAttestationNoVerifySignature")
defer span.End()
@ -105,7 +106,7 @@ func SetParticipationAndRewardProposer(
beaconState state.BeaconState,
targetEpoch primitives.Epoch,
indices []uint64,
participatedFlags map[uint8]bool, totalBalance uint64) (state.BeaconState, error) {
participatedFlags map[uint8]bool, totalBalance *big.Int) (state.BeaconState, error) {
var proposerRewardNumerator uint64
currentEpoch := time.CurrentEpoch(beaconState)
var stateErr error
@ -165,7 +166,7 @@ func AddValidatorFlag(flag, flagPosition uint8) (uint8, error) {
// 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) {
func EpochParticipation(beaconState state.BeaconState, indices []uint64, epochParticipation []byte, participatedFlags map[uint8]bool, totalBalance *big.Int) (uint64, []byte, error) {
cfg := params.BeaconConfig()
sourceFlagIndex := cfg.TimelySourceFlagIndex
targetFlagIndex := cfg.TimelyTargetFlagIndex

View File

@ -512,9 +512,10 @@ func TestSetParticipationAndRewardProposer(t *testing.T) {
i, err := helpers.BeaconProposerIndex(context.Background(), st)
require.NoError(t, err)
b, err = beaconState.BalanceAtIndex(i)
var bal uint64
bal, err = beaconState.BalanceAtIndex(i)
require.NoError(t, err)
require.Equal(t, test.wantedBalance, b)
require.Equal(t, test.wantedBalance, bal)
if test.epoch == currentEpoch {
p, err := beaconState.CurrentEpochParticipation()

View File

@ -2,6 +2,7 @@ package altair
import (
"context"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
@ -148,13 +149,13 @@ func VerifySyncCommitteeSig(s state.BeaconState, syncKeys []bls.PublicKey, syncS
}
// 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) {
func SyncRewards(activeBalance *big.Int) (proposerReward, participantReward uint64, err error) {
cfg := params.BeaconConfig()
totalActiveIncrements := activeBalance / cfg.EffectiveBalanceIncrement
baseRewardPerInc, err := BaseRewardPerIncrement(activeBalance)
if err != nil {
return 0, 0, err
}
totalActiveIncrements := new(big.Int).Div(activeBalance, new(big.Int).SetUint64(cfg.EffectiveBalanceIncrement)).Uint64()
totalBaseRewards := baseRewardPerInc * totalActiveIncrements
maxParticipantRewards := totalBaseRewards * cfg.SyncRewardWeight / cfg.WeightDenominator / uint64(cfg.SlotsPerEpoch)
participantReward = maxParticipantRewards / cfg.SyncCommitteeSize

View File

@ -3,6 +3,7 @@ package altair_test
import (
"context"
"math"
"math/big"
"testing"
"github.com/prysmaticlabs/go-bitfield"
@ -290,49 +291,49 @@ func Test_VerifySyncCommitteeSig(t *testing.T) {
func Test_SyncRewards(t *testing.T) {
tests := []struct {
name string
activeBalance uint64
activeBalance *big.Int
wantProposerReward uint64
wantParticipantReward uint64
errString string
}{
{
name: "active balance is 0",
activeBalance: 0,
activeBalance: big.NewInt(0),
wantProposerReward: 0,
wantParticipantReward: 0,
errString: "active balance can't be 0",
},
{
name: "active balance is 1",
activeBalance: 1,
activeBalance: big.NewInt(1),
wantProposerReward: 0,
wantParticipantReward: 0,
errString: "",
},
{
name: "active balance is 1eth",
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement),
wantProposerReward: 0,
wantParticipantReward: 3,
errString: "",
},
{
name: "active balance is 32eth",
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance),
wantProposerReward: 3,
wantParticipantReward: 21,
errString: "",
},
{
name: "active balance is 32eth * 1m validators",
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance * 1e9),
wantProposerReward: 62780,
wantParticipantReward: 439463,
errString: "",
},
{
name: "active balance is max uint64",
activeBalance: math.MaxUint64,
activeBalance: new(big.Int).SetUint64(math.MaxUint64),
wantProposerReward: 70368,
wantParticipantReward: 492581,
errString: "",

View File

@ -2,6 +2,7 @@ package altair
import (
"context"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute"
@ -28,7 +29,7 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
_, span := trace.StartSpan(ctx, "altair.InitializePrecomputeValidators")
defer span.End()
vals := make([]*precompute.Validator, beaconState.NumValidators())
bal := &precompute.Balance{}
bal := precompute.NewBalance()
prevEpoch := time.PrevEpoch(beaconState)
currentEpoch := time.CurrentEpoch(beaconState)
inactivityScores, err := beaconState.InactivityScores()
@ -43,6 +44,7 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
}
if err := beaconState.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
// Set validator's balance, inactivity score and slashed/withdrawable status.
effectiveBalance := new(big.Int).SetUint64(val.EffectiveBalance())
v := &precompute.Validator{
CurrentEpochEffectiveBalance: val.EffectiveBalance(),
InactivityScore: inactivityScores[idx],
@ -52,18 +54,12 @@ func InitializePrecomputeValidators(ctx context.Context, beaconState state.Beaco
// Set validator's active status for current epoch.
if helpers.IsActiveValidatorUsingTrie(val, currentEpoch) {
v.IsActiveCurrentEpoch = true
bal.ActiveCurrentEpoch, err = math.Add64(bal.ActiveCurrentEpoch, val.EffectiveBalance())
if err != nil {
return err
}
bal.ActiveCurrentEpoch.Add(bal.ActiveCurrentEpoch, effectiveBalance)
}
// Set validator's active status for previous epoch.
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
v.IsActivePrevEpoch = true
bal.ActivePrevEpoch, err = math.Add64(bal.ActivePrevEpoch, val.EffectiveBalance())
if err != nil {
return err
}
bal.ActivePrevEpoch.Add(bal.ActivePrevEpoch, effectiveBalance)
}
vals[idx] = v
return nil
@ -274,7 +270,8 @@ func AttestationsDelta(beaconState state.BeaconState, bal *precompute.Balance, v
finalizedEpoch := beaconState.FinalizedCheckpointEpoch()
increment := cfg.EffectiveBalanceIncrement
factor := cfg.BaseRewardFactor
baseRewardMultiplier := increment * factor / math.CachedSquareRoot(bal.ActiveCurrentEpoch)
activeCurrentEpochSqrt := new(big.Int).Sqrt(bal.ActiveCurrentEpoch).Uint64()
baseRewardMultiplier := increment * factor / activeCurrentEpochSqrt
leak := helpers.IsInInactivityLeak(prevEpoch, finalizedEpoch)
// Modified in Altair and Bellatrix.
@ -302,15 +299,15 @@ func attestationDelta(
inactivityLeak bool) (*AttDelta, error) {
eligible := val.IsActivePrevEpoch || (val.IsSlashed && !val.IsWithdrawableCurrentEpoch)
// Per spec `ActiveCurrentEpoch` can't be 0 to process attestation delta.
if !eligible || bal.ActiveCurrentEpoch == 0 {
if !eligible || bal.ActiveCurrentEpoch.Cmp(big.NewInt(0)) == 0 {
return &AttDelta{}, nil
}
cfg := params.BeaconConfig()
increment := cfg.EffectiveBalanceIncrement
increment := new(big.Int).SetUint64(cfg.EffectiveBalanceIncrement)
effectiveBalance := val.CurrentEpochEffectiveBalance
baseReward := (effectiveBalance / increment) * baseRewardMultiplier
activeIncrement := bal.ActiveCurrentEpoch / increment
baseReward := (effectiveBalance / cfg.EffectiveBalanceIncrement) * baseRewardMultiplier
activeIncrement := new(big.Int).Div(bal.ActiveCurrentEpoch, increment).Uint64()
weightDenominator := cfg.WeightDenominator
srcWeight := cfg.TimelySourceWeight
@ -320,7 +317,7 @@ func attestationDelta(
// Process source reward / penalty
if val.IsPrevEpochSourceAttester && !val.IsSlashed {
if !inactivityLeak {
n := baseReward * srcWeight * (bal.PrevEpochAttested / increment)
n := baseReward * srcWeight * (new(big.Int).Div(bal.PrevEpochAttested, increment)).Uint64()
attDelta.SourceReward += n / (activeIncrement * weightDenominator)
}
} else {
@ -330,7 +327,7 @@ func attestationDelta(
// Process target reward / penalty
if val.IsPrevEpochTargetAttester && !val.IsSlashed {
if !inactivityLeak {
n := baseReward * tgtWeight * (bal.PrevEpochTargetAttested / increment)
n := baseReward * tgtWeight * (new(big.Int).Div(bal.PrevEpochTargetAttested, increment)).Uint64()
attDelta.TargetReward += n / (activeIncrement * weightDenominator)
}
} else {
@ -340,7 +337,7 @@ func attestationDelta(
// Process head reward / penalty
if val.IsPrevEpochHeadAttester && !val.IsSlashed {
if !inactivityLeak {
n := baseReward * headWeight * (bal.PrevEpochHeadAttested / increment)
n := baseReward * headWeight * (new(big.Int).Div(bal.PrevEpochHeadAttested, increment)).Uint64()
attDelta.HeadReward += n / (activeIncrement * weightDenominator)
}
}

View File

@ -3,6 +3,7 @@ package altair
import (
"context"
"math"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute"
@ -56,10 +57,10 @@ func TestInitializeEpochValidators_Ok(t *testing.T) {
InactivityScore: 3,
}, v[3], "Incorrect validator 3 status")
wantedBalances := &precompute.Balance{
ActiveCurrentEpoch: 100,
ActivePrevEpoch: 200,
}
wantedBalances := precompute.NewBalance()
wantedBalances.ActiveCurrentEpoch = big.NewInt(100)
wantedBalances.ActivePrevEpoch = big.NewInt(200)
assert.DeepEqual(t, wantedBalances, b, "Incorrect wanted balance")
}
@ -75,7 +76,8 @@ func TestInitializeEpochValidators_Overflow(t *testing.T) {
})
require.NoError(t, err)
_, _, err = InitializePrecomputeValidators(context.Background(), s)
require.ErrorContains(t, "could not read every validator: addition overflows", err)
// This no longer overflows as total balance is big.int
require.NoError(t, err)
}
func TestInitializeEpochValidators_BadState(t *testing.T) {
@ -133,10 +135,10 @@ func TestProcessEpochParticipation(t *testing.T) {
IsPrevEpochTargetAttester: true,
IsPrevEpochHeadAttester: true,
}, validators[3])
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance*3, balance.PrevEpochAttested)
require.Equal(t, balance.CurrentEpochTargetAttested, params.BeaconConfig().MaxEffectiveBalance*2)
require.Equal(t, balance.PrevEpochTargetAttested, params.BeaconConfig().MaxEffectiveBalance*2)
require.Equal(t, balance.PrevEpochHeadAttested, params.BeaconConfig().MaxEffectiveBalance*1)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance*3, balance.PrevEpochAttested.Uint64())
require.Equal(t, balance.CurrentEpochTargetAttested.Uint64(), params.BeaconConfig().MaxEffectiveBalance*2)
require.Equal(t, balance.PrevEpochTargetAttested.Uint64(), params.BeaconConfig().MaxEffectiveBalance*2)
require.Equal(t, balance.PrevEpochHeadAttested.Uint64(), params.BeaconConfig().MaxEffectiveBalance*1)
}
func TestProcessEpochParticipation_InactiveValidator(t *testing.T) {
@ -200,10 +202,10 @@ func TestProcessEpochParticipation_InactiveValidator(t *testing.T) {
IsPrevEpochTargetAttester: true,
IsPrevEpochHeadAttester: true,
}, validators[2])
require.Equal(t, balance.PrevEpochAttested, 2*params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.CurrentEpochTargetAttested, params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.PrevEpochTargetAttested, 2*params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.PrevEpochHeadAttested, params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.PrevEpochAttested.Uint64(), 2*params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.CurrentEpochTargetAttested.Uint64(), params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.PrevEpochTargetAttested.Uint64(), 2*params.BeaconConfig().MaxEffectiveBalance)
require.Equal(t, balance.PrevEpochHeadAttested.Uint64(), params.BeaconConfig().MaxEffectiveBalance)
}
func TestAttestationsDelta(t *testing.T) {

View File

@ -1,12 +1,13 @@
package altair
import (
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
)
// BaseReward takes state and validator index and calculate
@ -33,7 +34,7 @@ func BaseReward(s state.ReadOnlyBeaconState, index primitives.ValidatorIndex) (u
}
// BaseRewardWithTotalBalance calculates the base reward with the provided total balance.
func BaseRewardWithTotalBalance(s state.ReadOnlyBeaconState, index primitives.ValidatorIndex, totalBalance uint64) (uint64, error) {
func BaseRewardWithTotalBalance(s state.ReadOnlyBeaconState, index primitives.ValidatorIndex, totalBalance *big.Int) (uint64, error) {
val, err := s.ValidatorAtIndexReadOnly(index)
if err != nil {
return 0, err
@ -53,10 +54,11 @@ func BaseRewardWithTotalBalance(s state.ReadOnlyBeaconState, index primitives.Va
// 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 {
func BaseRewardPerIncrement(activeBalance *big.Int) (uint64, error) {
if activeBalance.Cmp(big.NewInt(0)) == 0 {
return 0, errors.New("active balance can't be 0")
}
cfg := params.BeaconConfig()
return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / math.CachedSquareRoot(activeBalance), nil
activeBalanceSqrt := new(big.Int).Sqrt(activeBalance).Uint64()
return cfg.EffectiveBalanceIncrement * cfg.BaseRewardFactor / activeBalanceSqrt, nil
}

View File

@ -2,6 +2,7 @@ package altair_test
import (
"math"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
@ -73,56 +74,56 @@ func Test_BaseRewardWithTotalBalance(t *testing.T) {
tests := []struct {
name string
valIdx primitives.ValidatorIndex
activeBalance uint64
activeBalance *big.Int
want uint64
errString string
}{
{
name: "active balance is 0",
valIdx: 0,
activeBalance: 0,
activeBalance: big.NewInt(0),
want: 0,
errString: "active balance can't be 0",
},
{
name: "unknown validator",
valIdx: 2,
activeBalance: 1,
activeBalance: big.NewInt(1),
want: 0,
errString: "validator index 2 does not exist",
},
{
name: "active balance is 1",
valIdx: 0,
activeBalance: 1,
activeBalance: big.NewInt(1),
want: 2048000000000,
errString: "",
},
{
name: "active balance is 1eth",
valIdx: 0,
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement),
want: 64765024,
errString: "",
},
{
name: "active balance is 32eth",
valIdx: 0,
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance),
want: 11448672,
errString: "",
},
{
name: "active balance is 32eth * 1m validators",
valIdx: 0,
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance * 1e9),
want: 544,
errString: "",
},
{
name: "active balance is max uint64",
valIdx: 0,
activeBalance: math.MaxUint64,
activeBalance: new(big.Int).SetUint64(math.MaxUint64),
want: 448,
errString: "",
},
@ -143,43 +144,43 @@ func Test_BaseRewardPerIncrement(t *testing.T) {
helpers.ClearCache()
tests := []struct {
name string
activeBalance uint64
activeBalance *big.Int
want uint64
errString string
}{
{
name: "active balance is 0",
activeBalance: 0,
activeBalance: big.NewInt(0),
want: 0,
errString: "active balance can't be 0",
},
{
name: "active balance is 1",
activeBalance: 1,
activeBalance: big.NewInt(1),
want: 64000000000,
errString: "",
},
{
name: "active balance is 1eth",
activeBalance: params.BeaconConfig().EffectiveBalanceIncrement,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement),
want: 2023907,
errString: "",
},
{
name: "active balance is 32eth",
activeBalance: params.BeaconConfig().MaxEffectiveBalance,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance),
want: 357771,
errString: "",
},
{
name: "active balance is 32eth * 1m validators",
activeBalance: params.BeaconConfig().MaxEffectiveBalance * 1e9,
activeBalance: new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance * 1e9),
want: 17,
errString: "",
},
{
name: "active balance is max uint64",
activeBalance: math.MaxUint64,
activeBalance: new(big.Int).SetUint64(math.MaxUint64),
want: 14,
errString: "",
},

View File

@ -4,6 +4,7 @@ import (
"context"
goErrors "errors"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
@ -139,8 +140,9 @@ func NextSyncCommitteeIndices(ctx context.Context, s state.BeaconState) ([]primi
return nil, err
}
effectiveBal := v.EffectiveBalance()
if effectiveBal*maxRandomByte >= cfg.MaxEffectiveBalance*uint64(randomByte) {
effectiveBal := new(big.Int).SetUint64(v.EffectiveBalance())
effectiveBal.Mul(effectiveBal, new(big.Int).SetUint64(maxRandomByte))
if effectiveBal.Cmp(new(big.Int).SetUint64(cfg.MaxEffectiveBalance*uint64(randomByte))) != -1 {
cIndices = append(cIndices, cIndex)
}
}

View File

@ -7,6 +7,7 @@ package epoch
import (
"context"
"fmt"
"math/big"
"sort"
"github.com/pkg/errors"
@ -59,10 +60,10 @@ func (s sortableIndices) Less(i, j int) bool {
// Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
// """
// return get_total_balance(state, get_unslashed_attesting_indices(state, attestations))
func AttestingBalance(ctx context.Context, state state.ReadOnlyBeaconState, atts []*ethpb.PendingAttestation) (uint64, error) {
func AttestingBalance(ctx context.Context, state state.ReadOnlyBeaconState, atts []*ethpb.PendingAttestation) (*big.Int, error) {
indices, err := UnslashedAttestingIndices(ctx, state, atts)
if err != nil {
return 0, errors.Wrap(err, "could not get attesting indices")
return big.NewInt(0), errors.Wrap(err, "could not get attesting indices")
}
return helpers.TotalBalance(state, indices), nil
}
@ -196,14 +197,23 @@ func ProcessSlashings(state state.BeaconState, slashingMultiplier uint64) (state
// 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)
increment := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
totalSlashingTimesMultiplier := new(big.Int).SetUint64(totalSlashing * slashingMultiplier)
minSlashing := totalBalance
if totalSlashingTimesMultiplier.Cmp(totalBalance) == -1 {
minSlashing = totalSlashingTimesMultiplier
} else {
minSlashing = 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, primitives.ValidatorIndex(idx), penalty); err != nil {
penalty := new(big.Int).SetUint64(val.EffectiveBalance) // val.EffectiveBalance
penalty.Div(penalty, increment) // val.EffectiveBalance / increment
penalty.Mul(penalty, minSlashing) // penaltyNumerator = val.EffectiveBalance / increment * minSlashing
penalty.Div(penalty, totalBalance) // penaltyNumerator / totalBalance
penalty = penalty.Mul(penalty, increment) // penalty = penaltyNumerator / totalBalance * increment
if err := helpers.DecreaseBalance(state, primitives.ValidatorIndex(idx), penalty.Uint64()); err != nil {
return false, val, err
}
return true, val, nil

View File

@ -146,7 +146,7 @@ func TestAttestingBalance_CorrectBalance(t *testing.T) {
balance, err := epoch.AttestingBalance(context.Background(), beaconState, atts)
require.NoError(t, err)
wanted := 256 * params.BeaconConfig().MaxEffectiveBalance
assert.Equal(t, wanted, balance)
assert.Equal(t, wanted, balance.Uint64())
}
func TestProcessSlashings_NotSlashed(t *testing.T) {

View File

@ -22,7 +22,6 @@ go_library(
"//beacon-chain/state:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//math:go_default_library",
"//monitoring/tracing:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
@ -55,7 +54,6 @@ go_test(
"//config/fieldparams:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//math:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//runtime/version:go_default_library",

View File

@ -3,6 +3,7 @@ package precompute
import (
"bytes"
"context"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
@ -174,23 +175,24 @@ func UpdateValidator(vp []*Validator, record *Validator, indices []uint64, a *et
func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
for _, v := range vp {
if !v.IsSlashed {
currentEpochEffectiveBalance := new(big.Int).SetUint64(v.CurrentEpochEffectiveBalance)
if v.IsCurrentEpochAttester {
bBal.CurrentEpochAttested += v.CurrentEpochEffectiveBalance
bBal.CurrentEpochAttested.Add(bBal.CurrentEpochAttested, currentEpochEffectiveBalance)
}
if v.IsCurrentEpochTargetAttester {
bBal.CurrentEpochTargetAttested += v.CurrentEpochEffectiveBalance
bBal.CurrentEpochTargetAttested.Add(bBal.CurrentEpochTargetAttested, currentEpochEffectiveBalance)
}
if stateVersion == version.Phase0 && v.IsPrevEpochAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
bBal.PrevEpochAttested.Add(bBal.PrevEpochAttested, currentEpochEffectiveBalance)
}
if stateVersion >= version.Altair && v.IsPrevEpochSourceAttester {
bBal.PrevEpochAttested += v.CurrentEpochEffectiveBalance
bBal.PrevEpochAttested.Add(bBal.PrevEpochAttested, currentEpochEffectiveBalance)
}
if v.IsPrevEpochTargetAttester {
bBal.PrevEpochTargetAttested += v.CurrentEpochEffectiveBalance
bBal.PrevEpochTargetAttested.Add(bBal.PrevEpochTargetAttested, currentEpochEffectiveBalance)
}
if v.IsPrevEpochHeadAttester {
bBal.PrevEpochHeadAttested += v.CurrentEpochEffectiveBalance
bBal.PrevEpochHeadAttested.Add(bBal.PrevEpochHeadAttested, currentEpochEffectiveBalance)
}
}
}
@ -202,26 +204,27 @@ func UpdateBalance(vp []*Validator, bBal *Balance, stateVersion int) *Balance {
// have EffectiveBalanceIncrement(1 eth) as a lower bound.
func EnsureBalancesLowerBound(bBal *Balance) *Balance {
ebi := params.BeaconConfig().EffectiveBalanceIncrement
if ebi > bBal.ActiveCurrentEpoch {
bBal.ActiveCurrentEpoch = ebi
ebiBig := new(big.Int).SetUint64(ebi)
if ebiBig.Cmp(bBal.ActiveCurrentEpoch) == 1 {
bBal.ActiveCurrentEpoch = ebiBig
}
if ebi > bBal.ActivePrevEpoch {
bBal.ActivePrevEpoch = ebi
if ebiBig.Cmp(bBal.ActivePrevEpoch) == 1 {
bBal.ActivePrevEpoch = ebiBig
}
if ebi > bBal.CurrentEpochAttested {
bBal.CurrentEpochAttested = ebi
if ebiBig.Cmp(bBal.CurrentEpochAttested) == 1 {
bBal.CurrentEpochAttested = ebiBig
}
if ebi > bBal.CurrentEpochTargetAttested {
bBal.CurrentEpochTargetAttested = ebi
if ebiBig.Cmp(bBal.CurrentEpochTargetAttested) == 1 {
bBal.CurrentEpochTargetAttested = ebiBig
}
if ebi > bBal.PrevEpochAttested {
bBal.PrevEpochAttested = ebi
if ebiBig.Cmp(bBal.PrevEpochAttested) == 1 {
bBal.PrevEpochAttested = ebiBig
}
if ebi > bBal.PrevEpochTargetAttested {
bBal.PrevEpochTargetAttested = ebi
if ebiBig.Cmp(bBal.PrevEpochTargetAttested) == 1 {
bBal.PrevEpochTargetAttested = ebiBig
}
if ebi > bBal.PrevEpochHeadAttested {
bBal.PrevEpochHeadAttested = ebi
if ebiBig.Cmp(bBal.PrevEpochHeadAttested) == 1 {
bBal.PrevEpochHeadAttested = ebiBig
}
return bBal
}

View File

@ -2,6 +2,7 @@ package precompute_test
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/go-bitfield"
@ -47,6 +48,10 @@ func TestUpdateValidator_InclusionOnlyCountsPrevEpoch(t *testing.T) {
}
func TestUpdateBalance(t *testing.T) {
ebi := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
ebiTimesHundred := big.NewInt(100).Mul(big.NewInt(100), ebi)
ebiTimesTwoHundred := big.NewInt(200).Mul(big.NewInt(200), ebi)
ebiTimesThreeHundred := big.NewInt(300).Mul(big.NewInt(300), ebi)
vp := []*precompute.Validator{
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
@ -58,19 +63,23 @@ func TestUpdateBalance(t *testing.T) {
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
}
wantedPBal := &precompute.Balance{
ActiveCurrentEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
ActivePrevEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochAttested: 300 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
ActiveCurrentEpoch: ebi,
ActivePrevEpoch: ebi,
CurrentEpochAttested: ebiTimesTwoHundred,
CurrentEpochTargetAttested: ebiTimesTwoHundred,
PrevEpochAttested: ebiTimesThreeHundred,
PrevEpochTargetAttested: ebiTimesHundred,
PrevEpochHeadAttested: ebiTimesTwoHundred,
}
pBal := precompute.UpdateBalance(vp, &precompute.Balance{}, version.Phase0)
pBal := precompute.NewBalance()
pBal = precompute.UpdateBalance(vp, pBal, version.Phase0)
assert.DeepEqual(t, wantedPBal, pBal, "Incorrect balance calculations")
}
func TestUpdateBalanceDifferentVersions(t *testing.T) {
ebi := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
ebiTimesHundred := big.NewInt(100).Mul(big.NewInt(100), ebi)
ebiTimesTwoHundred := big.NewInt(200).Mul(big.NewInt(200), ebi)
vp := []*precompute.Validator{
{IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
{IsCurrentEpochTargetAttester: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
@ -82,18 +91,19 @@ func TestUpdateBalanceDifferentVersions(t *testing.T) {
{IsSlashed: true, IsCurrentEpochAttester: true, CurrentEpochEffectiveBalance: 100 * params.BeaconConfig().EffectiveBalanceIncrement},
}
wantedPBal := &precompute.Balance{
ActiveCurrentEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
ActivePrevEpoch: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochAttested: params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochTargetAttested: 100 * params.BeaconConfig().EffectiveBalanceIncrement,
PrevEpochHeadAttested: 200 * params.BeaconConfig().EffectiveBalanceIncrement,
ActiveCurrentEpoch: ebi,
ActivePrevEpoch: ebi,
CurrentEpochAttested: ebiTimesTwoHundred,
CurrentEpochTargetAttested: ebiTimesTwoHundred,
PrevEpochAttested: ebi,
PrevEpochTargetAttested: ebiTimesHundred,
PrevEpochHeadAttested: ebiTimesTwoHundred,
}
pBal := precompute.UpdateBalance(vp, &precompute.Balance{}, version.Bellatrix)
pBal := precompute.NewBalance()
pBal = precompute.UpdateBalance(vp, pBal, version.Bellatrix)
assert.DeepEqual(t, wantedPBal, pBal, "Incorrect balance calculations")
pBal = precompute.UpdateBalance(vp, &precompute.Balance{}, version.Capella)
pBal = precompute.UpdateBalance(vp, precompute.NewBalance(), version.Capella)
assert.DeepEqual(t, wantedPBal, pBal, "Incorrect balance calculations")
}
@ -178,6 +188,7 @@ func TestProcessAttestations(t *testing.T) {
params.OverrideBeaconConfig(params.MinimalSpecConfig())
validators := uint64(128)
pBal := precompute.NewBalance()
beaconState, _ := util.DeterministicGenesisState(t, validators)
require.NoError(t, beaconState.SetSlot(params.BeaconConfig().SlotsPerEpoch))
c := helpers.SlotCommitteeCount(validators)
@ -206,7 +217,7 @@ func TestProcessAttestations(t *testing.T) {
for i := 0; i < len(pVals); i++ {
pVals[i] = &precompute.Validator{CurrentEpochEffectiveBalance: 100}
}
pVals, _, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, &precompute.Balance{})
pVals, _, err = precompute.ProcessAttestations(context.Background(), beaconState, pVals, pBal)
require.NoError(t, err)
committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
@ -230,14 +241,14 @@ func TestProcessAttestations(t *testing.T) {
}
func TestEnsureBalancesLowerBound(t *testing.T) {
b := &precompute.Balance{}
b := precompute.NewBalance()
b = precompute.EnsureBalancesLowerBound(b)
balanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
assert.Equal(t, balanceIncrement, b.ActiveCurrentEpoch, "Did not get wanted active current balance")
assert.Equal(t, balanceIncrement, b.ActivePrevEpoch, "Did not get wanted active previous balance")
assert.Equal(t, balanceIncrement, b.CurrentEpochAttested, "Did not get wanted current attested balance")
assert.Equal(t, balanceIncrement, b.CurrentEpochTargetAttested, "Did not get wanted target attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochAttested, "Did not get wanted prev attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochTargetAttested, "Did not get wanted prev target attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochHeadAttested, "Did not get wanted prev head attested balance")
assert.Equal(t, balanceIncrement, b.ActiveCurrentEpoch.Uint64(), "Did not get wanted active current balance")
assert.Equal(t, balanceIncrement, b.ActivePrevEpoch.Uint64(), "Did not get wanted active previous balance")
assert.Equal(t, balanceIncrement, b.CurrentEpochAttested.Uint64(), "Did not get wanted current attested balance")
assert.Equal(t, balanceIncrement, b.CurrentEpochTargetAttested.Uint64(), "Did not get wanted target attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochAttested.Uint64(), "Did not get wanted prev attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochTargetAttested.Uint64(), "Did not get wanted prev target attested balance")
assert.Equal(t, balanceIncrement, b.PrevEpochHeadAttested.Uint64(), "Did not get wanted prev head attested balance")
}

View File

@ -1,6 +1,8 @@
package precompute
import (
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
@ -69,15 +71,19 @@ func ProcessJustificationAndFinalizationPreCompute(state state.BeaconState, pBal
}
// processJustificationBits processes the justification bits during epoch processing.
func processJustificationBits(state state.BeaconState, totalActiveBalance, prevEpochTargetBalance, currEpochTargetBalance uint64) bitfield.Bitvector4 {
func processJustificationBits(state state.BeaconState, totalActiveBalance, prevEpochTargetBalance, currEpochTargetBalance *big.Int) bitfield.Bitvector4 {
newBits := state.JustificationBits()
newBits.Shift(1)
// If 2/3 or more of total balance attested in the previous epoch.
if 3*prevEpochTargetBalance >= 2*totalActiveBalance {
three := big.NewInt(3)
prevEpochTargetBalanceTimesThree := new(big.Int).Mul(three, prevEpochTargetBalance)
currEpochTargetBalanceTimesThree := new(big.Int).Mul(three, currEpochTargetBalance)
totalActiveBalanceTimesTwo := new(big.Int).Mul(big.NewInt(2), totalActiveBalance)
if prevEpochTargetBalanceTimesThree.Cmp(totalActiveBalanceTimesTwo) != -1 {
newBits.SetBitAt(1, true)
}
if 3*currEpochTargetBalance >= 2*totalActiveBalance {
if currEpochTargetBalanceTimesThree.Cmp(totalActiveBalanceTimesTwo) != -1 {
newBits.SetBitAt(0, true)
}

View File

@ -2,6 +2,7 @@ package precompute_test
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/go-bitfield"
@ -42,7 +43,8 @@ func TestProcessJustificationAndFinalizationPreCompute_ConsecutiveEpochs(t *test
state, err := state_native.InitializeFromProtoPhase0(base)
require.NoError(t, err)
attestedBalance := 4 * uint64(e) * 3 / 2
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
b := precompute.NewBalance()
b.PrevEpochTargetAttested = new(big.Int).SetUint64(attestedBalance)
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
require.NoError(t, err)
rt := [32]byte{byte(64)}
@ -79,7 +81,8 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyCurrentEpoch(t *te
state, err := state_native.InitializeFromProtoPhase0(base)
require.NoError(t, err)
attestedBalance := 4 * uint64(e) * 3 / 2
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
b := precompute.NewBalance()
b.PrevEpochTargetAttested = new(big.Int).SetUint64(attestedBalance)
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
require.NoError(t, err)
rt := [32]byte{byte(64)}
@ -115,7 +118,8 @@ func TestProcessJustificationAndFinalizationPreCompute_JustifyPrevEpoch(t *testi
state, err := state_native.InitializeFromProtoPhase0(base)
require.NoError(t, err)
attestedBalance := 4 * uint64(e) * 3 / 2
b := &precompute.Balance{PrevEpochTargetAttested: attestedBalance}
b := precompute.NewBalance()
b.PrevEpochTargetAttested = new(big.Int).SetUint64(attestedBalance)
newState, err := precompute.ProcessJustificationAndFinalizationPreCompute(state, b)
require.NoError(t, err)
rt := [32]byte{byte(64)}

View File

@ -5,6 +5,7 @@ package precompute
import (
"context"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
@ -22,7 +23,7 @@ func New(ctx context.Context, s state.BeaconState) ([]*Validator, *Balance, erro
defer span.End()
pValidators := make([]*Validator, s.NumValidators())
pBal := &Balance{}
pBal := NewBalance()
currentEpoch := time.CurrentEpoch(s)
prevEpoch := time.PrevEpoch(s)
@ -30,6 +31,7 @@ func New(ctx context.Context, s state.BeaconState) ([]*Validator, *Balance, erro
if err := s.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
// Was validator withdrawable or slashed
withdrawable := prevEpoch+1 >= val.WithdrawableEpoch()
effectiveBalance := new(big.Int).SetUint64(val.EffectiveBalance())
pVal := &Validator{
IsSlashed: val.Slashed(),
IsWithdrawableCurrentEpoch: withdrawable,
@ -38,12 +40,12 @@ func New(ctx context.Context, s state.BeaconState) ([]*Validator, *Balance, erro
// Was validator active current epoch
if helpers.IsActiveValidatorUsingTrie(val, currentEpoch) {
pVal.IsActiveCurrentEpoch = true
pBal.ActiveCurrentEpoch += val.EffectiveBalance()
pBal.ActiveCurrentEpoch.Add(pBal.ActiveCurrentEpoch, effectiveBalance)
}
// Was validator active previous epoch
if helpers.IsActiveValidatorUsingTrie(val, prevEpoch) {
pVal.IsActivePrevEpoch = true
pBal.ActivePrevEpoch += val.EffectiveBalance()
pBal.ActivePrevEpoch.Add(pBal.ActivePrevEpoch, effectiveBalance)
}
// Set inclusion slot and inclusion distance to be max, they will be compared and replaced
// with the lower values
@ -57,3 +59,15 @@ func New(ctx context.Context, s state.BeaconState) ([]*Validator, *Balance, erro
}
return pValidators, pBal, nil
}
func NewBalance() *Balance {
return &Balance{
ActiveCurrentEpoch: big.NewInt(0),
ActivePrevEpoch: big.NewInt(0),
CurrentEpochAttested: big.NewInt(0),
CurrentEpochTargetAttested: big.NewInt(0),
PrevEpochAttested: big.NewInt(0),
PrevEpochHeadAttested: big.NewInt(0),
PrevEpochTargetAttested: big.NewInt(0),
}
}

View File

@ -2,6 +2,7 @@ package precompute_test
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute"
@ -57,9 +58,8 @@ func TestNew(t *testing.T) {
InclusionSlot: e,
}, v[3], "Incorrect validator 3 status")
wantedBalances := &precompute.Balance{
ActiveCurrentEpoch: 100,
ActivePrevEpoch: 200,
}
wantedBalances := precompute.NewBalance()
wantedBalances.ActiveCurrentEpoch = big.NewInt(100)
wantedBalances.ActivePrevEpoch = big.NewInt(200)
assert.DeepEqual(t, wantedBalances, b, "Incorrect wanted balance")
}

View File

@ -1,13 +1,14 @@
package precompute
import (
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
)
type attesterRewardsFunc func(state.ReadOnlyBeaconState, *Balance, []*Validator) ([]uint64, []uint64, error)
@ -72,7 +73,7 @@ func AttestationsDelta(state state.ReadOnlyBeaconState, pBal *Balance, vp []*Val
prevEpoch := time.PrevEpoch(state)
finalizedEpoch := state.FinalizedCheckpointEpoch()
sqrtActiveCurrentEpoch := math.CachedSquareRoot(pBal.ActiveCurrentEpoch)
sqrtActiveCurrentEpoch := new(big.Int).Sqrt(pBal.ActiveCurrentEpoch).Uint64()
for i, v := range vp {
rewards[i], penalties[i] = attestationDelta(pBal, sqrtActiveCurrentEpoch, v, prevEpoch, finalizedEpoch)
}
@ -80,16 +81,16 @@ func AttestationsDelta(state state.ReadOnlyBeaconState, pBal *Balance, vp []*Val
}
func attestationDelta(pBal *Balance, sqrtActiveCurrentEpoch uint64, v *Validator, prevEpoch, finalizedEpoch primitives.Epoch) (uint64, uint64) {
if !EligibleForRewards(v) || pBal.ActiveCurrentEpoch == 0 {
if !EligibleForRewards(v) || pBal.ActiveCurrentEpoch.Cmp(big.NewInt(0)) != 1 {
return 0, 0
}
baseRewardsPerEpoch := params.BeaconConfig().BaseRewardsPerEpoch
effectiveBalanceIncrement := params.BeaconConfig().EffectiveBalanceIncrement
effectiveBalanceIncrement := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
vb := v.CurrentEpochEffectiveBalance
br := vb * params.BeaconConfig().BaseRewardFactor / sqrtActiveCurrentEpoch / baseRewardsPerEpoch
r, p := uint64(0), uint64(0)
currentEpochBalance := pBal.ActiveCurrentEpoch / effectiveBalanceIncrement
currentEpochBalance := new(big.Int).Div(pBal.ActiveCurrentEpoch, effectiveBalanceIncrement).Uint64()
// Process source reward / penalty
if v.IsPrevEpochAttester && !v.IsSlashed {
@ -102,7 +103,7 @@ func attestationDelta(pBal *Balance, sqrtActiveCurrentEpoch uint64, v *Validator
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochAttested / effectiveBalanceIncrement)
rewardNumerator := br * (new(big.Int).Div(pBal.PrevEpochAttested, effectiveBalanceIncrement)).Uint64()
r += rewardNumerator / currentEpochBalance
}
} else {
@ -116,7 +117,7 @@ func attestationDelta(pBal *Balance, sqrtActiveCurrentEpoch uint64, v *Validator
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochTargetAttested / effectiveBalanceIncrement)
rewardNumerator := br * (new(big.Int).Div(pBal.PrevEpochTargetAttested, effectiveBalanceIncrement)).Uint64()
r += rewardNumerator / currentEpochBalance
}
} else {
@ -130,7 +131,7 @@ func attestationDelta(pBal *Balance, sqrtActiveCurrentEpoch uint64, v *Validator
// optimal participation receives full base reward compensation here.
r += br
} else {
rewardNumerator := br * (pBal.PrevEpochHeadAttested / effectiveBalanceIncrement)
rewardNumerator := br * (new(big.Int).Div(pBal.PrevEpochHeadAttested, effectiveBalanceIncrement)).Uint64()
r += rewardNumerator / currentEpochBalance
}
} else {
@ -160,7 +161,7 @@ func ProposersDelta(state state.ReadOnlyBeaconState, pBal *Balance, vp []*Valida
rewards := make([]uint64, numofVals)
totalBalance := pBal.ActiveCurrentEpoch
balanceSqrt := math.CachedSquareRoot(totalBalance)
balanceSqrt := new(big.Int).Sqrt(totalBalance).Uint64()
// Balance square root cannot be 0, this prevents division by 0.
if balanceSqrt == 0 {
balanceSqrt = 1

View File

@ -2,6 +2,7 @@ package precompute
import (
"context"
"math/big"
"testing"
"github.com/pkg/errors"
@ -14,7 +15,6 @@ import (
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/runtime/version"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
@ -97,8 +97,10 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
// Add some variances to target and head balances.
// See: https://github.com/prysmaticlabs/prysm/issues/5593
bp.PrevEpochTargetAttested /= 2
bp.PrevEpochHeadAttested = bp.PrevEpochHeadAttested * 2 / 3
two := big.NewInt(2)
three := big.NewInt(3)
bp.PrevEpochTargetAttested.Div(bp.PrevEpochTargetAttested, two)
bp.PrevEpochHeadAttested.Div(new(big.Int).Mul(bp.PrevEpochHeadAttested, two), three)
rewards, penalties, err := AttestationsDelta(beaconState, bp, vp)
require.NoError(t, err)
attestedBalance, err := epoch.AttestingBalance(context.Background(), beaconState, atts)
@ -112,14 +114,23 @@ func TestAttestationDeltaPrecompute(t *testing.T) {
require.NoError(t, err, "Could not get base reward")
// Base rewards for getting source right
wanted := attestedBalance*base/totalBalance +
bp.PrevEpochTargetAttested*base/totalBalance +
bp.PrevEpochHeadAttested*base/totalBalance
baseBig := new(big.Int).SetUint64(base)
attestedBalanceTimesBase := new(big.Int).Mul(attestedBalance, baseBig)
prevEpochTargetAttestedTimesBase := new(big.Int).Mul(bp.PrevEpochTargetAttested, baseBig)
prevEpochHeadAttestedTimesBase := new(big.Int).Mul(bp.PrevEpochHeadAttested, baseBig)
attestedBalanceTimesBaseDivTotalBal := new(big.Int).Div(attestedBalanceTimesBase, totalBalance)
prevEpochTargetAttestedTimesBaseDivTotalBal := new(big.Int).Div(prevEpochTargetAttestedTimesBase, totalBalance)
prevEpochHeadAttestedTimesBaseDivTotalBal := new(big.Int).Div(prevEpochHeadAttestedTimesBase, totalBalance)
wanted := new(big.Int).Add(new(big.Int).Add(attestedBalanceTimesBaseDivTotalBal, prevEpochTargetAttestedTimesBaseDivTotalBal), prevEpochHeadAttestedTimesBaseDivTotalBal)
// Base rewards for proposer and attesters working together getting attestation
// on chain in the fatest manner
proposerReward := base / params.BeaconConfig().ProposerRewardQuotient
wanted += (base-proposerReward)*uint64(params.BeaconConfig().MinAttestationInclusionDelay) - 1
assert.Equal(t, wanted, rewards[i], "Unexpected reward balance for validator with index %d", i)
baseSubProposerReward := new(big.Int).Sub(baseBig, new(big.Int).SetUint64(proposerReward))
baseSubProposerRewardTimesMinAttestIncDelay := new(big.Int).Mul(baseSubProposerReward, new(big.Int).SetUint64(uint64(params.BeaconConfig().MinAttestationInclusionDelay)))
baseSubProposerRewardTimesMinAttestIncDelaySubOne := new(big.Int).Sub(baseSubProposerRewardTimesMinAttestIncDelay, big.NewInt(1))
wanted.Add(wanted, baseSubProposerRewardTimesMinAttestIncDelaySubOne)
assert.Equal(t, wanted.Uint64(), rewards[i], "Unexpected reward balance for validator with index %d", i)
// Since all these validators attested, they shouldn't get penalized.
assert.Equal(t, uint64(0), penalties[i], "Unexpected penalty balance")
}
@ -173,7 +184,7 @@ func TestAttestationDeltas_ZeroEpoch(t *testing.T) {
pVals, pBal, err = ProcessAttestations(context.Background(), beaconState, pVals, pBal)
require.NoError(t, err)
pBal.ActiveCurrentEpoch = 0 // Could cause a divide by zero panic.
pBal.ActiveCurrentEpoch = big.NewInt(0) // Could cause a divide by zero panic.
_, _, err = AttestationsDelta(beaconState, pBal, pVals)
require.NoError(t, err)
@ -307,18 +318,22 @@ func TestProposerDeltaPrecompute_HappyCase(t *testing.T) {
require.NoError(t, err)
proposerIndex := primitives.ValidatorIndex(1)
b := &Balance{ActiveCurrentEpoch: 1000}
b := NewBalance()
b.ActiveCurrentEpoch = big.NewInt(1000)
v := []*Validator{
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
}
r, err := ProposersDelta(beaconState, b, v)
require.NoError(t, err)
baseReward := v[0].CurrentEpochEffectiveBalance * params.BeaconConfig().BaseRewardFactor /
math.IntegerSquareRoot(b.ActiveCurrentEpoch) / params.BeaconConfig().BaseRewardsPerEpoch
proposerReward := baseReward / params.BeaconConfig().ProposerRewardQuotient
activeCurrEpochSqrt := new(big.Int).Sqrt(b.ActiveCurrentEpoch)
currEpochEffectBal := new(big.Int).SetUint64(v[0].CurrentEpochEffectiveBalance)
currEpochEffBalTimesBrFact := new(big.Int).Mul(currEpochEffectBal, new(big.Int).SetUint64(params.BeaconConfig().BaseRewardFactor))
currEpochEffBalTimesBrFactDivSqrt := new(big.Int).Div(currEpochEffBalTimesBrFact, activeCurrEpochSqrt)
baseReward := new(big.Int).Div(currEpochEffBalTimesBrFactDivSqrt, new(big.Int).SetUint64(params.BeaconConfig().BaseRewardsPerEpoch))
proposerReward := new(big.Int).Div(baseReward, new(big.Int).SetUint64(params.BeaconConfig().ProposerRewardQuotient))
assert.Equal(t, proposerReward, r[proposerIndex], "Unexpected proposer reward")
assert.Equal(t, proposerReward.Uint64(), r[proposerIndex], "Unexpected proposer reward")
}
func TestProposerDeltaPrecompute_ValidatorIndexOutOfRange(t *testing.T) {
@ -329,7 +344,8 @@ func TestProposerDeltaPrecompute_ValidatorIndexOutOfRange(t *testing.T) {
require.NoError(t, err)
proposerIndex := primitives.ValidatorIndex(validatorCount)
b := &Balance{ActiveCurrentEpoch: 1000}
b := NewBalance()
b.ActiveCurrentEpoch = big.NewInt(1000)
v := []*Validator{
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex},
}
@ -345,7 +361,8 @@ func TestProposerDeltaPrecompute_SlashedCase(t *testing.T) {
require.NoError(t, err)
proposerIndex := primitives.ValidatorIndex(1)
b := &Balance{ActiveCurrentEpoch: 1000}
b := NewBalance()
b.ActiveCurrentEpoch = big.NewInt(1000)
v := []*Validator{
{IsPrevEpochAttester: true, CurrentEpochEffectiveBalance: 32, ProposerIndex: proposerIndex, IsSlashed: true},
}
@ -373,7 +390,8 @@ func baseReward(state state.ReadOnlyBeaconState, index primitives.ValidatorIndex
return 0, err
}
effectiveBalance := val.EffectiveBalance()
totalBalanceSqrt := new(big.Int).Sqrt(totalBalance).Uint64()
baseReward := effectiveBalance * params.BeaconConfig().BaseRewardFactor /
math.IntegerSquareRoot(totalBalance) / params.BeaconConfig().BaseRewardsPerEpoch
totalBalanceSqrt / params.BeaconConfig().BaseRewardsPerEpoch
return baseReward, nil
}

View File

@ -1,12 +1,13 @@
package precompute
import (
"math/big"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
@ -23,7 +24,14 @@ func ProcessSlashingsPrecompute(s state.BeaconState, pBal *Balance) error {
totalSlashing += slashing
}
minSlashing := math.Min(totalSlashing*params.BeaconConfig().ProportionalSlashingMultiplier, pBal.ActiveCurrentEpoch)
minSlashing := pBal.ActiveCurrentEpoch
totalSlashingTimesPropSlashMul := new(big.Int).SetUint64(totalSlashing * params.BeaconConfig().ProportionalSlashingMultiplier)
if totalSlashingTimesPropSlashMul.Cmp(pBal.ActiveCurrentEpoch) == -1 {
minSlashing = totalSlashingTimesPropSlashMul
} else {
minSlashing = pBal.ActiveCurrentEpoch
}
epochToWithdraw := currentEpoch + exitLength/2
var hasSlashing bool
@ -43,15 +51,19 @@ func ProcessSlashingsPrecompute(s state.BeaconState, pBal *Balance) error {
return nil
}
increment := params.BeaconConfig().EffectiveBalanceIncrement
increment := new(big.Int).SetUint64(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, primitives.ValidatorIndex(idx), penalty); err != nil {
penalty := new(big.Int).SetUint64(val.EffectiveBalance) // valEffectiveBal
penalty.Div(penalty, increment) // val.EffectiveBalance / increment
penalty.Mul(penalty, minSlashing) // penaltyNumerator = val.EffectiveBalance / increment * minSlashing
penalty.Div(penalty, pBal.ActiveCurrentEpoch) // penaltyNumerator / pBal.ActiveCurrentEpoch
penalty = penalty.Mul(penalty, increment) // penalty = penaltyNumerator / pBal.ActiveCurrentEpoch * increment
if err := helpers.DecreaseBalance(s, primitives.ValidatorIndex(idx), penalty.Uint64()); err != nil {
return false, val, err
}
return true, val, nil
}
return false, val, nil

View File

@ -2,6 +2,7 @@ package precompute_test
import (
"fmt"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/epoch/precompute"
@ -21,7 +22,8 @@ func TestProcessSlashingsPrecompute_NotSlashedWithSlashedTrue(t *testing.T) {
Slashings: []uint64{0, 1e9},
})
require.NoError(t, err)
pBal := &precompute.Balance{ActiveCurrentEpoch: params.BeaconConfig().MaxEffectiveBalance}
pBal := precompute.NewBalance()
pBal.ActiveCurrentEpoch = new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance)
require.NoError(t, precompute.ProcessSlashingsPrecompute(s, pBal))
wanted := params.BeaconConfig().MaxEffectiveBalance
@ -36,7 +38,8 @@ func TestProcessSlashingsPrecompute_NotSlashedWithSlashedFalse(t *testing.T) {
Slashings: []uint64{0, 1e9},
})
require.NoError(t, err)
pBal := &precompute.Balance{ActiveCurrentEpoch: params.BeaconConfig().MaxEffectiveBalance}
pBal := precompute.NewBalance()
pBal.ActiveCurrentEpoch = new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance)
require.NoError(t, precompute.ProcessSlashingsPrecompute(s, pBal))
wanted := params.BeaconConfig().MaxEffectiveBalance
@ -112,16 +115,16 @@ func TestProcessSlashingsPrecompute_SlashedLess(t *testing.T) {
for i, tt := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
ab := uint64(0)
ab := big.NewInt(0)
for i, b := range tt.state.Balances {
// Skip validator 0 since it's slashed
if i == 0 {
continue
}
ab += b
ab.Add(ab, new(big.Int).SetUint64(b))
}
pBal := &precompute.Balance{ActiveCurrentEpoch: ab}
pBal := precompute.NewBalance()
pBal.ActiveCurrentEpoch = ab
original := proto.Clone(tt.state)
state, err := state_native.InitializeFromProtoPhase0(tt.state)
require.NoError(t, err)

View File

@ -1,6 +1,10 @@
package precompute
import "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
import (
"math/big"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
)
// Validator stores the pre computation of individual validator's attesting records these records
// consist of attestation votes, block inclusion record. Pre computing and storing such record
@ -48,20 +52,20 @@ type Validator struct {
// 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
ActiveCurrentEpoch *big.Int
// ActivePrevEpoch is the total effective balance of all active validators during prev epoch.
ActivePrevEpoch uint64
ActivePrevEpoch *big.Int
// CurrentEpochAttested is the total effective balance of all validators who attested during current epoch.
CurrentEpochAttested uint64
CurrentEpochAttested *big.Int
// CurrentEpochTargetAttested is the total effective balance of all validators who attested
// for epoch boundary block during current epoch.
CurrentEpochTargetAttested uint64
CurrentEpochTargetAttested *big.Int
// PrevEpochAttested is the total effective balance of all validators who attested during prev epoch.
PrevEpochAttested uint64
PrevEpochAttested *big.Int
// PrevEpochTargetAttested is the total effective balance of all validators who attested
// for epoch boundary block during prev epoch.
PrevEpochTargetAttested uint64
PrevEpochTargetAttested *big.Int
// PrevEpochHeadAttested is the total effective balance of all validators who attested
// correctly for head block during prev epoch.
PrevEpochHeadAttested uint64
PrevEpochHeadAttested *big.Int
}

View File

@ -2,6 +2,7 @@ package helpers
import (
"errors"
"math/big"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
@ -25,20 +26,22 @@ var balanceCache = cache.NewEffectiveBalanceCache()
// Math safe up to ~10B ETH, afterwhich this overflows uint64.
// """
// return Gwei(max(EFFECTIVE_BALANCE_INCREMENT, sum([state.validators[index].effective_balance for index in indices])))
func TotalBalance(state state.ReadOnlyValidators, indices []primitives.ValidatorIndex) uint64 {
total := uint64(0)
func TotalBalance(state state.ReadOnlyValidators, indices []primitives.ValidatorIndex) *big.Int {
total := big.NewInt(0)
for _, idx := range indices {
val, err := state.ValidatorAtIndexReadOnly(idx)
if err != nil {
continue
}
total += val.EffectiveBalance()
effectiveBalance := val.EffectiveBalance()
total.Add(total, new(big.Int).SetUint64(effectiveBalance))
}
// EFFECTIVE_BALANCE_INCREMENT is the lower bound for total balance.
if total < params.BeaconConfig().EffectiveBalanceIncrement {
return params.BeaconConfig().EffectiveBalanceIncrement
effectiveBalanceIncrement := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
if total.Cmp(effectiveBalanceIncrement) == -1 {
return effectiveBalanceIncrement
}
return total
@ -55,8 +58,9 @@ func TotalBalance(state state.ReadOnlyValidators, indices []primitives.Validator
// Note: ``get_total_balance`` returns ``EFFECTIVE_BALANCE_INCREMENT`` Gwei minimum to avoid divisions by zero.
// """
// return get_total_balance(state, set(get_active_validator_indices(state, get_current_epoch(state))))
func TotalActiveBalance(s state.ReadOnlyBeaconState) (uint64, error) {
func TotalActiveBalance(s state.ReadOnlyBeaconState) (*big.Int, error) {
bal, err := balanceCache.Get(s)
zero := big.NewInt(0)
switch {
case err == nil:
return bal, nil
@ -64,24 +68,28 @@ func TotalActiveBalance(s state.ReadOnlyBeaconState) (uint64, error) {
// Do nothing if we receive a not found error.
default:
// In the event, we encounter another error we return it.
return 0, err
return zero, err
}
total := uint64(0)
total := big.NewInt(0)
epoch := slots.ToEpoch(s.Slot())
if err := s.ReadFromEveryValidator(func(idx int, val state.ReadOnlyValidator) error {
if IsActiveValidatorUsingTrie(val, epoch) {
total += val.EffectiveBalance()
effectiveBalance := val.EffectiveBalance()
total.Add(total, new(big.Int).SetUint64(effectiveBalance))
}
return nil
}); err != nil {
return 0, err
return zero, err
}
// Spec defines `EffectiveBalanceIncrement` as min to avoid divisions by zero.
total = mathutil.Max(params.BeaconConfig().EffectiveBalanceIncrement, total)
effectiveBalanceIncrement := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
if effectiveBalanceIncrement.Cmp(total) == 1 {
total = effectiveBalanceIncrement
}
if err := balanceCache.AddTotalEffectiveBalance(s, total); err != nil {
return 0, err
return zero, err
}
return total, nil

View File

@ -25,7 +25,7 @@ func TestTotalBalance_OK(t *testing.T) {
balance := TotalBalance(state, []primitives.ValidatorIndex{0, 1, 2, 3})
wanted := state.Validators()[0].EffectiveBalance + state.Validators()[1].EffectiveBalance +
state.Validators()[2].EffectiveBalance + state.Validators()[3].EffectiveBalance
assert.Equal(t, wanted, balance, "Incorrect TotalBalance")
assert.Equal(t, wanted, balance.Uint64(), "Incorrect TotalBalance")
}
func TestTotalBalance_ReturnsEffectiveBalanceIncrement(t *testing.T) {
@ -36,7 +36,7 @@ func TestTotalBalance_ReturnsEffectiveBalanceIncrement(t *testing.T) {
balance := TotalBalance(state, []primitives.ValidatorIndex{})
wanted := params.BeaconConfig().EffectiveBalanceIncrement
assert.Equal(t, wanted, balance, "Incorrect TotalBalance")
assert.Equal(t, wanted, balance.Uint64(), "Incorrect TotalBalance")
}
func TestGetBalance_OK(t *testing.T) {
@ -78,7 +78,7 @@ func TestTotalActiveBalance(t *testing.T) {
require.NoError(t, err)
bal, err := TotalActiveBalance(state)
require.NoError(t, err)
require.Equal(t, uint64(test.vCount)*params.BeaconConfig().MaxEffectiveBalance, bal)
require.Equal(t, uint64(test.vCount)*params.BeaconConfig().MaxEffectiveBalance, bal.Uint64())
}
}
@ -101,7 +101,7 @@ func TestTotalActiveBal_ReturnMin(t *testing.T) {
require.NoError(t, err)
bal, err := TotalActiveBalance(state)
require.NoError(t, err)
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, bal)
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, bal.Uint64())
}
}
@ -125,7 +125,7 @@ func TestTotalActiveBalance_WithCache(t *testing.T) {
require.NoError(t, err)
bal, err := TotalActiveBalance(state)
require.NoError(t, err)
require.Equal(t, uint64(test.wantCount)*params.BeaconConfig().MaxEffectiveBalance, bal)
require.Equal(t, uint64(test.wantCount)*params.BeaconConfig().MaxEffectiveBalance, bal.Uint64())
}
}

View File

@ -5,6 +5,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"math/big"
"strconv"
"strings"
@ -70,11 +71,12 @@ func ComputeWeakSubjectivityPeriod(ctx context.Context, st state.ReadOnlyBeaconS
}
// Average effective balance in the given validator set, in Ether.
t, err := TotalActiveBalance(st)
total, err := TotalActiveBalance(st)
if err != nil {
return 0, fmt.Errorf("cannot find total active balance of validators: %w", err)
}
t = t / N / cfg.GweiPerEth
balancePerValidator := new(big.Int).Div(total, new(big.Int).SetUint64(N))
t := new(big.Int).Div(balancePerValidator, new(big.Int).SetUint64(cfg.GweiPerEth)).Uint64()
// Maximum effective balance per validator.
T := cfg.MaxEffectiveBalance / cfg.GweiPerEth

View File

@ -3,6 +3,7 @@ package doublylinkedtree
import (
"context"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
@ -31,6 +32,7 @@ func New() *ForkChoice {
prevJustifiedCheckpoint: &forkchoicetypes.Checkpoint{},
finalizedCheckpoint: &forkchoicetypes.Checkpoint{},
proposerBoostRoot: [32]byte{},
committeeWeight: big.NewInt(0),
nodeByRoot: make(map[[fieldparams.RootLength]byte]*Node),
nodeByPayload: make(map[[fieldparams.RootLength]byte]*Node),
slashedIndices: make(map[primitives.ValidatorIndex]bool),
@ -278,19 +280,19 @@ func (f *ForkChoice) updateBalances() error {
continue
}
oldBalance := uint64(0)
newBalance := uint64(0)
oldBalance := big.NewInt(0)
newBalance := big.NewInt(0)
// If the validator index did not exist in `f.balances` or
// `newBalances` list above, the balance is just 0.
if index < len(f.balances) {
oldBalance = f.balances[index]
oldBalance = new(big.Int).SetUint64(f.balances[index])
}
if index < len(newBalances) {
newBalance = newBalances[index]
newBalance = new(big.Int).SetUint64(newBalances[index])
}
// Update only if the validator's balance or vote has changed.
if vote.currentRoot != vote.nextRoot || oldBalance != newBalance {
if vote.currentRoot != vote.nextRoot || oldBalance.Cmp(newBalance) != 0 {
// Ignore the vote if the root is not in fork choice
// store, that means we have not seen the block before.
nextNode, ok := f.store.nodeByRoot[vote.nextRoot]
@ -299,7 +301,7 @@ func (f *ForkChoice) updateBalances() error {
if nextNode == nil {
return errors.Wrap(ErrNilNode, "could not update balances")
}
nextNode.balance += newBalance
nextNode.balance.Add(nextNode.balance, newBalance)
}
currentNode, ok := f.store.nodeByRoot[vote.currentRoot]
@ -308,7 +310,7 @@ func (f *ForkChoice) updateBalances() error {
if currentNode == nil {
return errors.Wrap(ErrNilNode, "could not update balances")
}
if currentNode.balance < oldBalance {
if currentNode.balance.Cmp(oldBalance) == -1 {
log.WithFields(logrus.Fields{
"nodeRoot": fmt.Sprintf("%#x", bytesutil.Trunc(vote.currentRoot[:])),
"oldBalance": oldBalance,
@ -318,9 +320,9 @@ func (f *ForkChoice) updateBalances() error {
"previousProposerBoostRoot": fmt.Sprintf("%#x", bytesutil.Trunc(f.store.previousProposerBoostRoot[:])),
"previousProposerBoostScore": f.store.previousProposerBoostScore,
}).Warning("node with invalid balance, setting it to zero")
currentNode.balance = 0
currentNode.balance = big.NewInt(0)
} else {
currentNode.balance -= oldBalance
currentNode.balance.Sub(currentNode.balance, oldBalance)
}
}
}
@ -397,10 +399,10 @@ func (f *ForkChoice) InsertSlashedIndex(_ context.Context, index primitives.Vali
return
}
if node.balance < f.balances[index] {
node.balance = 0
if node.balance.Cmp(new(big.Int).SetUint64(f.balances[index])) == -1 {
node.balance = big.NewInt(0)
} else {
node.balance -= f.balances[index]
node.balance.Sub(node.balance, new(big.Int).SetUint64(f.balances[index]))
}
}
@ -602,10 +604,10 @@ func (f *ForkChoice) SetBalancesByRooter(handler forkchoice.BalancesByRooter) {
}
// Weight returns the weight of the given root if found on the store
func (f *ForkChoice) Weight(root [32]byte) (uint64, error) {
func (f *ForkChoice) Weight(root [32]byte) (*big.Int, error) {
n, ok := f.store.nodeByRoot[root]
if !ok || n == nil {
return 0, ErrNilNode
return big.NewInt(0), ErrNilNode
}
return n.weight, nil
}
@ -617,15 +619,15 @@ func (f *ForkChoice) updateJustifiedBalances(ctx context.Context, root [32]byte)
return errors.Wrap(err, "could not get justified balances")
}
f.justifiedBalances = balances
f.store.committeeWeight = 0
f.store.committeeWeight = big.NewInt(0)
f.numActiveValidators = 0
for _, val := range balances {
if val > 0 {
f.store.committeeWeight += val
f.store.committeeWeight.Add(f.store.committeeWeight, new(big.Int).SetUint64(val))
f.numActiveValidators++
}
}
f.store.committeeWeight /= uint64(params.BeaconConfig().SlotsPerEpoch)
f.store.committeeWeight.Div(f.store.committeeWeight, new(big.Int).SetUint64(uint64(params.BeaconConfig().SlotsPerEpoch)))
return nil
}

View File

@ -3,6 +3,7 @@ package doublylinkedtree
import (
"context"
"encoding/binary"
"math/big"
"testing"
"time"
@ -85,9 +86,9 @@ func TestForkChoice_UpdateBalancesPositiveChange(t *testing.T) {
f.justifiedBalances = []uint64{10, 20, 30}
require.NoError(t, f.updateBalances())
s := f.store
assert.Equal(t, uint64(10), s.nodeByRoot[indexToHash(1)].balance)
assert.Equal(t, uint64(20), s.nodeByRoot[indexToHash(2)].balance)
assert.Equal(t, uint64(30), s.nodeByRoot[indexToHash(3)].balance)
assert.Equal(t, uint64(10), s.nodeByRoot[indexToHash(1)].balance.Uint64())
assert.Equal(t, uint64(20), s.nodeByRoot[indexToHash(2)].balance.Uint64())
assert.Equal(t, uint64(30), s.nodeByRoot[indexToHash(3)].balance.Uint64())
}
func TestForkChoice_UpdateBalancesNegativeChange(t *testing.T) {
@ -103,9 +104,9 @@ func TestForkChoice_UpdateBalancesNegativeChange(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, blkRoot))
s := f.store
s.nodeByRoot[indexToHash(1)].balance = 100
s.nodeByRoot[indexToHash(2)].balance = 100
s.nodeByRoot[indexToHash(3)].balance = 100
s.nodeByRoot[indexToHash(1)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(2)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(3)].balance = big.NewInt(100)
f.balances = []uint64{100, 100, 100}
f.votes = []Vote{
@ -116,9 +117,9 @@ func TestForkChoice_UpdateBalancesNegativeChange(t *testing.T) {
f.justifiedBalances = []uint64{10, 20, 30}
require.NoError(t, f.updateBalances())
assert.Equal(t, uint64(10), s.nodeByRoot[indexToHash(1)].balance)
assert.Equal(t, uint64(20), s.nodeByRoot[indexToHash(2)].balance)
assert.Equal(t, uint64(30), s.nodeByRoot[indexToHash(3)].balance)
assert.Equal(t, uint64(10), s.nodeByRoot[indexToHash(1)].balance.Uint64())
assert.Equal(t, uint64(20), s.nodeByRoot[indexToHash(2)].balance.Uint64())
assert.Equal(t, uint64(30), s.nodeByRoot[indexToHash(3)].balance.Uint64())
}
func TestForkChoice_UpdateBalancesUnderflow(t *testing.T) {
@ -134,9 +135,9 @@ func TestForkChoice_UpdateBalancesUnderflow(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, blkRoot))
s := f.store
s.nodeByRoot[indexToHash(1)].balance = 100
s.nodeByRoot[indexToHash(2)].balance = 100
s.nodeByRoot[indexToHash(3)].balance = 100
s.nodeByRoot[indexToHash(1)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(2)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(3)].balance = big.NewInt(100)
f.balances = []uint64{125, 125, 125}
f.votes = []Vote{
@ -147,9 +148,9 @@ func TestForkChoice_UpdateBalancesUnderflow(t *testing.T) {
f.justifiedBalances = []uint64{10, 20, 30}
require.NoError(t, f.updateBalances())
assert.Equal(t, uint64(0), s.nodeByRoot[indexToHash(1)].balance)
assert.Equal(t, uint64(0), s.nodeByRoot[indexToHash(2)].balance)
assert.Equal(t, uint64(5), s.nodeByRoot[indexToHash(3)].balance)
assert.Equal(t, uint64(0), s.nodeByRoot[indexToHash(1)].balance.Uint64())
assert.Equal(t, uint64(0), s.nodeByRoot[indexToHash(2)].balance.Uint64())
assert.Equal(t, uint64(5), s.nodeByRoot[indexToHash(3)].balance.Uint64())
}
func TestForkChoice_IsCanonical(t *testing.T) {
@ -205,10 +206,10 @@ func TestForkChoice_IsCanonicalReorg(t *testing.T) {
require.NoError(t, err)
require.NoError(t, f.InsertNode(ctx, st, blkRoot))
f.store.nodeByRoot[[32]byte{'3'}].balance = 10
f.store.nodeByRoot[[32]byte{'3'}].balance = big.NewInt(10)
require.NoError(t, f.store.treeRootNode.applyWeightChanges(ctx))
require.Equal(t, uint64(10), f.store.nodeByRoot[[32]byte{'1'}].weight)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'2'}].weight)
require.Equal(t, uint64(10), f.store.nodeByRoot[[32]byte{'1'}].weight.Uint64())
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'2'}].weight.Uint64())
require.NoError(t, f.store.treeRootNode.updateBestDescendant(ctx, 1, 1, 1))
require.DeepEqual(t, [32]byte{'3'}, f.store.treeRootNode.bestDescendant.root)
@ -323,21 +324,21 @@ func TestForkChoice_RemoveEquivocating(t *testing.T) {
// Process b's slashing, c is now head
f.InsertSlashedIndex(ctx, 1)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance.Uint64())
f.justifiedBalances = []uint64{100, 200, 200, 300}
head, err = f.Head(ctx)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight)
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight.Uint64())
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight.Uint64())
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
// Process b's slashing again, should be a noop
f.InsertSlashedIndex(ctx, 1)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].balance.Uint64())
f.justifiedBalances = []uint64{100, 200, 200, 300}
head, err = f.Head(ctx)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight)
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight)
require.Equal(t, uint64(200), f.store.nodeByRoot[[32]byte{'b'}].weight.Uint64())
require.Equal(t, uint64(300), f.store.nodeByRoot[[32]byte{'c'}].weight.Uint64())
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, head)
@ -720,14 +721,14 @@ func TestWeight(t *testing.T) {
n, ok := f.store.nodeByRoot[root]
require.Equal(t, true, ok)
n.weight = 10
n.weight = big.NewInt(10)
w, err := f.Weight(root)
require.NoError(t, err)
require.Equal(t, uint64(10), w)
require.Equal(t, uint64(10), w.Uint64())
w, err = f.Weight([32]byte{'b'})
require.ErrorIs(t, err, ErrNilNode)
require.Equal(t, uint64(0), w)
require.Equal(t, uint64(0), w.Uint64())
}
func TestForkchoice_UpdateJustifiedBalances(t *testing.T) {
@ -738,7 +739,7 @@ func TestForkchoice_UpdateJustifiedBalances(t *testing.T) {
}
require.NoError(t, f.updateJustifiedBalances(context.Background(), [32]byte{}))
require.Equal(t, uint64(7), f.numActiveValidators)
require.Equal(t, uint64(430)/32, f.store.committeeWeight)
require.Equal(t, uint64(430)/32, f.store.committeeWeight.Uint64())
require.DeepEqual(t, balances, f.justifiedBalances)
}

View File

@ -3,6 +3,7 @@ package doublylinkedtree
import (
"bytes"
"context"
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/config/params"
@ -19,7 +20,7 @@ const ProcessAttestationsThreshold = 10
// using the current balance stored in each node.
func (n *Node) applyWeightChanges(ctx context.Context) error {
// Recursively calling the children to sum their weights.
childrenWeight := uint64(0)
childrenWeight := big.NewInt(0)
for _, child := range n.children {
if ctx.Err() != nil {
return ctx.Err()
@ -27,12 +28,12 @@ func (n *Node) applyWeightChanges(ctx context.Context) error {
if err := child.applyWeightChanges(ctx); err != nil {
return err
}
childrenWeight += child.weight
childrenWeight.Add(childrenWeight, child.weight)
}
if n.root == params.BeaconConfig().ZeroHash {
return nil
}
n.weight = n.balance + childrenWeight
n.weight.Add(n.balance, childrenWeight)
return nil
}
@ -48,7 +49,7 @@ func (n *Node) updateBestDescendant(ctx context.Context, justifiedEpoch, finaliz
}
var bestChild *Node
bestWeight := uint64(0)
bestWeight := big.NewInt(0)
hasViableDescendant := false
for _, child := range n.children {
if child == nil {
@ -66,12 +67,12 @@ func (n *Node) updateBestDescendant(ctx context.Context, justifiedEpoch, finaliz
hasViableDescendant = true
} else if childLeadsToViableHead {
// If both are viable, compare their weights.
if child.weight == bestWeight {
if child.weight.Cmp(bestWeight) == 0 {
// Tie-breaker of equal weights by root.
if bytes.Compare(child.root[:], bestChild.root[:]) > 0 {
bestChild = child
}
} else if child.weight > bestWeight {
} else if child.weight.Cmp(bestWeight) == 1 {
bestChild = child
bestWeight = child.weight
}

View File

@ -2,6 +2,7 @@ package doublylinkedtree
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
@ -27,15 +28,15 @@ func TestNode_ApplyWeightChanges_PositiveChange(t *testing.T) {
// The updated balances of each node is 100
s := f.store
s.nodeByRoot[indexToHash(1)].balance = 100
s.nodeByRoot[indexToHash(2)].balance = 100
s.nodeByRoot[indexToHash(3)].balance = 100
s.nodeByRoot[indexToHash(1)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(2)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(3)].balance = big.NewInt(100)
assert.NoError(t, s.treeRootNode.applyWeightChanges(ctx))
assert.Equal(t, uint64(300), s.nodeByRoot[indexToHash(1)].weight)
assert.Equal(t, uint64(200), s.nodeByRoot[indexToHash(2)].weight)
assert.Equal(t, uint64(100), s.nodeByRoot[indexToHash(3)].weight)
assert.Equal(t, uint64(300), s.nodeByRoot[indexToHash(1)].weight.Uint64())
assert.Equal(t, uint64(200), s.nodeByRoot[indexToHash(2)].weight.Uint64())
assert.Equal(t, uint64(100), s.nodeByRoot[indexToHash(3)].weight.Uint64())
}
func TestNode_ApplyWeightChanges_NegativeChange(t *testing.T) {
@ -53,19 +54,19 @@ func TestNode_ApplyWeightChanges_NegativeChange(t *testing.T) {
// The updated balances of each node is 100
s := f.store
s.nodeByRoot[indexToHash(1)].weight = 400
s.nodeByRoot[indexToHash(2)].weight = 400
s.nodeByRoot[indexToHash(3)].weight = 400
s.nodeByRoot[indexToHash(1)].weight = big.NewInt(400)
s.nodeByRoot[indexToHash(2)].weight = big.NewInt(400)
s.nodeByRoot[indexToHash(3)].weight = big.NewInt(400)
s.nodeByRoot[indexToHash(1)].balance = 100
s.nodeByRoot[indexToHash(2)].balance = 100
s.nodeByRoot[indexToHash(3)].balance = 100
s.nodeByRoot[indexToHash(1)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(2)].balance = big.NewInt(100)
s.nodeByRoot[indexToHash(3)].balance = big.NewInt(100)
assert.NoError(t, s.treeRootNode.applyWeightChanges(ctx))
assert.Equal(t, uint64(300), s.nodeByRoot[indexToHash(1)].weight)
assert.Equal(t, uint64(200), s.nodeByRoot[indexToHash(2)].weight)
assert.Equal(t, uint64(100), s.nodeByRoot[indexToHash(3)].weight)
assert.Equal(t, uint64(300), s.nodeByRoot[indexToHash(1)].weight.Uint64())
assert.Equal(t, uint64(200), s.nodeByRoot[indexToHash(2)].weight.Uint64())
assert.Equal(t, uint64(100), s.nodeByRoot[indexToHash(3)].weight.Uint64())
}
func TestNode_UpdateBestDescendant_NonViableChild(t *testing.T) {
@ -108,8 +109,8 @@ func TestNode_UpdateBestDescendant_HigherWeightChild(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
s := f.store
s.nodeByRoot[indexToHash(1)].weight = 100
s.nodeByRoot[indexToHash(2)].weight = 200
s.nodeByRoot[indexToHash(1)].weight = big.NewInt(100)
s.nodeByRoot[indexToHash(2)].weight = big.NewInt(200)
assert.NoError(t, s.treeRootNode.updateBestDescendant(ctx, 1, 1, 1))
assert.Equal(t, 2, len(s.treeRootNode.children))
@ -128,8 +129,8 @@ func TestNode_UpdateBestDescendant_LowerWeightChild(t *testing.T) {
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
s := f.store
s.nodeByRoot[indexToHash(1)].weight = 200
s.nodeByRoot[indexToHash(2)].weight = 100
s.nodeByRoot[indexToHash(1)].weight = big.NewInt(200)
s.nodeByRoot[indexToHash(2)].weight = big.NewInt(100)
assert.NoError(t, s.treeRootNode.updateBestDescendant(ctx, 1, 1, 1))
assert.Equal(t, 2, len(s.treeRootNode.children))

View File

@ -2,6 +2,7 @@ package doublylinkedtree
import (
"fmt"
"math/big"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/config/params"
@ -11,13 +12,13 @@ import (
// relevant nodes.
func (f *ForkChoice) applyProposerBoostScore() error {
s := f.store
proposerScore := uint64(0)
proposerScore := big.NewInt(0)
if s.previousProposerBoostRoot != params.BeaconConfig().ZeroHash {
previousNode, ok := s.nodeByRoot[s.previousProposerBoostRoot]
if !ok || previousNode == nil {
log.WithError(errInvalidProposerBoostRoot).Errorf(fmt.Sprintf("invalid prev root %#x", s.previousProposerBoostRoot))
} else {
previousNode.balance -= s.previousProposerBoostScore
previousNode.balance.Sub(previousNode.balance, new(big.Int).SetUint64(s.previousProposerBoostScore))
}
}
@ -26,12 +27,13 @@ func (f *ForkChoice) applyProposerBoostScore() error {
if !ok || currentNode == nil {
log.WithError(errInvalidProposerBoostRoot).Errorf(fmt.Sprintf("invalid current root %#x", s.proposerBoostRoot))
} else {
proposerScore = (s.committeeWeight * params.BeaconConfig().ProposerScoreBoost) / 100
currentNode.balance += proposerScore
proposerScore = new(big.Int).Mul(s.committeeWeight, new(big.Int).SetUint64(params.BeaconConfig().ProposerScoreBoost))
proposerScore.Div(proposerScore, big.NewInt(100))
currentNode.balance.Add(currentNode.balance, proposerScore)
}
}
s.previousProposerBoostRoot = s.proposerBoostRoot
s.previousProposerBoostScore = proposerScore
s.previousProposerBoostScore = proposerScore.Uint64()
return nil
}

View File

@ -2,6 +2,7 @@ package doublylinkedtree
import (
"context"
"math/big"
"testing"
"time"
@ -34,7 +35,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
t.Run("back-propagates boost score to ancestors after proposer boosting", func(t *testing.T) {
f := setup(jEpoch, fEpoch)
f.justifiedBalances = balances
f.store.committeeWeight = uint64(len(balances)*10) / uint64(params.BeaconConfig().SlotsPerEpoch)
f.store.committeeWeight = new(big.Int).SetUint64(uint64(len(balances)*10) / uint64(params.BeaconConfig().SlotsPerEpoch))
f.numActiveValidators = uint64(len(balances))
// The head should always start at the finalized block.
@ -154,7 +155,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// Expect nodes to have a boosted, back-propagated score.
// Ancestors have the added weights of their children. Genesis is a special exception at 0 weight,
require.Equal(t, f.store.treeRootNode.weight, uint64(0))
require.Equal(t, f.store.treeRootNode.weight.Uint64(), uint64(0))
// Proposer boost score with these test parameters is 8
// Each of the nodes received one attestation accounting for 10.
@ -164,13 +165,13 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// \--------------->(4: 18)
//
node1 := f.store.nodeByRoot[indexToHash(1)]
require.Equal(t, node1.weight, uint64(48))
require.Equal(t, node1.weight.Uint64(), uint64(48))
node2 := f.store.nodeByRoot[indexToHash(2)]
require.Equal(t, node2.weight, uint64(38))
require.Equal(t, node2.weight.Uint64(), uint64(38))
node3 := f.store.nodeByRoot[indexToHash(3)]
require.Equal(t, node3.weight, uint64(10))
require.Equal(t, node3.weight.Uint64(), uint64(10))
node4 := f.store.nodeByRoot[indexToHash(4)]
require.Equal(t, node4.weight, uint64(18))
require.Equal(t, node4.weight.Uint64(), uint64(18))
// Regression: process attestations for C, check that it
// becomes head, we need two attestations to have C.weight = 30 > 24 = D.weight
@ -327,7 +328,7 @@ func TestForkChoice_BoostProposerRoot_PreventsExAnteAttack(t *testing.T) {
// Block D received at N+3 — D is head
f := setup(jEpoch, fEpoch)
f.justifiedBalances = balances
f.store.committeeWeight = uint64(len(balances)*10) / uint64(params.BeaconConfig().SlotsPerEpoch)
f.store.committeeWeight = new(big.Int).SetUint64(uint64(len(balances)*10) / uint64(params.BeaconConfig().SlotsPerEpoch))
f.numActiveValidators = uint64(len(balances))
a := zeroHash

View File

@ -1,6 +1,7 @@
package doublylinkedtree
import (
"math/big"
"time"
"github.com/prysmaticlabs/prysm/v5/config/params"
@ -78,7 +79,7 @@ func (f *ForkChoice) ShouldOverrideFCU() (override bool) {
// }
// Only orphan a block if the head LMD vote is weak
if head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold {
if f.headVoteIsStrong() {
return
}
@ -92,7 +93,7 @@ func (f *ForkChoice) ShouldOverrideFCU() (override bool) {
return true
}
// Only orphan a block if the parent LMD vote is strong
if parent.weight*100 < f.store.committeeWeight*params.BeaconConfig().ReorgParentWeightThreshold {
if f.parentVoteIsWeak() {
return
}
return true
@ -143,12 +144,12 @@ func (f *ForkChoice) GetProposerHead() [32]byte {
}
// Only orphan a block if the head LMD vote is weak
if head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold {
if f.headVoteIsStrong() {
return head.root
}
// Only orphan a block if the parent LMD vote is strong
if parent.weight*100 < f.store.committeeWeight*params.BeaconConfig().ReorgParentWeightThreshold {
if f.parentVoteIsWeak() {
return head.root
}
@ -163,3 +164,25 @@ func (f *ForkChoice) GetProposerHead() [32]byte {
}
return parent.root
}
// headVoteIsStrong returns true if the head LMD vote is explicitly above the threshold.
func (f *ForkChoice) headVoteIsStrong() bool {
// This function replaces the following upstream code, using big.Int:
// head.weight*100 > f.store.committeeWeight*params.BeaconConfig().ReorgWeightThreshold
head := f.store.headNode
scaledHeadWeight := new(big.Int).Mul(head.weight, big.NewInt(100))
threshold := new(big.Int).SetUint64(params.BeaconConfig().ReorgWeightThreshold)
threshold.Mul(threshold, f.store.committeeWeight)
return scaledHeadWeight.Cmp(threshold) == 1
}
// parentVoteIsWeak returns true if the parent LMD vote is explicitly below the threshold.
func (f *ForkChoice) parentVoteIsWeak() bool {
// This function replaces the following upstream code, using big.Int:
// parent.weight*100 < f.store.committeeWeight*params.BeaconConfig().ReorgParentWeightThreshold
parent := f.store.headNode.parent
scaledParentWeight := new(big.Int).Mul(parent.weight, big.NewInt(100))
threshold := new(big.Int).SetUint64(params.BeaconConfig().ReorgParentWeightThreshold)
threshold.Mul(threshold, f.store.committeeWeight)
return scaledParentWeight.Cmp(threshold) == -1
}

View File

@ -2,6 +2,7 @@ package doublylinkedtree
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/prysm/v5/config/params"
@ -14,9 +15,9 @@ func TestForkChoice_ShouldOverrideFCU(t *testing.T) {
f.justifiedBalances = make([]uint64, f.numActiveValidators)
for i := range f.justifiedBalances {
f.justifiedBalances[i] = uint64(10)
f.store.committeeWeight += uint64(10)
f.store.committeeWeight.Add(f.store.committeeWeight, big.NewInt(10))
}
f.store.committeeWeight /= uint64(params.BeaconConfig().SlotsPerEpoch)
f.store.committeeWeight.Div(f.store.committeeWeight, new(big.Int).SetUint64(uint64(params.BeaconConfig().SlotsPerEpoch)))
ctx := context.Background()
driftGenesisTime(f, 1, 0)
st, root, err := prepareForkchoiceState(ctx, 1, [32]byte{'a'}, [32]byte{}, [32]byte{'A'}, 0, 0)
@ -87,14 +88,14 @@ func TestForkChoice_ShouldOverrideFCU(t *testing.T) {
})
t.Run("parent is weak early call", func(t *testing.T) {
saved := f.store.headNode.parent.weight
f.store.headNode.parent.weight = 0
f.store.headNode.parent.weight = big.NewInt(0)
require.Equal(t, true, f.ShouldOverrideFCU())
f.store.headNode.parent.weight = saved
})
t.Run("parent is weak late call", func(t *testing.T) {
saved := f.store.headNode.parent.weight
driftGenesisTime(f, 2, 11)
f.store.headNode.parent.weight = 0
f.store.headNode.parent.weight = big.NewInt(0)
require.Equal(t, false, f.ShouldOverrideFCU())
f.store.headNode.parent.weight = saved
driftGenesisTime(f, 2, orphanLateBlockFirstThreshold+1)
@ -111,9 +112,9 @@ func TestForkChoice_GetProposerHead(t *testing.T) {
f.justifiedBalances = make([]uint64, f.numActiveValidators)
for i := range f.justifiedBalances {
f.justifiedBalances[i] = uint64(10)
f.store.committeeWeight += uint64(10)
f.store.committeeWeight.Add(f.store.committeeWeight, big.NewInt(10))
}
f.store.committeeWeight /= uint64(params.BeaconConfig().SlotsPerEpoch)
f.store.committeeWeight.Div(f.store.committeeWeight, new(big.Int).SetUint64(uint64(params.BeaconConfig().SlotsPerEpoch)))
ctx := context.Background()
driftGenesisTime(f, 1, 0)
parentRoot := [32]byte{'a'}
@ -187,7 +188,7 @@ func TestForkChoice_GetProposerHead(t *testing.T) {
})
t.Run("parent is weak", func(t *testing.T) {
saved := f.store.headNode.parent.weight
f.store.headNode.parent.weight = 0
f.store.headNode.parent.weight = big.NewInt(0)
require.Equal(t, false, f.ShouldOverrideFCU())
f.store.headNode.parent.weight = saved
})

View File

@ -3,6 +3,7 @@ package doublylinkedtree
import (
"context"
"fmt"
"math/big"
"time"
"github.com/pkg/errors"
@ -45,8 +46,10 @@ func (s *Store) head(ctx context.Context) ([32]byte, error) {
currentEpoch := slots.EpochsSinceGenesis(time.Unix(int64(s.genesisTime), 0))
if !bestDescendant.viableForHead(s.justifiedCheckpoint.Epoch, currentEpoch) {
s.allTipsAreInvalid = true
weight := big.NewInt(10e9)
weight.Div(bestDescendant.weight, weight)
return [32]byte{}, fmt.Errorf("head at slot %d with weight %d is not eligible, finalizedEpoch, justified Epoch %d, %d != %d, %d",
bestDescendant.slot, bestDescendant.weight/10e9, bestDescendant.finalizedEpoch, bestDescendant.justifiedEpoch, s.finalizedCheckpoint.Epoch, s.justifiedCheckpoint.Epoch)
bestDescendant.slot, weight, bestDescendant.finalizedEpoch, bestDescendant.justifiedEpoch, s.finalizedCheckpoint.Epoch, s.justifiedCheckpoint.Epoch)
}
s.allTipsAreInvalid = false
@ -85,6 +88,8 @@ func (s *Store) insert(ctx context.Context,
unrealizedFinalizedEpoch: finalizedEpoch,
optimistic: true,
payloadHash: payloadHash,
balance: big.NewInt(0),
weight: big.NewInt(0),
timestamp: uint64(time.Now().Unix()),
}

View File

@ -1,6 +1,7 @@
package doublylinkedtree
import (
"math/big"
"sync"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice"
@ -30,7 +31,7 @@ type Store struct {
proposerBoostRoot [fieldparams.RootLength]byte // latest block root that was boosted after being received in a timely manner.
previousProposerBoostRoot [fieldparams.RootLength]byte // previous block root that was boosted after being received in a timely manner.
previousProposerBoostScore uint64 // previous proposer boosted root score.
committeeWeight uint64 // tracks the total active validator balance divided by the number of slots per Epoch.
committeeWeight *big.Int // tracks the total active validator balance divided by the number of slots per Epoch.
treeRootNode *Node // the root node of the store tree.
headNode *Node // last head Node
nodeByRoot map[[fieldparams.RootLength]byte]*Node // nodes indexed by roots.
@ -56,8 +57,8 @@ type Node struct {
unrealizedJustifiedEpoch primitives.Epoch // the epoch that would be justified if the block would be advanced to the next epoch.
finalizedEpoch primitives.Epoch // finalizedEpoch of this node.
unrealizedFinalizedEpoch primitives.Epoch // the epoch that would be finalized if the block would be advanced to the next epoch.
balance uint64 // the balance that voted for this node directly
weight uint64 // weight of this node: the total balance including children
balance *big.Int // the balance that voted for this node directly
weight *big.Int // weight of this node: the total balance including children
bestDescendant *Node // bestDescendant node of this node.
optimistic bool // whether the block has been fully validated or not
timestamp uint64 // The timestamp when the node was inserted.

View File

@ -99,8 +99,8 @@ func TestStore_LongFork(t *testing.T) {
headRoot, err = f.Head(ctx)
require.NoError(t, err)
require.Equal(t, [32]byte{'c'}, headRoot)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'c'}].weight)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight.Uint64())
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'c'}].weight.Uint64())
}
// Epoch 1 Epoch 2 Epoch 3
@ -244,8 +244,8 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, err)
require.Equal(t, [32]byte{'d'}, headRoot)
require.Equal(t, primitives.Epoch(2), f.JustifiedCheckpoint().Epoch)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight.Uint64())
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight.Uint64())
// Set current epoch to 3, and H's unrealized checkpoint. Check it's head
driftGenesisTime(f, 99, 0)
require.NoError(t, f.store.setUnrealizedJustifiedEpoch([32]byte{'h'}, 2))
@ -253,8 +253,8 @@ func TestStore_ForkNextEpoch(t *testing.T) {
require.NoError(t, err)
require.Equal(t, [32]byte{'h'}, headRoot)
require.Equal(t, primitives.Epoch(2), f.JustifiedCheckpoint().Epoch)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight)
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight)
require.Equal(t, uint64(0), f.store.nodeByRoot[[32]byte{'d'}].weight.Uint64())
require.Equal(t, uint64(100), f.store.nodeByRoot[[32]byte{'h'}].weight.Uint64())
}
func TestStore_PullTips_Heuristics(t *testing.T) {

View File

@ -2,6 +2,7 @@ package forkchoice
import (
"context"
"math/big"
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
@ -79,7 +80,7 @@ type FastGetter interface {
Slot([32]byte) (primitives.Slot, error)
TargetRootForEpoch([32]byte, primitives.Epoch) ([32]byte, error)
UnrealizedJustifiedPayloadBlockHash() [32]byte
Weight(root [32]byte) (uint64, error)
Weight(root [32]byte) (*big.Int, error)
}
// Setter allows to set forkchoice information

View File

@ -1,6 +1,8 @@
package forkchoice
import (
"math/big"
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
@ -129,7 +131,7 @@ func (ro *ROForkChoice) ReceivedBlocksLastEpoch() (uint64, error) {
}
// Weight delegates to the underlying forkchoice call, under a lock.
func (ro *ROForkChoice) Weight(root [32]byte) (uint64, error) {
func (ro *ROForkChoice) Weight(root [32]byte) (*big.Int, error) {
ro.l.RLock()
defer ro.l.RUnlock()
return ro.getter.Weight(root)

View File

@ -2,6 +2,7 @@ package forkchoice
import (
"io"
"math/big"
"testing"
forkchoicetypes "github.com/prysmaticlabs/prysm/v5/beacon-chain/forkchoice/types"
@ -261,9 +262,9 @@ func (ro *mockROForkchoice) ReceivedBlocksLastEpoch() (uint64, error) {
return 0, nil
}
func (ro *mockROForkchoice) Weight(_ [32]byte) (uint64, error) {
func (ro *mockROForkchoice) Weight(_ [32]byte) (*big.Int, error) {
ro.calls = append(ro.calls, weightCalled)
return 0, nil
return new(big.Int), nil
}
func (ro *mockROForkchoice) IsOptimistic(_ [32]byte) (bool, error) {

View File

@ -3,6 +3,7 @@ package beacon
import (
"context"
"fmt"
"math/big"
"sort"
"strconv"
@ -543,21 +544,36 @@ func (bs *Server) GetValidatorParticipation(
}
cp := bs.FinalizationFetcher.FinalizedCheckpt()
var globalParticipationRate float32
zero := big.NewInt(0)
if b.PrevEpochTargetAttested.Cmp(zero) == 1 || b.ActivePrevEpoch.Cmp(zero) == 1 {
prevEpochTargetAttested, f1 := new(big.Float).SetString(b.PrevEpochTargetAttested.String())
if !f1 {
globalParticipationRate = float32(0)
}
activePrevEpoch, f2 := new(big.Float).SetString(b.ActivePrevEpoch.String())
if !f2 {
globalParticipationRate = float32(0)
}
if f1 && f2 {
globalParticipationRate, _ = new(big.Float).Quo(prevEpochTargetAttested, activePrevEpoch).Float32()
}
}
p := &ethpb.ValidatorParticipationResponse{
Epoch: requestedEpoch,
Finalized: requestedEpoch <= cp.Epoch,
Participation: &ethpb.ValidatorParticipation{
// TODO(7130): Remove these three deprecated fields.
GlobalParticipationRate: float32(b.PrevEpochTargetAttested) / float32(b.ActivePrevEpoch),
VotedEther: b.PrevEpochTargetAttested,
EligibleEther: b.ActivePrevEpoch,
CurrentEpochActiveGwei: b.ActiveCurrentEpoch,
CurrentEpochAttestingGwei: b.CurrentEpochAttested,
CurrentEpochTargetAttestingGwei: b.CurrentEpochTargetAttested,
PreviousEpochActiveGwei: b.ActivePrevEpoch,
PreviousEpochAttestingGwei: b.PrevEpochAttested,
PreviousEpochTargetAttestingGwei: b.PrevEpochTargetAttested,
PreviousEpochHeadAttestingGwei: b.PrevEpochHeadAttested,
GlobalParticipationRate: globalParticipationRate,
VotedEther: b.PrevEpochTargetAttested.String(),
EligibleEther: b.ActivePrevEpoch.String(),
CurrentEpochActiveGwei: b.ActiveCurrentEpoch.String(),
CurrentEpochAttestingGwei: b.CurrentEpochAttested.String(),
CurrentEpochTargetAttestingGwei: b.CurrentEpochTargetAttested.String(),
PreviousEpochActiveGwei: b.ActivePrevEpoch.String(),
PreviousEpochAttestingGwei: b.PrevEpochAttested.String(),
PreviousEpochTargetAttestingGwei: b.PrevEpochTargetAttested.String(),
PreviousEpochHeadAttestingGwei: b.PrevEpochHeadAttested.String(),
},
}

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/binary"
"fmt"
"math/big"
"sort"
"strconv"
"testing"
@ -1566,18 +1567,35 @@ func TestServer_GetValidatorParticipation_CurrentAndPrevEpoch(t *testing.T) {
res, err := bs.GetValidatorParticipation(ctx, &ethpb.GetValidatorParticipationRequest{QueryFilter: &ethpb.GetValidatorParticipationRequest_Epoch{Epoch: 1}})
require.NoError(t, err)
effectiveBal := new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance)
effectiveBalIncr := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
valCountTimesEffBal := new(big.Int).Mul(new(big.Int).SetUint64(validatorCount), effectiveBal)
var globalParticipationRate float32
zero := big.NewInt(0)
if effectiveBalIncr.Cmp(zero) == 1 || valCountTimesEffBal.Cmp(zero) == 1 {
prevEpochTargetAttested, f1 := new(big.Float).SetString(effectiveBalIncr.String())
if !f1 {
globalParticipationRate = float32(0)
}
activePrevEpoch, f2 := new(big.Float).SetString(valCountTimesEffBal.String())
if !f2 {
globalParticipationRate = float32(0)
}
if f1 && f2 {
globalParticipationRate, _ = new(big.Float).Quo(prevEpochTargetAttested, activePrevEpoch).Float32()
}
}
wanted := &ethpb.ValidatorParticipation{
GlobalParticipationRate: float32(params.BeaconConfig().EffectiveBalanceIncrement) / float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance),
VotedEther: params.BeaconConfig().EffectiveBalanceIncrement,
EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochHeadAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
GlobalParticipationRate: globalParticipationRate,
VotedEther: effectiveBalIncr.String(),
EligibleEther: valCountTimesEffBal.String(),
CurrentEpochActiveGwei: valCountTimesEffBal.String(),
CurrentEpochAttestingGwei: effectiveBalIncr.String(),
CurrentEpochTargetAttestingGwei: effectiveBalIncr.String(),
PreviousEpochActiveGwei: valCountTimesEffBal.String(),
PreviousEpochAttestingGwei: effectiveBalIncr.String(),
PreviousEpochTargetAttestingGwei: effectiveBalIncr.String(),
PreviousEpochHeadAttestingGwei: effectiveBalIncr.String(),
}
assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond")
assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond")
@ -1646,17 +1664,35 @@ func TestServer_GetValidatorParticipation_OrphanedUntilGenesis(t *testing.T) {
res, err := bs.GetValidatorParticipation(ctx, &ethpb.GetValidatorParticipationRequest{QueryFilter: &ethpb.GetValidatorParticipationRequest_Epoch{Epoch: 1}})
require.NoError(t, err)
effectiveBal := new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance)
effectiveBalIncr := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
valCountTimesEffBal := new(big.Int).Mul(new(big.Int).SetUint64(validatorCount), effectiveBal)
var globalParticipationRate float32
zero := big.NewInt(0)
if effectiveBalIncr.Cmp(zero) == 1 || valCountTimesEffBal.Cmp(zero) == 1 {
prevEpochTargetAttested, f1 := new(big.Float).SetString(effectiveBalIncr.String())
if !f1 {
globalParticipationRate = float32(0)
}
activePrevEpoch, f2 := new(big.Float).SetString(valCountTimesEffBal.String())
if !f2 {
globalParticipationRate = float32(0)
}
if f1 && f2 {
globalParticipationRate, _ = new(big.Float).Quo(prevEpochTargetAttested, activePrevEpoch).Float32()
}
}
wanted := &ethpb.ValidatorParticipation{
GlobalParticipationRate: float32(params.BeaconConfig().EffectiveBalanceIncrement) / float32(validatorCount*params.BeaconConfig().MaxEffectiveBalance),
VotedEther: params.BeaconConfig().EffectiveBalanceIncrement,
EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
CurrentEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochHeadAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
GlobalParticipationRate: globalParticipationRate,
VotedEther: effectiveBalIncr.String(),
EligibleEther: valCountTimesEffBal.String(),
CurrentEpochActiveGwei: valCountTimesEffBal.String(),
CurrentEpochAttestingGwei: effectiveBalIncr.String(),
CurrentEpochTargetAttestingGwei: effectiveBalIncr.String(),
PreviousEpochActiveGwei: valCountTimesEffBal.String(),
PreviousEpochAttestingGwei: effectiveBalIncr.String(),
PreviousEpochTargetAttestingGwei: effectiveBalIncr.String(),
PreviousEpochHeadAttestingGwei: effectiveBalIncr.String(),
}
assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond")
assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond")
@ -1757,17 +1793,20 @@ func runGetValidatorParticipationCurrentAndPrevEpoch(t *testing.T, genState stat
res, err := bs.GetValidatorParticipation(ctx, &ethpb.GetValidatorParticipationRequest{QueryFilter: &ethpb.GetValidatorParticipationRequest_Epoch{Epoch: 0}})
require.NoError(t, err)
effectiveBal := new(big.Int).SetUint64(params.BeaconConfig().MaxEffectiveBalance)
effectiveBalIncr := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
valCountTimesEffBal := new(big.Int).Mul(new(big.Int).SetUint64(validatorCount), effectiveBal)
wanted := &ethpb.ValidatorParticipation{
GlobalParticipationRate: 1,
VotedEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochTargetAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochTargetAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochHeadAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
GlobalParticipationRate: float32(1),
VotedEther: valCountTimesEffBal.String(),
EligibleEther: valCountTimesEffBal.String(),
CurrentEpochActiveGwei: valCountTimesEffBal.String(),
CurrentEpochAttestingGwei: valCountTimesEffBal.String(),
CurrentEpochTargetAttestingGwei: valCountTimesEffBal.String(),
PreviousEpochActiveGwei: valCountTimesEffBal.String(),
PreviousEpochAttestingGwei: valCountTimesEffBal.String(),
PreviousEpochTargetAttestingGwei: valCountTimesEffBal.String(),
PreviousEpochHeadAttestingGwei: valCountTimesEffBal.String(),
}
assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond")
assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond")
@ -1776,16 +1815,16 @@ func runGetValidatorParticipationCurrentAndPrevEpoch(t *testing.T, genState stat
require.NoError(t, err)
wanted = &ethpb.ValidatorParticipation{
GlobalParticipationRate: 1,
VotedEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
EligibleEther: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
CurrentEpochAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement, // Empty because after one epoch, current participation rotates to previous
CurrentEpochTargetAttestingGwei: params.BeaconConfig().EffectiveBalanceIncrement,
PreviousEpochActiveGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochTargetAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
PreviousEpochHeadAttestingGwei: validatorCount * params.BeaconConfig().MaxEffectiveBalance,
GlobalParticipationRate: float32(1),
VotedEther: valCountTimesEffBal.String(),
EligibleEther: valCountTimesEffBal.String(),
CurrentEpochActiveGwei: valCountTimesEffBal.String(),
CurrentEpochAttestingGwei: effectiveBalIncr.String(), // Empty because after one epoch, current participation rotates to previous
CurrentEpochTargetAttestingGwei: effectiveBalIncr.String(),
PreviousEpochActiveGwei: valCountTimesEffBal.String(),
PreviousEpochAttestingGwei: valCountTimesEffBal.String(),
PreviousEpochTargetAttestingGwei: valCountTimesEffBal.String(),
PreviousEpochHeadAttestingGwei: valCountTimesEffBal.String(),
}
assert.DeepEqual(t, true, res.Finalized, "Incorrect validator participation respond")
assert.DeepEqual(t, wanted, res.Participation, "Incorrect validator participation respond")

View File

@ -6,6 +6,7 @@ package state
import (
"context"
"encoding/json"
"math/big"
"github.com/prysmaticlabs/go-bitfield"
fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams"
@ -143,7 +144,7 @@ type ReadOnlyCheckpoint interface {
FinalizedCheckpoint() *ethpb.Checkpoint
FinalizedCheckpointEpoch() primitives.Epoch
JustificationBits() bitfield.Bitvector4
UnrealizedCheckpointBalances() (uint64, uint64, uint64, error)
UnrealizedCheckpointBalances() (*big.Int, *big.Int, *big.Int, error)
}
// ReadOnlyBlockRoots defines a struct which only has read access to block roots methods.

View File

@ -1,6 +1,8 @@
package state_native
import (
"math/big"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state/stateutil"
"github.com/prysmaticlabs/prysm/v5/config/features"
@ -42,9 +44,9 @@ func (b *BeaconState) PreviousEpochParticipation() ([]byte, error) {
// UnrealizedCheckpointBalances returns the total balances: active, target attested in
// current epoch and target attested in previous epoch. This function is used to
// compute the "unrealized justification" that a synced Beacon Block will have.
func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, error) {
func (b *BeaconState) UnrealizedCheckpointBalances() (*big.Int, *big.Int, *big.Int, error) {
if b.version == version.Phase0 {
return 0, 0, 0, errNotSupported("UnrealizedCheckpointBalances", b.version)
return big.NewInt(0), big.NewInt(0), big.NewInt(0), errNotSupported("UnrealizedCheckpointBalances", b.version)
}
currentEpoch := time.CurrentEpoch(b)
@ -54,7 +56,7 @@ func (b *BeaconState) UnrealizedCheckpointBalances() (uint64, uint64, uint64, er
cp := b.currentEpochParticipation
pp := b.previousEpochParticipation
if cp == nil || pp == nil {
return 0, 0, 0, ErrNilParticipation
return big.NewInt(0), big.NewInt(0), big.NewInt(0), ErrNilParticipation
}
if features.Get().EnableExperimentalState {

View File

@ -34,9 +34,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
allActive := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
active, previous, current, err := state.UnrealizedCheckpointBalances()
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(t, allActive, active.Uint64())
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
// Add some votes in the last two epochs:
base.CurrentEpochParticipation[0] = 0xFF
@ -47,9 +47,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current)
require.Equal(t, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(t, allActive, active.Uint64())
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, current.Uint64())
require.Equal(t, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
// Slash some validators
validators[0].Slashed = true
@ -57,8 +57,8 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
require.NoError(t, err)
active, previous, current, err = state.UnrealizedCheckpointBalances()
require.NoError(t, err)
require.Equal(t, allActive, active)
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(t, allActive, active.Uint64())
require.Equal(t, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
}

View File

@ -1,10 +1,11 @@
package stateutil
import (
"math/big"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/math"
)
// UnrealizedCheckpointBalances returns the total current active balance, the
@ -12,58 +13,50 @@ import (
// current epoch correctly attested for target balance. It takes the current and
// previous epoch participation bits as parameters so implicitly only works for
// beacon states post-Altair.
func UnrealizedCheckpointBalances(cp, pp []byte, validators ValReader, currentEpoch primitives.Epoch) (uint64, uint64, uint64, error) {
func UnrealizedCheckpointBalances(cp, pp []byte, validators ValReader, currentEpoch primitives.Epoch) (*big.Int, *big.Int, *big.Int, error) {
targetIdx := params.BeaconConfig().TimelyTargetFlagIndex
activeBalance := uint64(0)
currentTarget := uint64(0)
prevTarget := uint64(0)
activeBalance := big.NewInt(0)
currentTarget := big.NewInt(0)
prevTarget := big.NewInt(0)
if len(cp) < validators.Len() || len(pp) < validators.Len() {
return 0, 0, 0, errors.New("participation does not match validator set")
return activeBalance, currentTarget, prevTarget, errors.New("participation does not match validator set")
}
valLength := validators.Len()
for i := 0; i < valLength; i++ {
v, err := validators.At(i)
if err != nil {
return 0, 0, 0, err
return activeBalance, currentTarget, prevTarget, err
}
activeCurrent := v.ActivationEpoch <= currentEpoch && currentEpoch < v.ExitEpoch
effectiveBalance := new(big.Int).SetUint64(v.EffectiveBalance)
if activeCurrent {
activeBalance, err = math.Add64(activeBalance, v.EffectiveBalance)
if err != nil {
return 0, 0, 0, err
}
activeBalance.Add(activeBalance, effectiveBalance)
}
if v.Slashed {
continue
}
if activeCurrent && ((cp[i]>>targetIdx)&1) == 1 {
currentTarget, err = math.Add64(currentTarget, v.EffectiveBalance)
if err != nil {
return 0, 0, 0, err
}
currentTarget.Add(currentTarget, effectiveBalance)
}
activePrevious := v.ActivationEpoch < currentEpoch && currentEpoch <= v.ExitEpoch
if activePrevious && ((pp[i]>>targetIdx)&1) == 1 {
prevTarget, err = math.Add64(prevTarget, v.EffectiveBalance)
if err != nil {
return 0, 0, 0, err
}
prevTarget.Add(prevTarget, effectiveBalance)
}
}
activeBalance, prevTarget, currentTarget = ensureLowerBound(activeBalance, prevTarget, currentTarget)
return activeBalance, prevTarget, currentTarget, nil
}
func ensureLowerBound(activeCurrEpoch, prevTargetAttested, currTargetAttested uint64) (uint64, uint64, uint64) {
ebi := params.BeaconConfig().EffectiveBalanceIncrement
if ebi > activeCurrEpoch {
func ensureLowerBound(activeCurrEpoch, prevTargetAttested, currTargetAttested *big.Int) (*big.Int, *big.Int, *big.Int) {
ebi := new(big.Int).SetUint64(params.BeaconConfig().EffectiveBalanceIncrement)
if ebi.Cmp(activeCurrEpoch) > 0 {
activeCurrEpoch = ebi
}
if ebi > prevTargetAttested {
if ebi.Cmp(prevTargetAttested) > 0 {
prevTargetAttested = ebi
}
if ebi > currTargetAttested {
if ebi.Cmp(currTargetAttested) > 0 {
currTargetAttested = ebi
}
return activeCurrEpoch, prevTargetAttested, currTargetAttested

View File

@ -28,9 +28,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
t.Run("No one voted last two epochs", func(tt *testing.T) {
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 0)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("bad votes in last two epochs", func(tt *testing.T) {
@ -38,9 +38,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0x00, 0x00, 0x00, 0x00})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("two votes in last epoch", func(tt *testing.T) {
@ -48,9 +48,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0x00, 0x00, 0x00, 0x00, 0xFF ^ (1 << targetFlag)})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("two votes in previous epoch", func(tt *testing.T) {
@ -58,9 +58,9 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00, 1 << targetFlag, 1 << targetFlag})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("votes in both epochs, decreased balance in first validator", func(tt *testing.T) {
@ -70,27 +70,27 @@ func TestState_UnrealizedCheckpointBalances(t *testing.T) {
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 1)
require.NoError(tt, err)
expectedActive -= params.BeaconConfig().MinDepositAmount
require.Equal(tt, expectedActive, active)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("slash a validator", func(tt *testing.T) {
validators[1].Slashed = true
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("Exit a validator", func(tt *testing.T) {
validators[4].ExitEpoch = 1
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValSliceReader(validators), 2)
require.NoError(tt, err)
expectedActive -= params.BeaconConfig().MaxEffectiveBalance
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
}
@ -117,9 +117,9 @@ func TestState_MVSlice_UnrealizedCheckpointBalances(t *testing.T) {
t.Run("No one voted last two epochs", func(tt *testing.T) {
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 0)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("bad votes in last two epochs", func(tt *testing.T) {
@ -127,9 +127,9 @@ func TestState_MVSlice_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0x00, 0x00, 0x00, 0x00})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("two votes in last epoch", func(tt *testing.T) {
@ -137,9 +137,9 @@ func TestState_MVSlice_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0x00, 0x00, 0x00, 0x00, 0xFF ^ (1 << targetFlag)})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, current)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, current.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, previous.Uint64())
})
t.Run("two votes in previous epoch", func(tt *testing.T) {
@ -147,9 +147,9 @@ func TestState_MVSlice_UnrealizedCheckpointBalances(t *testing.T) {
copy(pp, []byte{0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0xFF ^ (1 << targetFlag), 0x00, 1 << targetFlag, 1 << targetFlag})
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().EffectiveBalanceIncrement, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("votes in both epochs, decreased balance in first validator", func(tt *testing.T) {
@ -159,27 +159,27 @@ func TestState_MVSlice_UnrealizedCheckpointBalances(t *testing.T) {
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 1)
require.NoError(tt, err)
expectedActive -= params.BeaconConfig().MinDepositAmount
require.Equal(tt, expectedActive, active)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("slash a validator", func(tt *testing.T) {
validators[1].Slashed = true
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 1)
require.NoError(tt, err)
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, 2*params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
t.Run("Exit a validator", func(tt *testing.T) {
validators[4].ExitEpoch = 1
active, previous, current, err := UnrealizedCheckpointBalances(cp, pp, NewValMultiValueSliceReader(mv, &testObject{id: 0}), 2)
require.NoError(tt, err)
expectedActive -= params.BeaconConfig().MaxEffectiveBalance
require.Equal(tt, expectedActive, active)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current)
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance, previous)
require.Equal(tt, expectedActive, active.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance-params.BeaconConfig().MinDepositAmount, current.Uint64())
require.Equal(tt, params.BeaconConfig().MaxEffectiveBalance, previous.Uint64())
})
}

View File

@ -1,6 +1,8 @@
package forkchoice
import (
"math/big"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)
@ -45,8 +47,8 @@ type Node struct {
FinalizedEpoch primitives.Epoch
UnrealizedJustifiedEpoch primitives.Epoch
UnrealizedFinalizedEpoch primitives.Epoch
Balance uint64
Weight uint64
Balance *big.Int
Weight *big.Int
Timestamp uint64
BlockRoot []byte
ParentRoot []byte

View File

@ -1904,16 +1904,16 @@ type ValidatorParticipation struct {
// Deprecated: Marked as deprecated in proto/prysm/v1alpha1/validator.proto.
GlobalParticipationRate float32 `protobuf:"fixed32,1,opt,name=global_participation_rate,json=globalParticipationRate,proto3" json:"global_participation_rate,omitempty"`
// Deprecated: Marked as deprecated in proto/prysm/v1alpha1/validator.proto.
VotedEther uint64 `protobuf:"varint,2,opt,name=voted_ether,json=votedEther,proto3" json:"voted_ether,omitempty"`
VotedEther string `protobuf:"bytes,2,opt,name=voted_ether,json=votedEther,proto3" json:"voted_ether,omitempty"`
// Deprecated: Marked as deprecated in proto/prysm/v1alpha1/validator.proto.
EligibleEther uint64 `protobuf:"varint,3,opt,name=eligible_ether,json=eligibleEther,proto3" json:"eligible_ether,omitempty"`
CurrentEpochActiveGwei uint64 `protobuf:"varint,4,opt,name=current_epoch_active_gwei,json=currentEpochActiveGwei,proto3" json:"current_epoch_active_gwei,omitempty"`
CurrentEpochAttestingGwei uint64 `protobuf:"varint,5,opt,name=current_epoch_attesting_gwei,json=currentEpochAttestingGwei,proto3" json:"current_epoch_attesting_gwei,omitempty"`
CurrentEpochTargetAttestingGwei uint64 `protobuf:"varint,6,opt,name=current_epoch_target_attesting_gwei,json=currentEpochTargetAttestingGwei,proto3" json:"current_epoch_target_attesting_gwei,omitempty"`
PreviousEpochActiveGwei uint64 `protobuf:"varint,7,opt,name=previous_epoch_active_gwei,json=previousEpochActiveGwei,proto3" json:"previous_epoch_active_gwei,omitempty"`
PreviousEpochAttestingGwei uint64 `protobuf:"varint,8,opt,name=previous_epoch_attesting_gwei,json=previousEpochAttestingGwei,proto3" json:"previous_epoch_attesting_gwei,omitempty"`
PreviousEpochTargetAttestingGwei uint64 `protobuf:"varint,9,opt,name=previous_epoch_target_attesting_gwei,json=previousEpochTargetAttestingGwei,proto3" json:"previous_epoch_target_attesting_gwei,omitempty"`
PreviousEpochHeadAttestingGwei uint64 `protobuf:"varint,10,opt,name=previous_epoch_head_attesting_gwei,json=previousEpochHeadAttestingGwei,proto3" json:"previous_epoch_head_attesting_gwei,omitempty"`
EligibleEther string `protobuf:"bytes,3,opt,name=eligible_ether,json=eligibleEther,proto3" json:"eligible_ether,omitempty"`
CurrentEpochActiveGwei string `protobuf:"bytes,4,opt,name=current_epoch_active_gwei,json=currentEpochActiveGwei,proto3" json:"current_epoch_active_gwei,omitempty"`
CurrentEpochAttestingGwei string `protobuf:"bytes,5,opt,name=current_epoch_attesting_gwei,json=currentEpochAttestingGwei,proto3" json:"current_epoch_attesting_gwei,omitempty"`
CurrentEpochTargetAttestingGwei string `protobuf:"bytes,6,opt,name=current_epoch_target_attesting_gwei,json=currentEpochTargetAttestingGwei,proto3" json:"current_epoch_target_attesting_gwei,omitempty"`
PreviousEpochActiveGwei string `protobuf:"bytes,7,opt,name=previous_epoch_active_gwei,json=previousEpochActiveGwei,proto3" json:"previous_epoch_active_gwei,omitempty"`
PreviousEpochAttestingGwei string `protobuf:"bytes,8,opt,name=previous_epoch_attesting_gwei,json=previousEpochAttestingGwei,proto3" json:"previous_epoch_attesting_gwei,omitempty"`
PreviousEpochTargetAttestingGwei string `protobuf:"bytes,9,opt,name=previous_epoch_target_attesting_gwei,json=previousEpochTargetAttestingGwei,proto3" json:"previous_epoch_target_attesting_gwei,omitempty"`
PreviousEpochHeadAttestingGwei string `protobuf:"bytes,10,opt,name=previous_epoch_head_attesting_gwei,json=previousEpochHeadAttestingGwei,proto3" json:"previous_epoch_head_attesting_gwei,omitempty"`
}
func (x *ValidatorParticipation) Reset() {
@ -1957,68 +1957,68 @@ func (x *ValidatorParticipation) GetGlobalParticipationRate() float32 {
}
// Deprecated: Marked as deprecated in proto/prysm/v1alpha1/validator.proto.
func (x *ValidatorParticipation) GetVotedEther() uint64 {
func (x *ValidatorParticipation) GetVotedEther() string {
if x != nil {
return x.VotedEther
}
return 0
return ""
}
// Deprecated: Marked as deprecated in proto/prysm/v1alpha1/validator.proto.
func (x *ValidatorParticipation) GetEligibleEther() uint64 {
func (x *ValidatorParticipation) GetEligibleEther() string {
if x != nil {
return x.EligibleEther
}
return 0
return ""
}
func (x *ValidatorParticipation) GetCurrentEpochActiveGwei() uint64 {
func (x *ValidatorParticipation) GetCurrentEpochActiveGwei() string {
if x != nil {
return x.CurrentEpochActiveGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetCurrentEpochAttestingGwei() uint64 {
func (x *ValidatorParticipation) GetCurrentEpochAttestingGwei() string {
if x != nil {
return x.CurrentEpochAttestingGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetCurrentEpochTargetAttestingGwei() uint64 {
func (x *ValidatorParticipation) GetCurrentEpochTargetAttestingGwei() string {
if x != nil {
return x.CurrentEpochTargetAttestingGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetPreviousEpochActiveGwei() uint64 {
func (x *ValidatorParticipation) GetPreviousEpochActiveGwei() string {
if x != nil {
return x.PreviousEpochActiveGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetPreviousEpochAttestingGwei() uint64 {
func (x *ValidatorParticipation) GetPreviousEpochAttestingGwei() string {
if x != nil {
return x.PreviousEpochAttestingGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetPreviousEpochTargetAttestingGwei() uint64 {
func (x *ValidatorParticipation) GetPreviousEpochTargetAttestingGwei() string {
if x != nil {
return x.PreviousEpochTargetAttestingGwei
}
return 0
return ""
}
func (x *ValidatorParticipation) GetPreviousEpochHeadAttestingGwei() uint64 {
func (x *ValidatorParticipation) GetPreviousEpochHeadAttestingGwei() string {
if x != nil {
return x.PreviousEpochHeadAttestingGwei
}
return 0
return ""
}
type ValidatorInfo struct {
@ -3417,39 +3417,39 @@ var file_proto_prysm_v1alpha1_validator_proto_rawDesc = []byte{
0x72, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x42, 0x02, 0x18, 0x01, 0x52, 0x17,
0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x65, 0x12, 0x23, 0x0a, 0x0b, 0x76, 0x6f, 0x74, 0x65, 0x64,
0x5f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01,
0x5f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01,
0x52, 0x0a, 0x76, 0x6f, 0x74, 0x65, 0x64, 0x45, 0x74, 0x68, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x0e,
0x65, 0x6c, 0x69, 0x67, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x18, 0x03,
0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0d, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62,
0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0d, 0x65, 0x6c, 0x69, 0x67, 0x69, 0x62,
0x6c, 0x65, 0x45, 0x74, 0x68, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x75, 0x72, 0x72, 0x65,
0x6e, 0x74, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f,
0x67, 0x77, 0x65, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x75, 0x72, 0x72,
0x67, 0x77, 0x65, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x75, 0x72, 0x72,
0x65, 0x6e, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x77,
0x65, 0x69, 0x12, 0x3f, 0x0a, 0x1c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x70,
0x6f, 0x63, 0x68, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77,
0x65, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x65, 0x69, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x19, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x47,
0x77, 0x65, 0x69, 0x12, 0x4c, 0x0a, 0x23, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x65,
0x70, 0x6f, 0x63, 0x68, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x65,
0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04,
0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x52, 0x1f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x54, 0x61,
0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x77, 0x65,
0x69, 0x12, 0x3b, 0x0a, 0x1a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x65, 0x70,
0x6f, 0x63, 0x68, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18,
0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45,
0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x17, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45,
0x70, 0x6f, 0x63, 0x68, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x47, 0x77, 0x65, 0x69, 0x12, 0x41,
0x0a, 0x1d, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x65, 0x70, 0x6f, 0x63, 0x68,
0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18,
0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45,
0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45,
0x70, 0x6f, 0x63, 0x68, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x77, 0x65,
0x69, 0x12, 0x4e, 0x0a, 0x24, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x65, 0x70,
0x6f, 0x63, 0x68, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73,
0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52,
0x74, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x20, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x54, 0x61,
0x72, 0x67, 0x65, 0x74, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x77, 0x65,
0x69, 0x12, 0x4a, 0x0a, 0x22, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x65, 0x70,
0x6f, 0x63, 0x68, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69,
0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1e, 0x70,
0x6e, 0x67, 0x5f, 0x67, 0x77, 0x65, 0x69, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1e, 0x70,
0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x45, 0x70, 0x6f, 0x63, 0x68, 0x48, 0x65, 0x61, 0x64,
0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x47, 0x77, 0x65, 0x69, 0x22, 0xad, 0x03,
0x0a, 0x0d, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12,

View File

@ -665,24 +665,24 @@ message ValidatorParticipation {
// contains a value between 0 and 1.
float global_participation_rate = 1 [deprecated = true];
// The total amount of ether, in gwei, that has been used in voting.
uint64 voted_ether = 2 [deprecated = true];
string voted_ether = 2 [deprecated = true];
// The total amount of ether, in gwei, that is eligible for voting.
uint64 eligible_ether = 3 [deprecated = true];
string eligible_ether = 3 [deprecated = true];
// Total staked gwei that was active (i.e. eligible to vote) during the current epoch.
uint64 current_epoch_active_gwei = 4;
string current_epoch_active_gwei = 4;
// Total staked gwei that had attestations included in a block during the current epoch,
// attestations by the same validator do not increase this figure.
uint64 current_epoch_attesting_gwei = 5;
string current_epoch_attesting_gwei = 5;
// Total staked gwei that attested to the majority-elected Casper FFG target epoch during the current epoch.
uint64 current_epoch_target_attesting_gwei = 6;
string current_epoch_target_attesting_gwei = 6;
// Same as current_epoch_active_gwei but for previous epoch.
uint64 previous_epoch_active_gwei = 7;
string previous_epoch_active_gwei = 7;
// Same as current_epoch_attesting_gwei but for previous epoch.
uint64 previous_epoch_attesting_gwei = 8;
string previous_epoch_attesting_gwei = 8;
// Same as current_epoch_target_attesting_gwei but for previous epoch.
uint64 previous_epoch_target_attesting_gwei = 9;
string previous_epoch_target_attesting_gwei = 9;
// Total staked gwei that attested to a head beacon block that is in the canonical chain.
uint64 previous_epoch_head_attesting_gwei = 10;
string previous_epoch_head_attesting_gwei = 10;
}
// ValidatorInfo gives information about the state of a validator at a certain epoch.

123
pulse/pulse_rewards_test.go Normal file
View File

@ -0,0 +1,123 @@
package pulse_test
import (
"context"
"math/big"
"testing"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/altair"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/time"
p2pType "github.com/prysmaticlabs/prysm/v5/beacon-chain/p2p/types"
"github.com/prysmaticlabs/prysm/v5/config/params"
types "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
"github.com/prysmaticlabs/prysm/v5/time/slots"
)
func TestPulseChainValidatorRewardsMock(t *testing.T) {
cfg := params.MainnetConfig()
cfg.BaseRewardFactor = 780000
cfg.MinDepositAmount = 16000000000000000
cfg.MaxEffectiveBalance = 32000000000000000
params.OverrideBeaconConfig(cfg)
// Vars
numOfVals := uint64(18312)
slotsPerEpoch := uint64(32)
amountOfEpochsToProcess := 5
// Generate genesis Beaconchain state with required num of vals and deposit amounts
beaconState, privKeys := util.DeterministicGenesisStateBellatrix(t, numOfVals)
validators, balance, err := altair.InitializePrecomputeValidators(context.Background(), beaconState)
require.NoError(t, err)
// Generate perfect participation object
// All validators are participating 100% meaning no penalties accounted
participation := make([]byte, numOfVals)
inds := make([]uint64, numOfVals)
for i := 0; i < len(participation); i++ {
participation[i] = generateParticipation(params.BeaconConfig().TimelySourceFlagIndex, params.BeaconConfig().TimelyTargetFlagIndex, params.BeaconConfig().TimelyHeadFlagIndex)
inds[i] = uint64(i)
}
// Loop for simulating slot progression
// Sync rewards being processed per each slot
// Epoch rewards being processed per each epoch
var slotCounter uint64
for i := 0; i < int(slotsPerEpoch)*amountOfEpochsToProcess; i++ {
// Progress 1 slot each itteration
require.NoError(t, beaconState.SetSlot(types.Slot(i+1)))
slotCounter++
// Assign sync committee
committee, err := altair.NextSyncCommittee(context.Background(), beaconState)
require.NoError(t, err)
require.NoError(t, beaconState.SetCurrentSyncCommittee(committee))
// Define signatures
syncBits := bitfield.NewBitvector512()
for i := range syncBits {
syncBits[i] = 0xff
}
indices, err := altair.NextSyncCommitteeIndices(context.Background(), beaconState)
require.NoError(t, err)
ps := slots.PrevSlot(beaconState.Slot())
pbr, err := helpers.BlockRootAtSlot(beaconState, ps)
require.NoError(t, err)
sigs := make([]bls.Signature, len(indices))
for i, indice := range indices {
b := p2pType.SSZBytes(pbr)
sb, err := signing.ComputeDomainAndSign(beaconState, time.CurrentEpoch(beaconState), &b, params.BeaconConfig().DomainSyncCommittee, privKeys[indice])
require.NoError(t, err)
sig, err := bls.SignatureFromBytes(sb)
require.NoError(t, err)
sigs[i] = sig
}
aggregatedSig := bls.AggregateSignatures(sigs).Marshal()
syncAggregate := &ethpb.SyncAggregate{
SyncCommitteeBits: syncBits,
SyncCommitteeSignature: aggregatedSig,
}
// Process Sync aggregation and process rewards
beaconState, _, err = altair.ProcessSyncAggregate(context.Background(), beaconState, syncAggregate)
require.NoError(t, err)
// If epoch passed - process participation and rewards
if slotCounter == 32 {
slotCounter = 0
require.NoError(t, beaconState.SetCurrentParticipationBits(participation))
require.NoError(t, beaconState.SetPreviousParticipationBits(participation))
validators, balance, err = altair.ProcessEpochParticipation(context.Background(), beaconState, balance, validators)
require.NoError(t, err)
beaconState, err = altair.ProcessRewardsAndPenaltiesPrecompute(beaconState, balance, validators)
require.NoError(t, err)
}
}
// Count total rewards after simulation
var totalRewards *big.Int = big.NewInt(0)
bal := beaconState.Balances()
for i := 0; i < len(bal); i++ {
totalRewards.Add(totalRewards, new(big.Int).Sub(new(big.Int).SetUint64(bal[i]), new(big.Int).SetUint64(cfg.MaxEffectiveBalance)))
}
t.Log("totalRewards:", totalRewards)
}
// Helper function to generate participation
func generateParticipation(flags ...uint8) byte {
b := byte(0)
var err error
for _, flag := range flags {
b, err = altair.AddValidatorFlag(b, flag)
if err != nil {
return 0
}
}
return b
}

View File

@ -338,9 +338,9 @@ func (v *validator) logForEachValidator(index int, pubKey []byte, resp *ethpb.Va
"correctlyVotedSource": correctlyVotedSource,
"correctlyVotedTarget": correctlyVotedTarget,
"correctlyVotedHead": correctlyVotedHead,
"startBalance": startBalance,
"oldBalance": prevBalance,
"newBalance": newBalance,
"startBalance": fmt.Sprintf("%f", startBalance),
"oldBalance": fmt.Sprintf("%f", prevBalance),
"newBalance": fmt.Sprintf("%f", newBalance),
"percentChange": fmt.Sprintf("%.5f%%", percentNet*100),
"percentChangeSinceStart": fmt.Sprintf("%.5f%%", percentSinceStart*100),
}