Refactor fork schedules (#15490)

* overhaul fork schedule management for bpos

* Unify log

* Radek's comments

* Use arg config to determine previous epoch, with regression test

* Remove unnecessary NewClock. @potuz feedback

* Continuation of previous commit: Remove unnecessary NewClock. @potuz feedback

* Remove VerifyBlockHeaderSignatureUsingCurrentFork

* cosmetic changes

* Remove unnecessary copy. entryWithForkDigest passes by value, not by pointer so it shold be fine

* Reuse ErrInvalidTopic from p2p package

* Unskip TestServer_GetBeaconConfig

* Resolve TODO about forkwatcher in local mode

* remove Copy()

---------

Co-authored-by: Kasey <kasey@users.noreply.github.com>
Co-authored-by: terence tsao <terence@prysmaticlabs.com>
Co-authored-by: rkapka <radoslaw.kapka@gmail.com>
Co-authored-by: Preston Van Loon <preston@pvl.dev>
This commit is contained in:
kasey
2025-08-11 09:08:53 -07:00
committed by GitHub
parent f7f992c256
commit 3da40ecd9c
117 changed files with 1469 additions and 2426 deletions

View File

@@ -52,10 +52,12 @@ common_deps = [
"//beacon-chain/operations/slashings/mock:go_default_library",
"//beacon-chain/startup:go_default_library",
"//beacon-chain/state/stategen/mock:go_default_library",
"//beacon-chain/state:go_default_library",
"//config/params:go_default_library",
"//consensus-types/primitives:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//genesis:go_default_library",
"//io/file:go_default_library",
"//proto/eth/v1:go_default_library",
"//math:go_default_library",
@@ -73,7 +75,6 @@ common_deps = [
"//testing/slasher/simulator:go_default_library",
"//testing/util:go_default_library",
"//validator/helpers:go_default_library",
"//network/forks:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",

View File

@@ -172,7 +172,7 @@ func NewBeaconNode(config *e2etypes.E2EConfig, index int, enr string) *BeaconNod
func (node *BeaconNode) saveGenesis(ctx context.Context) (string, error) {
// The deposit contract starts with an empty trie, we use the BeaconState to "pre-mine" the validator registry,
g, err := generateGenesis(ctx)
g, err := GenerateGenesis(ctx)
if err != nil {
return "", err
}
@@ -351,7 +351,7 @@ func (node *BeaconNode) UnderlyingProcess() *os.Process {
return node.cmd.Process
}
func generateGenesis(ctx context.Context) (state.BeaconState, error) {
func GenerateGenesis(ctx context.Context) (state.BeaconState, error) {
if e2e.TestParams.Eth1GenesisBlock == nil {
return nil, errors.New("Cannot construct bellatrix block, e2e.TestParams.Eth1GenesisBlock == nil")
}

View File

@@ -276,7 +276,7 @@ func (node *LighthouseBeaconNode) createTestnetDir(ctx context.Context, index in
func (node *LighthouseBeaconNode) saveGenesis(ctx context.Context, testNetDir string) error {
// The deposit contract starts with an empty trie, we use the BeaconState to "pre-mine" the validator registry,
g, err := generateGenesis(ctx)
g, err := GenerateGenesis(ctx)
if err != nil {
return err
}

View File

@@ -18,11 +18,12 @@ import (
"github.com/OffchainLabs/prysm/v6/api/client/beacon"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/genesis"
"github.com/OffchainLabs/prysm/v6/io/file"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/assert"
@@ -61,6 +62,7 @@ type testRunner struct {
config *e2etypes.E2EConfig
comHandler *componentHandler
depositor *eth1.Depositor
genesis state.BeaconState
}
// newTestRunner creates E2E test runner.
@@ -165,6 +167,25 @@ func (r *testRunner) waitForChainStart() {
r.t.Run("chain started", func(t *testing.T) {
require.NoError(t, helpers.WaitForTextInFile(beaconLogFile, "Chain started in sync service"), "Chain did not start")
})
r.postStartConfigure()
}
// postStartConfigure runs at the end of waitForChainStart to set up common runtime dependencies
// like genesis state and configuration (fork schedule) setup.
// It needs to run later because the genesis state cannot be correctly generated until after the
// miner EL component finishes startup and sets the eth1block.
func (r *testRunner) postStartConfigure() {
// set up genesis state with the same value it will have for components
gs, err := components.GenerateGenesis(r.t.Context())
if err != nil {
r.t.Fatal(errors.Wrap(err, "generate genesis")) // // lint:nopanic -- the test runner startup chain doesn't handle errors cleanly
}
r.genesis = gs
genesis.StoreStateDuringTest(r.t, gs)
// initialize genesis and fork schedule params in the test runner config to the same values they will have in the components
params.BeaconConfig().ApplyOptions(params.WithGenesisValidatorsRoot(bytesutil.ToBytes32(gs.GenesisValidatorsRoot())))
params.BeaconConfig().InitializeForkSchedule()
}
// runEvaluators executes assigned evaluators.
@@ -636,7 +657,7 @@ func (r *testRunner) multiScenarioMulticlient(ec *e2etypes.EvaluationContext, ep
Status *enginev1.PayloadStatus `json:"payloadStatus"`
PayloadId *enginev1.PayloadIDBytes `json:"payloadId"`
}
lastForkEpoch := forks.LastForkEpoch()
lastForkEpoch := params.LastForkEpoch()
freezeStartEpoch := lastForkEpoch + 1
freezeEndEpoch := lastForkEpoch + 2
optimisticStartEpoch := lastForkEpoch + 6
@@ -753,7 +774,7 @@ func (r *testRunner) eeOffline(_ *e2etypes.EvaluationContext, epoch uint64, _ []
// will test this with our optimistic sync evaluator to ensure everything works
// as expected.
func (r *testRunner) multiScenario(ec *e2etypes.EvaluationContext, epoch uint64, conns []*grpc.ClientConn) bool {
lastForkEpoch := forks.LastForkEpoch()
lastForkEpoch := params.LastForkEpoch()
freezeStartEpoch := lastForkEpoch + 1
freezeEndEpoch := lastForkEpoch + 2
valOfflineStartEpoch := lastForkEpoch + 6

View File

@@ -38,7 +38,7 @@ go_library(
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//encoding/ssz/detect:go_default_library",
"//network/forks:go_default_library",
"//genesis:go_default_library",
"//network/httputil:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//runtime/interop:go_default_library",

View File

@@ -11,7 +11,8 @@ import (
"time"
"github.com/OffchainLabs/prysm/v6/beacon-chain/p2p"
"github.com/OffchainLabs/prysm/v6/network/forks"
"github.com/OffchainLabs/prysm/v6/config/params"
"github.com/OffchainLabs/prysm/v6/genesis"
eth "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
e2e "github.com/OffchainLabs/prysm/v6/testing/endtoend/params"
"github.com/OffchainLabs/prysm/v6/testing/endtoend/policies"
@@ -86,14 +87,9 @@ var metricComparisonTests = []comparisonTest{
}
func metricsTest(_ *types.EvaluationContext, conns ...*grpc.ClientConn) error {
genesis, err := eth.NewNodeClient(conns[0]).GetGenesis(context.Background(), &emptypb.Empty{})
if err != nil {
return err
}
forkDigest, err := forks.CreateForkDigest(time.Unix(genesis.GenesisTime.Seconds, 0), genesis.GenesisValidatorsRoot)
if err != nil {
return err
}
currentSlot := slots.CurrentSlot(genesis.Time())
currentEpoch := slots.ToEpoch(currentSlot)
forkDigest := params.ForkDigest(currentEpoch)
for i := 0; i < len(conns); i++ {
response, err := http.Get(fmt.Sprintf("http://localhost:%d/metrics", e2e.TestParams.Ports.PrysmBeaconNodeMetricsPort+i))
if err != nil {

View File

@@ -50,6 +50,7 @@ func (mockSyncChecker) IsSynced(_ context.Context) (bool, error) {
func TestEndToEnd_SlasherSimulator(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.E2ETestConfig().Copy())
params.BeaconConfig().InitializeForkSchedule()
hook := logTest.NewGlobal()
ctx := t.Context()

View File

@@ -62,7 +62,6 @@ go_library(
"//crypto/random:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//network/forks:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/eth/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",

View File

@@ -13,7 +13,6 @@ import (
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/crypto/random"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -126,11 +125,7 @@ func GenerateTestDenebBlockWithSidecar(t *testing.T, parent [32]byte, slot primi
}
if g.sign {
epoch := slots.ToEpoch(block.Block.Slot)
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
version, err := schedule.VersionForEpoch(epoch)
require.NoError(t, err)
fork, err := schedule.ForkFromVersion(version)
require.NoError(t, err)
fork := params.ForkFromConfig(params.BeaconConfig(), epoch)
domain := params.BeaconConfig().DomainBeaconProposer
sig, err := signing.ComputeDomainAndSignWithoutState(fork, epoch, domain, g.valRoot, block.Block, g.sk)
require.NoError(t, err)

View File

@@ -12,7 +12,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
"github.com/OffchainLabs/prysm/v6/testing/require"
@@ -131,11 +130,7 @@ func GenerateTestElectraBlockWithSidecar(t *testing.T, parent [32]byte, slot pri
if g.sign {
epoch := slots.ToEpoch(block.Block.Slot)
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
version, err := schedule.VersionForEpoch(epoch)
require.NoError(t, err)
fork, err := schedule.ForkFromVersion(version)
require.NoError(t, err)
fork := params.ForkFromConfig(params.BeaconConfig(), epoch)
domain := params.BeaconConfig().DomainBeaconProposer
sig, err := signing.ComputeDomainAndSignWithoutState(fork, epoch, domain, g.valRoot, block.Block, g.sk)
require.NoError(t, err)

View File

@@ -13,7 +13,6 @@ import (
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/crypto/bls"
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v6/network/forks"
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/time/slots"
@@ -137,13 +136,7 @@ func GenerateTestFuluBlockWithSidecars(t *testing.T, blobCount int, options ...F
if generator.sign {
epoch := slots.ToEpoch(block.Block.Slot)
schedule := forks.NewOrderedSchedule(params.BeaconConfig())
version, err := schedule.VersionForEpoch(epoch)
require.NoError(t, err)
fork, err := schedule.ForkFromVersion(version)
require.NoError(t, err)
fork := params.ForkFromConfig(params.BeaconConfig(), epoch)
domain := params.BeaconConfig().DomainBeaconProposer
sig, err := signing.ComputeDomainAndSignWithoutState(fork, epoch, domain, generator.valRoot, block.Block, generator.sk)