diff --git a/beacon-chain/core/helpers/validators.go b/beacon-chain/core/helpers/validators.go index a45c69562fe6..99f6ef8990c7 100644 --- a/beacon-chain/core/helpers/validators.go +++ b/beacon-chain/core/helpers/validators.go @@ -17,6 +17,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/crypto/hash" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/time/slots" log "github.com/sirupsen/logrus" "go.opencensus.io/trace" @@ -357,10 +358,11 @@ func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconSt // candidate_index = indices[compute_shuffled_index(i % total, total, seed)] // random_byte = hash(seed + uint_to_bytes(uint64(i // 32)))[i % 32] // effective_balance = state.validators[candidate_index].effective_balance -// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE * random_byte: +// # [Modified in Electra:EIP7251] +// if effective_balance * MAX_RANDOM_BYTE >= MAX_EFFECTIVE_BALANCE_ELECTRA * random_byte: // return candidate_index // i += 1 -func ComputeProposerIndex(bState state.ReadOnlyValidators, activeIndices []primitives.ValidatorIndex, seed [32]byte) (primitives.ValidatorIndex, error) { +func ComputeProposerIndex(bState state.ReadOnlyBeaconState, activeIndices []primitives.ValidatorIndex, seed [32]byte) (primitives.ValidatorIndex, error) { length := uint64(len(activeIndices)) if length == 0 { return 0, errors.New("empty active indices list") @@ -385,7 +387,12 @@ func ComputeProposerIndex(bState state.ReadOnlyValidators, activeIndices []primi } effectiveBal := v.EffectiveBalance() - if effectiveBal*maxRandomByte >= params.BeaconConfig().MaxEffectiveBalance*uint64(randomByte) { + maxEB := params.BeaconConfig().MaxEffectiveBalanceElectra + if bState.Version() < version.Electra { + maxEB = params.BeaconConfig().MaxEffectiveBalance + } + + if effectiveBal*maxRandomByte >= maxEB*uint64(randomByte) { return candidateIndex, nil } } diff --git a/beacon-chain/core/helpers/validators_test.go b/beacon-chain/core/helpers/validators_test.go index efa21c75cb63..df75647cac19 100644 --- a/beacon-chain/core/helpers/validators_test.go +++ b/beacon-chain/core/helpers/validators_test.go @@ -16,6 +16,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/crypto/hash" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/prysmaticlabs/prysm/v5/testing/assert" "github.com/prysmaticlabs/prysm/v5/testing/require" ) @@ -595,6 +596,7 @@ func TestComputeProposerIndex(t *testing.T) { validators []*ethpb.Validator indices []primitives.ValidatorIndex seed [32]byte + minVersion int } tests := []struct { name string @@ -682,21 +684,81 @@ func TestComputeProposerIndex(t *testing.T) { }, want: 7, }, + { + name: "all_active_indices_above_min_activation_balance", + args: args{ + validators: []*ethpb.Validator{ + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + }, + indices: []primitives.ValidatorIndex{0, 1, 2, 3, 4}, + seed: seed, + minVersion: version.Electra, + }, + want: 2, + }, + { + name: "second_half_active_above_min_activation_balance", + args: args{ + validators: []*ethpb.Validator{ + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + {EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra}, + }, + indices: []primitives.ValidatorIndex{5, 6, 7, 8, 9}, + seed: seed, + minVersion: version.Electra, + }, + want: 7, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - helpers.ClearCache() + t.Run("phase0", func(t *testing.T) { + if tt.args.minVersion > version.Phase0 { + t.Skip("scenario does not apply to phase0") + } + helpers.ClearCache() + bState := ðpb.BeaconState{Validators: tt.args.validators} + stTrie, err := state_native.InitializeFromProtoUnsafePhase0(bState) + require.NoError(t, err) + got, err := helpers.ComputeProposerIndex(stTrie, tt.args.indices, tt.args.seed) + if tt.wantedErr != "" { + assert.ErrorContains(t, tt.wantedErr, err) + return + } + assert.NoError(t, err, "received unexpected error") + assert.Equal(t, tt.want, got, "ComputeProposerIndex()") + }) + t.Run("electra", func(t *testing.T) { + if tt.args.minVersion > version.Electra { + t.Skip("scenario does not apply to electra") + } + helpers.ClearCache() + bState := ðpb.BeaconStateElectra{Validators: tt.args.validators} + stTrie, err := state_native.InitializeFromProtoUnsafeElectra(bState) + require.NoError(t, err) - bState := ðpb.BeaconState{Validators: tt.args.validators} - stTrie, err := state_native.InitializeFromProtoUnsafePhase0(bState) - require.NoError(t, err) - got, err := helpers.ComputeProposerIndex(stTrie, tt.args.indices, tt.args.seed) - if tt.wantedErr != "" { - assert.ErrorContains(t, tt.wantedErr, err) - return - } - assert.NoError(t, err, "received unexpected error") - assert.Equal(t, tt.want, got, "ComputeProposerIndex()") + require.Equal(t, stTrie.Version(), version.Electra) + + got, err := helpers.ComputeProposerIndex(stTrie, tt.args.indices, tt.args.seed) + if tt.wantedErr != "" { + assert.ErrorContains(t, tt.wantedErr, err) + return + } + assert.NoError(t, err, "received unexpected error") + assert.Equal(t, tt.want, got, "ComputeProposerIndex()") + }) }) } }