e2e support electra forkstart (#16048)

<!-- Thanks for sending a PR! Before submitting:

1. If this is your first PR, check out our contribution guide here
https://docs.prylabs.network/docs/contribute/contribution-guidelines
You will then need to sign our Contributor License Agreement (CLA),
which will show up as a comment from a bot in this pull request after
you open it. We cannot review code without a signed CLA.
2. Please file an associated tracking issue if this pull request is
non-trivial and requires context for our team to understand. All
features and most bug fixes should have
an associated issue with a design discussed and decided upon. Small bug
   fixes and documentation improvements don't need issues.
3. New features and bug fixes must have tests. Documentation may need to
be updated. If you're unsure what to update, send the PR, and we'll
discuss
   in review.
4. Note that PRs updating dependencies and new Go versions are not
accepted.
   Please file an issue instead.
5. A changelog entry is required for user facing issues.
-->

**What type of PR is this?**

Bug fix


**What does this PR do? Why is it needed?**

Allows for starting e2e tests from electra or a specific fork of
interest again. doesn't fix missing execution requests tests, nishant
reverted it.

**Which issues(s) does this PR fix?**

Fixes #

**Other notes for review**

**Acknowledgements**

- [x] I have read
[CONTRIBUTING.md](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md).
- [x] I have included a uniquely named [changelog fragment
file](https://github.com/prysmaticlabs/prysm/blob/develop/CONTRIBUTING.md#maintaining-changelogmd).
- [x] I have added a description to this PR with sufficient context for
reviewers to understand this PR.

---------

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
james-prysm
2025-11-26 08:33:24 -08:00
committed by GitHub
parent 08d0f42725
commit f97622b054
10 changed files with 125 additions and 32 deletions

View File

@@ -0,0 +1,3 @@
### Fixed
- fixes E2E tests to be able to start from Electra genesis fork or future forks

View File

@@ -62,8 +62,8 @@ func E2ETestConfig() *BeaconChainConfig {
e2eConfig.FuluForkVersion = []byte{6, 0, 0, 253}
e2eConfig.BlobSchedule = []BlobScheduleEntry{
{Epoch: 12, MaxBlobsPerBlock: 6},
{Epoch: 14, MaxBlobsPerBlock: 9},
{Epoch: e2eConfig.DenebForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlock)},
{Epoch: e2eConfig.ElectraForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlockElectra)},
}
e2eConfig.InitializeForkSchedule()
@@ -117,8 +117,8 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
e2eConfig.MinPerEpochChurnLimit = 2
e2eConfig.BlobSchedule = []BlobScheduleEntry{
{Epoch: 12, MaxBlobsPerBlock: 6},
{Epoch: 14, MaxBlobsPerBlock: 9},
{Epoch: e2eConfig.DenebForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlock)},
{Epoch: e2eConfig.ElectraForkEpoch, MaxBlobsPerBlock: uint64(e2eConfig.DeprecatedMaxBlobsPerBlockElectra)},
}
e2eConfig.InitializeForkSchedule()

View File

@@ -156,12 +156,16 @@ func (s *PremineGenesisConfig) empty() (state.BeaconState, error) {
return nil, err
}
case version.Electra:
e, err = state_native.InitializeFromProtoElectra(&ethpb.BeaconStateElectra{})
e, err = state_native.InitializeFromProtoElectra(&ethpb.BeaconStateElectra{
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
})
if err != nil {
return nil, err
}
case version.Fulu:
e, err = state_native.InitializeFromProtoFulu(&ethpb.BeaconStateFulu{})
e, err = state_native.InitializeFromProtoFulu(&ethpb.BeaconStateFulu{
DepositRequestsStartIndex: params.BeaconConfig().UnsetDepositRequestsStartIndex,
})
if err != nil {
return nil, err
}

View File

@@ -10,33 +10,36 @@ import (
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/policies"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
e2etypes "github.com/OffchainLabs/prysm/v7/testing/endtoend/types"
"github.com/OffchainLabs/prysm/v7/time/slots"
"github.com/pkg/errors"
"google.golang.org/grpc"
)
var streamDeadline = 1 * time.Minute
var startingFork = version.Phase0
// AltairForkTransition ensures that the Altair hard fork has occurred successfully.
var AltairForkTransition = types.Evaluator{
var AltairForkTransition = e2etypes.Evaluator{
Name: "altair_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
altair := policies.OnEpoch(params.BeaconConfig().AltairForkEpoch)
// TODO (11750): modify policies to take an end to end config
if startingFork == version.Phase0 {
return altair(e)
// Only run if we started before Altair
if e2etypes.GenesisFork() >= version.Altair {
return false
}
return false
altair := policies.OnEpoch(params.BeaconConfig().AltairForkEpoch)
return altair(e)
},
Evaluation: altairForkOccurs,
}
// BellatrixForkTransition ensures that the Bellatrix hard fork has occurred successfully.
var BellatrixForkTransition = types.Evaluator{
var BellatrixForkTransition = e2etypes.Evaluator{
Name: "bellatrix_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
// Only run if we started before Bellatrix
if e2etypes.GenesisFork() >= version.Bellatrix {
return false
}
fEpoch := params.BeaconConfig().BellatrixForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
@@ -44,9 +47,13 @@ var BellatrixForkTransition = types.Evaluator{
}
// CapellaForkTransition ensures that the Capella hard fork has occurred successfully.
var CapellaForkTransition = types.Evaluator{
var CapellaForkTransition = e2etypes.Evaluator{
Name: "capella_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
// Only run if we started before Capella
if e2etypes.GenesisFork() >= version.Capella {
return false
}
fEpoch := params.BeaconConfig().CapellaForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
@@ -54,9 +61,13 @@ var CapellaForkTransition = types.Evaluator{
}
// DenebForkTransition ensures that the Deneb hard fork has occurred successfully
var DenebForkTransition = types.Evaluator{
var DenebForkTransition = e2etypes.Evaluator{
Name: "deneb_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
// Only run if we started before Deneb
if e2etypes.GenesisFork() >= version.Deneb {
return false
}
fEpoch := params.BeaconConfig().DenebForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
@@ -64,16 +75,20 @@ var DenebForkTransition = types.Evaluator{
}
// ElectraForkTransition ensures that the electra hard fork has occurred successfully
var ElectraForkTransition = types.Evaluator{
var ElectraForkTransition = e2etypes.Evaluator{
Name: "electra_fork_transition_%d",
Policy: func(e primitives.Epoch) bool {
// Only run if we started before Electra
if e2etypes.GenesisFork() >= version.Electra {
return false
}
fEpoch := params.BeaconConfig().ElectraForkEpoch
return policies.OnEpoch(fEpoch)(e)
},
Evaluation: electraForkOccurs,
}
func altairForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
func altairForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
@@ -115,7 +130,7 @@ func altairForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) err
return nil
}
func bellatrixForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
func bellatrixForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
@@ -160,7 +175,7 @@ func bellatrixForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn)
return nil
}
func capellaForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
func capellaForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
@@ -203,7 +218,7 @@ func capellaForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) er
return nil
}
func denebForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
func denebForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)
@@ -246,7 +261,7 @@ func denebForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) erro
return nil
}
func electraForkOccurs(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
func electraForkOccurs(_ *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
conn := conns[0]
client := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), streamDeadline)

View File

@@ -18,6 +18,7 @@ import (
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/encoding/ssz/detect"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/helpers"
e2e "github.com/OffchainLabs/prysm/v7/testing/endtoend/params"
"github.com/OffchainLabs/prysm/v7/testing/endtoend/policies"
@@ -42,9 +43,16 @@ var depositEndEpoch = depositActivationStartEpoch + primitives.Epoch(math.Ceil(f
var exitSubmissionEpoch = primitives.Epoch(7)
// ProcessesDepositsInBlocks ensures the expected amount of deposits are accepted into blocks.
// Note: This evaluator only works for pre-Electra genesis since Electra uses EIP-6110 deposit requests.
var ProcessesDepositsInBlocks = e2etypes.Evaluator{
Name: "processes_deposits_in_blocks_epoch_%d",
Policy: policies.OnEpoch(depositsInBlockStart), // We expect all deposits to enter in one epoch.
Name: "processes_deposits_in_blocks_epoch_%d",
Policy: func(e primitives.Epoch) bool {
// Skip if starting at Electra or later - deposits work differently with EIP-6110
if e2etypes.GenesisFork() >= version.Electra {
return false
}
return policies.OnEpoch(depositsInBlockStart)(e)
},
Evaluation: processesDepositsInBlocks,
}
@@ -56,16 +64,30 @@ var VerifyBlockGraffiti = e2etypes.Evaluator{
}
// ActivatesDepositedValidators ensures the expected amount of validator deposits are activated into the state.
// Note: This evaluator only works for pre-Electra genesis since Electra uses EIP-6110 deposit requests.
var ActivatesDepositedValidators = e2etypes.Evaluator{
Name: "processes_deposit_validators_epoch_%d",
Policy: policies.BetweenEpochs(depositActivationStartEpoch, depositEndEpoch),
Name: "processes_deposit_validators_epoch_%d",
Policy: func(e primitives.Epoch) bool {
// Skip if starting at Electra or later - deposits work differently with EIP-6110
if e2etypes.GenesisFork() >= version.Electra {
return false
}
return policies.BetweenEpochs(depositActivationStartEpoch, depositEndEpoch)(e)
},
Evaluation: activatesDepositedValidators,
}
// DepositedValidatorsAreActive ensures the expected amount of validators are active after their deposits are processed.
// Note: This evaluator only works for pre-Electra genesis since Electra uses EIP-6110 deposit requests.
var DepositedValidatorsAreActive = e2etypes.Evaluator{
Name: "deposited_validators_are_active_epoch_%d",
Policy: policies.AfterNthEpoch(depositEndEpoch),
Name: "deposited_validators_are_active_epoch_%d",
Policy: func(e primitives.Epoch) bool {
// Skip if starting at Electra or later - deposits work differently with EIP-6110
if e2etypes.GenesisFork() >= version.Electra {
return false
}
return policies.AfterNthEpoch(depositEndEpoch)(e)
},
Evaluation: depositedValidatorsAreActive,
}
@@ -88,6 +110,10 @@ var SubmitWithdrawal = e2etypes.Evaluator{
Name: "submit_withdrawal_epoch_%d",
Policy: func(currentEpoch primitives.Epoch) bool {
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run after exit submission
if e2etypes.GenesisFork() >= version.Deneb {
return policies.OnEpoch(exitSubmissionEpoch + 1)(currentEpoch)
}
return policies.BetweenEpochs(fEpoch-2, fEpoch+1)(currentEpoch)
},
Evaluation: submitWithdrawal,
@@ -102,7 +128,14 @@ var ValidatorsHaveWithdrawn = e2etypes.Evaluator{
return false
}
// Only run this for minimal setups after capella
validWithdrawnEpoch := params.BeaconConfig().CapellaForkEpoch + 1
fEpoch := params.BeaconConfig().CapellaForkEpoch
// If Capella is disabled (starting at Deneb+), run after withdrawal submission
var validWithdrawnEpoch primitives.Epoch
if e2etypes.GenesisFork() >= version.Deneb {
validWithdrawnEpoch = exitSubmissionEpoch + 2
} else {
validWithdrawnEpoch = fEpoch + 1
}
requiredPolicy := policies.OnEpoch(validWithdrawnEpoch)
return requiredPolicy(currentEpoch)

View File

@@ -1 +0,0 @@
package endtoend

View File

@@ -11,4 +11,4 @@ import (
func TestEndToEnd_MinimalConfig(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2ETestConfig()), types.WithCheckpointSync())
r.run()
}
}

View File

@@ -25,6 +25,11 @@ func TestEndToEnd_MinimalConfig_Web3Signer_PersistentKeys(t *testing.T) {
e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2ETestConfig()), types.WithRemoteSignerAndPersistentKeysFile()).run()
}
func TestEndToEnd_MinimalConfig_CurrentFork(t *testing.T) {
r := e2eMinimal(t, types.InitForkCfg(version.Electra, version.Electra, params.E2ETestConfig()), types.WithCheckpointSync())
r.run()
}
func TestEndToEnd_MinimalConfig_ValidatorRESTApi_SSZ(t *testing.T) {
e2eMinimal(t, types.InitForkCfg(version.Bellatrix, version.Electra, params.E2ETestConfig()), types.WithCheckpointSync(), types.WithValidatorRESTApi(), types.WithSSZOnly()).run()
}

View File

@@ -6,6 +6,7 @@ import (
"github.com/OffchainLabs/prysm/v7/config/params"
"github.com/OffchainLabs/prysm/v7/runtime/version"
log "github.com/sirupsen/logrus"
)
func InitForkCfg(start, end int, c *params.BeaconChainConfig) *params.BeaconChainConfig {
@@ -13,6 +14,9 @@ func InitForkCfg(start, end int, c *params.BeaconChainConfig) *params.BeaconChai
if end < start {
panic("end fork is less than the start fork") // lint:nopanic -- test code.
}
if start < version.Bellatrix {
log.Fatal("E2e tests require starting from Bellatrix or later (pre-merge forks are not supported)") // lint:nopanic -- test code.
}
if start >= version.Altair {
c.AltairForkEpoch = 0
}
@@ -28,6 +32,13 @@ func InitForkCfg(start, end int, c *params.BeaconChainConfig) *params.BeaconChai
if start >= version.Electra {
c.ElectraForkEpoch = 0
}
if start >= version.Fulu {
c.FuluForkEpoch = 0
}
if end < version.Fulu {
c.FuluForkEpoch = math.MaxUint64
}
if end < version.Electra {
c.ElectraForkEpoch = math.MaxUint64
}
@@ -45,7 +56,23 @@ func InitForkCfg(start, end int, c *params.BeaconChainConfig) *params.BeaconChai
}
// Time TTD to line up roughly with the bellatrix fork epoch.
// E2E sets EL block production rate equal to SecondsPerETH1Block to keep the math simple.
// the chain starts post-merge (AKA post bellatrix) so TTD should be 0.
ttd := uint64(c.BellatrixForkEpoch) * uint64(c.SlotsPerEpoch) * c.SecondsPerSlot
c.TerminalTotalDifficulty = fmt.Sprintf("%d", ttd)
// Update blob schedule to use the modified fork epochs.
// Only include entries for forks that are enabled (not set to MaxUint64).
c.BlobSchedule = nil
if c.DenebForkEpoch != math.MaxUint64 {
c.BlobSchedule = append(c.BlobSchedule, params.BlobScheduleEntry{
Epoch: c.DenebForkEpoch, MaxBlobsPerBlock: uint64(c.DeprecatedMaxBlobsPerBlock),
})
}
if c.ElectraForkEpoch != math.MaxUint64 {
c.BlobSchedule = append(c.BlobSchedule, params.BlobScheduleEntry{
Epoch: c.ElectraForkEpoch, MaxBlobsPerBlock: uint64(c.DeprecatedMaxBlobsPerBlockElectra),
})
}
c.InitializeForkSchedule()
return c
}

View File

@@ -94,6 +94,13 @@ type E2EConfig struct {
func GenesisFork() int {
cfg := params.BeaconConfig()
// Check from highest fork to lowest to find the genesis fork.
if cfg.ElectraForkEpoch == 0 {
return version.Electra
}
if cfg.DenebForkEpoch == 0 {
return version.Deneb
}
if cfg.CapellaForkEpoch == 0 {
return version.Capella
}