diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef632908876..05cc55a01c28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -118,6 +118,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve - Fix proposer boost spec tests being flakey by adjusting start time from 3 to 2s into slot. - Fix segmentation fault in E2E when light-client feature flag is enabled. [PR](https://github.com/prysmaticlabs/prysm/pull/14699) - Fix `searchForPeers` infinite loop in small networks. +- Fix slashing pool behavior to enforce MaxAttesterSlashings limit in Electra version. ### Security diff --git a/beacon-chain/operations/slashings/BUILD.bazel b/beacon-chain/operations/slashings/BUILD.bazel index f4f21b7bb4a1..39efbd2d5209 100644 --- a/beacon-chain/operations/slashings/BUILD.bazel +++ b/beacon-chain/operations/slashings/BUILD.bazel @@ -25,6 +25,7 @@ go_library( "//container/slice:go_default_library", "//monitoring/tracing/trace:go_default_library", "//proto/prysm/v1alpha1:go_default_library", + "//runtime/version:go_default_library", "@com_github_pkg_errors//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", diff --git a/beacon-chain/operations/slashings/service.go b/beacon-chain/operations/slashings/service.go index 803d2530495a..561c77da225d 100644 --- a/beacon-chain/operations/slashings/service.go +++ b/beacon-chain/operations/slashings/service.go @@ -15,6 +15,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/container/slice" "github.com/prysmaticlabs/prysm/v5/monitoring/tracing/trace" ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" "github.com/trailofbits/go-mutexasserts" ) @@ -43,6 +44,11 @@ func (p *Pool) PendingAttesterSlashings(ctx context.Context, state state.ReadOnl // Allocate pending slice with a capacity of maxAttesterSlashings or len(p.pendingAttesterSlashing)) depending on the request. maxSlashings := params.BeaconConfig().MaxAttesterSlashings + + // EIP-7549: Beginning from Electra, the max attester slashings is reduced to 1. + if state.Version() >= version.Electra { + maxSlashings = params.BeaconConfig().MaxAttesterSlashingsElectra + } if noLimit { maxSlashings = uint64(len(p.pendingAttesterSlashing)) } diff --git a/beacon-chain/operations/slashings/service_attester_test.go b/beacon-chain/operations/slashings/service_attester_test.go index 2dab3f107613..9d705c07184b 100644 --- a/beacon-chain/operations/slashings/service_attester_test.go +++ b/beacon-chain/operations/slashings/service_attester_test.go @@ -516,6 +516,70 @@ func TestPool_PendingAttesterSlashings(t *testing.T) { } } +func TestPool_PendingAttesterSlashings_AfterElectra(t *testing.T) { + type fields struct { + pending []*PendingAttesterSlashing + all bool + } + params.SetupTestConfigCleanup(t) + beaconState, privKeys := util.DeterministicGenesisStateElectra(t, 64) + + pendingSlashings := make([]*PendingAttesterSlashing, 20) + slashings := make([]ethpb.AttSlashing, 20) + for i := 0; i < len(pendingSlashings); i++ { + sl, err := util.GenerateAttesterSlashingForValidator(beaconState, privKeys[i], primitives.ValidatorIndex(i)) + require.NoError(t, err) + pendingSlashings[i] = &PendingAttesterSlashing{ + attesterSlashing: sl, + validatorToSlash: primitives.ValidatorIndex(i), + } + slashings[i] = sl + } + tests := []struct { + name string + fields fields + want []ethpb.AttSlashing + }{ + { + name: "Empty list", + fields: fields{ + pending: []*PendingAttesterSlashing{}, + }, + want: []ethpb.AttSlashing{}, + }, + { + name: "All pending", + fields: fields{ + pending: pendingSlashings, + all: true, + }, + want: slashings, + }, + { + name: "All eligible", + fields: fields{ + pending: pendingSlashings, + }, + want: slashings[0:1], + }, + { + name: "Multiple indices", + fields: fields{ + pending: pendingSlashings[3:6], + }, + want: slashings[3:4], + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Pool{ + pendingAttesterSlashing: tt.fields.pending, + } + assert.DeepEqual(t, tt.want, p.PendingAttesterSlashings(context.Background(), beaconState, tt.fields.all)) + }) + } +} + func TestPool_PendingAttesterSlashings_Slashed(t *testing.T) { type fields struct { pending []*PendingAttesterSlashing