mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-21 19:20:38 +00:00
Total balance refactor to big.Int
This commit is contained in:
parent
cca294cba1
commit
b3b42448a5
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
12
beacon-chain/cache/active_balance.go
vendored
12
beacon-chain/cache/active_balance.go
vendored
@ -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:
|
||||
|
7
beacon-chain/cache/active_balance_test.go
vendored
7
beacon-chain/cache/active_balance_test.go
vendored
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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: "",
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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: "",
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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()),
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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 := ðpb.ValidatorParticipationResponse{
|
||||
Epoch: requestedEpoch,
|
||||
Finalized: requestedEpoch <= cp.Epoch,
|
||||
Participation: ðpb.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(),
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -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, ðpb.GetValidatorParticipationRequest{QueryFilter: ðpb.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 := ðpb.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, ðpb.GetValidatorParticipationRequest{QueryFilter: ðpb.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 := ðpb.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, ðpb.GetValidatorParticipationRequest{QueryFilter: ðpb.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 := ðpb.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 = ðpb.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")
|
||||
|
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
72
proto/prysm/v1alpha1/validator.pb.go
generated
72
proto/prysm/v1alpha1/validator.pb.go
generated
@ -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,
|
||||
|
@ -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
123
pulse/pulse_rewards_test.go
Normal 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 := ðpb.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
|
||||
}
|
@ -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),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user