Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion beacon-chain/core/epoch/epoch_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func ProcessRegistryUpdates(ctx context.Context, state state.BeaconState) (state
activationEligibilityEpoch := time.CurrentEpoch(state) + 1
for idx, validator := range vals {
// Process the validators for activation eligibility.
if helpers.IsEligibleForActivationQueue(validator) {
if helpers.IsEligibleForActivationQueue(validator, currentEpoch) {
validator.ActivationEligibilityEpoch = activationEligibilityEpoch
if err := state.UpdateValidatorAtIndex(primitives.ValidatorIndex(idx), validator); err != nil {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions beacon-chain/core/helpers/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ go_library(
"rewards_penalties.go",
"shuffle.go",
"sync_committee.go",
"validator_churn.go",
"validators.go",
"weak_subjectivity.go",
],
Expand Down Expand Up @@ -56,6 +57,7 @@ go_test(
"rewards_penalties_test.go",
"shuffle_test.go",
"sync_committee_test.go",
"validator_churn_test.go",
"validators_test.go",
"weak_subjectivity_test.go",
],
Expand Down
52 changes: 52 additions & 0 deletions beacon-chain/core/helpers/validator_churn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package helpers

import (
"github.com/prysmaticlabs/prysm/v5/config/params"
)

// BalanceChurnLimit for the current active balance, in gwei.
// New in Electra EIP-7251: https://eips.ethereum.org/EIPS/eip-7251
//
// Spec definition:
//
// def get_balance_churn_limit(state: BeaconState) -> Gwei:
// """
// Return the churn limit for the current epoch.
// """
// churn = max(
// MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA,
// get_total_active_balance(state) // CHURN_LIMIT_QUOTIENT
// )
// return churn - churn % EFFECTIVE_BALANCE_INCREMENT
func BalanceChurnLimit(activeBalanceGwei uint64) uint64 {
churn := max(
params.BeaconConfig().MinPerEpochChurnLimitElectra,
(activeBalanceGwei / params.BeaconConfig().ChurnLimitQuotient),
)
return churn - churn%params.BeaconConfig().EffectiveBalanceIncrement
}

// ActivationExitChurnLimit for the current active balance, in gwei.
// New in Electra EIP-7251: https://eips.ethereum.org/EIPS/eip-7251
//
// Spec definition:
//
// def get_activation_exit_churn_limit(state: BeaconState) -> Gwei:
// """
// Return the churn limit for the current epoch dedicated to activations and exits.
// """
// return min(MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, get_balance_churn_limit(state))
func ActivationExitChurnLimit(activeBalanceGwei uint64) uint64 {
return min(params.BeaconConfig().MaxPerEpochActivationExitChurnLimit, BalanceChurnLimit(activeBalanceGwei))
}

// ConsolidationChurnLimit for the current active balance, in gwei.
// New in EIP-7251: https://eips.ethereum.org/EIPS/eip-7251
//
// Spec definition:
//
// def get_consolidation_churn_limit(state: BeaconState) -> Gwei:
// return get_balance_churn_limit(state) - get_activation_exit_churn_limit(state)
func ConsolidationChurnLimit(activeBalanceGwei uint64) uint64 {
return BalanceChurnLimit(activeBalanceGwei) - ActivationExitChurnLimit(activeBalanceGwei)
}
71 changes: 71 additions & 0 deletions beacon-chain/core/helpers/validator_churn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package helpers_test

import (
"testing"

"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/testing/assert"
)

func TestBalanceChurnLimit(t *testing.T) {
tests := []struct {
name string
activeBalance uint64
expected uint64
}{
{
name: "less than MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA",
activeBalance: 111,
expected: params.BeaconConfig().MinPerEpochChurnLimitElectra,
},
{
name: "modulo EFFECTIVE_BALANCE_INCREMENT",
activeBalance: 111 + params.BeaconConfig().MinPerEpochChurnLimitElectra*params.BeaconConfig().ChurnLimitQuotient,
expected: params.BeaconConfig().MinPerEpochChurnLimitElectra,
},
{
name: "more than MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA",
activeBalance: 2000 * params.BeaconConfig().EffectiveBalanceIncrement * params.BeaconConfig().ChurnLimitQuotient,
expected: 2000 * params.BeaconConfig().EffectiveBalanceIncrement,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, helpers.BalanceChurnLimit(tt.activeBalance))
})
}
}

func TestActivationExitChurnLimit(t *testing.T) {
tests := []struct {
name string
activeBalance uint64
expected uint64
}{
{
name: "less than MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT",
activeBalance: 1,
expected: params.BeaconConfig().MinPerEpochChurnLimitElectra,
},
{
name: "more than MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT",
activeBalance: 2000 * params.BeaconConfig().EffectiveBalanceIncrement * params.BeaconConfig().ChurnLimitQuotient,
expected: params.BeaconConfig().MaxPerEpochActivationExitChurnLimit,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.expected, helpers.ActivationExitChurnLimit(tt.activeBalance))
})
}
}

// FuzzConsolidationChurnLimit exercises BalanceChurnLimit and ActivationExitChurnLimit
func FuzzConsolidationChurnLimit(f *testing.F) {
f.Fuzz(func(t *testing.T, activeBalance uint64) {
helpers.ConsolidationChurnLimit(activeBalance)
})
}
Loading