mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
initialize genesis data asap at node start (#15470)
* initialize genesis data asap at node start * add genesis validation tests with embedded state verification * Add test for hardcoded mainnet genesis validator root and time from init() function * Add test for UnmarshalState in encoding/ssz/detect/configfork.go * Add tests for genesis.Initialize * Move genesis/embedded to genesis/internal/embedded * Gazelle / BUILD fix * James feedback * Fix lint * Revert lock --------- Co-authored-by: Kasey <kasey@users.noreply.github.com> Co-authored-by: terence tsao <terence@prysmaticlabs.com> Co-authored-by: Preston Van Loon <preston@pvl.dev>
This commit is contained in:
@@ -182,6 +182,7 @@ go_test(
|
|||||||
"//container/trie:go_default_library",
|
"//container/trie:go_default_library",
|
||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/eth/v1:go_default_library",
|
"//proto/eth/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
@@ -624,6 +625,7 @@ func Test_hashForGenesisRoot(t *testing.T) {
|
|||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
c := setupBeaconChain(t, beaconDB)
|
c := setupBeaconChain(t, beaconDB)
|
||||||
st, _ := util.DeterministicGenesisStateElectra(t, 10)
|
st, _ := util.DeterministicGenesisStateElectra(t, 10)
|
||||||
|
genesis.StoreDuringTest(t, genesis.GenesisData{State: st})
|
||||||
require.NoError(t, c.cfg.BeaconDB.SaveGenesisData(ctx, st))
|
require.NoError(t, c.cfg.BeaconDB.SaveGenesisData(ctx, st))
|
||||||
root, err := beaconDB.GenesisBlockRoot(ctx)
|
root, err := beaconDB.GenesisBlockRoot(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
v1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
v1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
@@ -309,6 +310,7 @@ func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
|
|||||||
block: wba,
|
block: wba,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
genesis.StoreStateDuringTest(t, st)
|
||||||
require.NoError(t, beaconDB.SaveState(ctx, st, bra))
|
require.NoError(t, beaconDB.SaveState(ctx, st, bra))
|
||||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra))
|
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra))
|
||||||
a := &fcuConfig{
|
a := &fcuConfig{
|
||||||
@@ -403,6 +405,7 @@ func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
bState, _ := util.DeterministicGenesisState(t, 10)
|
bState, _ := util.DeterministicGenesisState(t, 10)
|
||||||
|
genesis.StoreStateDuringTest(t, bState)
|
||||||
require.NoError(t, beaconDB.SaveState(ctx, bState, bra))
|
require.NoError(t, beaconDB.SaveState(ctx, bState, bra))
|
||||||
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
|
||||||
state, blkRoot, err = prepareForkchoiceState(ctx, 2, brb, bra, [32]byte{'B'}, ojc, ofc)
|
state, blkRoot, err = prepareForkchoiceState(ctx, 2, brb, bra, [32]byte{'B'}, ojc, ofc)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
"github.com/OffchainLabs/prysm/v6/crypto/bls"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
@@ -1980,14 +1981,15 @@ func TestNoViableHead_Reboot(t *testing.T) {
|
|||||||
genesisState, keys := util.DeterministicGenesisState(t, 64)
|
genesisState, keys := util.DeterministicGenesisState(t, 64)
|
||||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||||
require.NoError(t, err, "Could not hash genesis state")
|
require.NoError(t, err, "Could not hash genesis state")
|
||||||
genesis := blocks.NewGenesisBlock(stateRoot[:])
|
gb := blocks.NewGenesisBlock(stateRoot[:])
|
||||||
wsb, err := consensusblocks.NewSignedBeaconBlock(genesis)
|
wsb, err := consensusblocks.NewSignedBeaconBlock(gb)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
genesisRoot, err := genesis.Block.HashTreeRoot()
|
genesisRoot, err := gb.Block.HashTreeRoot()
|
||||||
require.NoError(t, err, "Could not get signing root")
|
require.NoError(t, err, "Could not get signing root")
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb), "Could not save genesis block")
|
||||||
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
require.NoError(t, service.saveGenesisData(ctx, genesisState))
|
||||||
|
|
||||||
|
genesis.StoreStateDuringTest(t, genesisState)
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, genesisRoot), "Could not save genesis state")
|
require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, genesisState, genesisRoot), "Could not save genesis state")
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
require.NoError(t, service.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
||||||
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
require.NoError(t, service.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisRoot), "Could not save genesis state")
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/async/event"
|
"github.com/OffchainLabs/prysm/v6/async/event"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/blockchain/kzg"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/cache"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/cache"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed"
|
|
||||||
statefeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/state"
|
statefeed "github.com/OffchainLabs/prysm/v6/beacon-chain/core/feed/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/helpers"
|
||||||
lightClient "github.com/OffchainLabs/prysm/v6/beacon-chain/core/light-client"
|
lightClient "github.com/OffchainLabs/prysm/v6/beacon-chain/core/light-client"
|
||||||
@@ -207,17 +206,9 @@ func NewService(ctx context.Context, opts ...Option) (*Service, error) {
|
|||||||
|
|
||||||
// Start a blockchain service's main event loop.
|
// Start a blockchain service's main event loop.
|
||||||
func (s *Service) Start() {
|
func (s *Service) Start() {
|
||||||
saved := s.cfg.FinalizedStateAtStartUp
|
|
||||||
defer s.removeStartupState()
|
defer s.removeStartupState()
|
||||||
|
if err := s.StartFromSavedState(s.cfg.FinalizedStateAtStartUp); err != nil {
|
||||||
if saved != nil && !saved.IsNil() {
|
log.Fatal(err)
|
||||||
if err := s.StartFromSavedState(saved); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := s.startFromExecutionChain(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
s.spawnProcessAttestationsRoutine()
|
s.spawnProcessAttestationsRoutine()
|
||||||
go s.runLateBlockTasks()
|
go s.runLateBlockTasks()
|
||||||
@@ -266,6 +257,9 @@ func (s *Service) Status() error {
|
|||||||
|
|
||||||
// StartFromSavedState initializes the blockchain using a previously saved finalized checkpoint.
|
// StartFromSavedState initializes the blockchain using a previously saved finalized checkpoint.
|
||||||
func (s *Service) StartFromSavedState(saved state.BeaconState) error {
|
func (s *Service) StartFromSavedState(saved state.BeaconState) error {
|
||||||
|
if state.IsNil(saved) {
|
||||||
|
return errors.New("Last finalized state at startup is nil")
|
||||||
|
}
|
||||||
log.Info("Blockchain data already exists in DB, initializing...")
|
log.Info("Blockchain data already exists in DB, initializing...")
|
||||||
s.genesisTime = saved.GenesisTime()
|
s.genesisTime = saved.GenesisTime()
|
||||||
s.cfg.AttService.SetGenesisTime(saved.GenesisTime())
|
s.cfg.AttService.SetGenesisTime(saved.GenesisTime())
|
||||||
@@ -371,62 +365,6 @@ func (s *Service) initializeHead(ctx context.Context, st state.BeaconState) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) startFromExecutionChain() error {
|
|
||||||
log.Info("Waiting to reach the validator deposit threshold to start the beacon chain...")
|
|
||||||
if s.cfg.ChainStartFetcher == nil {
|
|
||||||
return errors.New("not configured execution chain")
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
stateChannel := make(chan *feed.Event, 1)
|
|
||||||
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
|
|
||||||
defer stateSub.Unsubscribe()
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case e := <-stateChannel:
|
|
||||||
if e.Type == statefeed.ChainStarted {
|
|
||||||
data, ok := e.Data.(*statefeed.ChainStartedData)
|
|
||||||
if !ok {
|
|
||||||
log.Error("Event data is not type *statefeed.ChainStartedData")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.WithField("startTime", data.StartTime).Debug("Received chain start event")
|
|
||||||
s.onExecutionChainStart(s.ctx, data.StartTime)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case <-s.ctx.Done():
|
|
||||||
log.Debug("Context closed, exiting goroutine")
|
|
||||||
return
|
|
||||||
case err := <-stateSub.Err():
|
|
||||||
log.WithError(err).Error("Subscription to state forRoot failed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// onExecutionChainStart initializes a series of deposits from the ChainStart deposits in the eth1
|
|
||||||
// deposit contract, initializes the beacon chain's state, and kicks off the beacon chain.
|
|
||||||
func (s *Service) onExecutionChainStart(ctx context.Context, genesisTime time.Time) {
|
|
||||||
preGenesisState := s.cfg.ChainStartFetcher.PreGenesisState()
|
|
||||||
initializedState, err := s.initializeBeaconChain(ctx, genesisTime, preGenesisState, s.cfg.ChainStartFetcher.ChainStartEth1Data())
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Fatal("Could not initialize beacon chain")
|
|
||||||
}
|
|
||||||
// We start a counter to genesis, if needed.
|
|
||||||
gRoot, err := initializedState.HashTreeRoot(s.ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.WithError(err).Fatal("Could not hash tree root genesis state")
|
|
||||||
}
|
|
||||||
go slots.CountdownToGenesis(ctx, genesisTime, uint64(initializedState.NumValidators()), gRoot)
|
|
||||||
|
|
||||||
vr := bytesutil.ToBytes32(initializedState.GenesisValidatorsRoot())
|
|
||||||
if err := s.clockSetter.SetClock(startup.NewClock(genesisTime, vr)); err != nil {
|
|
||||||
log.WithError(err).Fatal("Failed to initialize blockchain service from execution start event")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initializes the state and genesis block of the beacon chain to persistent storage
|
// initializes the state and genesis block of the beacon chain to persistent storage
|
||||||
// based on a genesis timestamp value obtained from the ChainStart event emitted
|
// based on a genesis timestamp value obtained from the ChainStart event emitted
|
||||||
// by the ETH1.0 Deposit Contract and the POWChain service of the node.
|
// by the ETH1.0 Deposit Contract and the POWChain service of the node.
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/container/trie"
|
"github.com/OffchainLabs/prysm/v6/container/trie"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
@@ -51,6 +52,7 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
|||||||
srv.Stop()
|
srv.Stop()
|
||||||
})
|
})
|
||||||
bState, _ := util.DeterministicGenesisState(t, 10)
|
bState, _ := util.DeterministicGenesisState(t, 10)
|
||||||
|
genesis.StoreStateDuringTest(t, bState)
|
||||||
pbState, err := state_native.ProtobufBeaconStatePhase0(bState.ToProtoUnsafe())
|
pbState, err := state_native.ProtobufBeaconStatePhase0(bState.ToProtoUnsafe())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
mockTrie, err := trie.NewTrie(0)
|
mockTrie, err := trie.NewTrie(0)
|
||||||
@@ -71,20 +73,22 @@ func setupBeaconChain(t *testing.T, beaconDB db.Database) *Service {
|
|||||||
DepositContainers: []*ethpb.DepositContainer{},
|
DepositContainers: []*ethpb.DepositContainer{},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
depositCache, err := depositsnapshot.New()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
web3Service, err = execution.NewService(
|
web3Service, err = execution.NewService(
|
||||||
ctx,
|
ctx,
|
||||||
execution.WithDatabase(beaconDB),
|
execution.WithDatabase(beaconDB),
|
||||||
execution.WithHttpEndpoint(endpoint),
|
execution.WithHttpEndpoint(endpoint),
|
||||||
execution.WithDepositContractAddress(common.Address{}),
|
execution.WithDepositContractAddress(common.Address{}),
|
||||||
|
execution.WithDepositCache(depositCache),
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "Unable to set up web3 service")
|
require.NoError(t, err, "Unable to set up web3 service")
|
||||||
|
|
||||||
attService, err := attestations.NewService(ctx, &attestations.Config{Pool: attestations.NewPool()})
|
attService, err := attestations.NewService(ctx, &attestations.Config{Pool: attestations.NewPool()})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
depositCache, err := depositsnapshot.New()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
fc := doublylinkedtree.New()
|
fc := doublylinkedtree.New()
|
||||||
stateGen := stategen.New(beaconDB, fc)
|
stateGen := stategen.New(beaconDB, fc)
|
||||||
// Safe a state in stategen to purposes of testing a service stop / shutdown.
|
// Safe a state in stategen to purposes of testing a service stop / shutdown.
|
||||||
@@ -396,24 +400,6 @@ func TestServiceStop_SaveCachedBlocks(t *testing.T) {
|
|||||||
require.Equal(t, true, s.cfg.BeaconDB.HasBlock(s.ctx, r))
|
require.Equal(t, true, s.cfg.BeaconDB.HasBlock(s.ctx, r))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessChainStartTime_ReceivedFeed(t *testing.T) {
|
|
||||||
ctx := t.Context()
|
|
||||||
beaconDB := testDB.SetupDB(t)
|
|
||||||
service := setupBeaconChain(t, beaconDB)
|
|
||||||
mgs := &MockClockSetter{}
|
|
||||||
service.clockSetter = mgs
|
|
||||||
gt := time.Now()
|
|
||||||
service.onExecutionChainStart(t.Context(), gt)
|
|
||||||
gs, err := beaconDB.GenesisState(ctx)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NotEqual(t, nil, gs)
|
|
||||||
require.Equal(t, 32, len(gs.GenesisValidatorsRoot()))
|
|
||||||
var zero [32]byte
|
|
||||||
require.DeepNotEqual(t, gs.GenesisValidatorsRoot(), zero[:])
|
|
||||||
require.Equal(t, gt, mgs.G.GenesisTime())
|
|
||||||
require.Equal(t, bytesutil.ToBytes32(gs.GenesisValidatorsRoot()), mgs.G.GenesisValidatorsRoot())
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkHasBlockDB(b *testing.B) {
|
func BenchmarkHasBlockDB(b *testing.B) {
|
||||||
ctx := b.Context()
|
ctx := b.Context()
|
||||||
s := testServiceWithDB(b)
|
s := testServiceWithDB(b)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ go_library(
|
|||||||
visibility = [
|
visibility = [
|
||||||
"//beacon-chain:__subpackages__",
|
"//beacon-chain:__subpackages__",
|
||||||
"//cmd/beacon-chain:__subpackages__",
|
"//cmd/beacon-chain:__subpackages__",
|
||||||
|
"//genesis:__subpackages__",
|
||||||
"//testing/slasher/simulator:__pkg__",
|
"//testing/slasher/simulator:__pkg__",
|
||||||
"//tools:__subpackages__",
|
"//tools:__subpackages__",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ go_library(
|
|||||||
"//beacon-chain/db/filters:go_default_library",
|
"//beacon-chain/db/filters:go_default_library",
|
||||||
"//beacon-chain/db/iface:go_default_library",
|
"//beacon-chain/db/iface:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/genesis:go_default_library",
|
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
@@ -52,6 +51,7 @@ go_library(
|
|||||||
"//container/slice:go_default_library",
|
"//container/slice:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
"//encoding/ssz/detect:go_default_library",
|
"//encoding/ssz/detect:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//io/file:go_default_library",
|
"//io/file:go_default_library",
|
||||||
"//monitoring/progress:go_default_library",
|
"//monitoring/progress:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
@@ -110,7 +110,6 @@ go_test(
|
|||||||
"//beacon-chain/db/filters:go_default_library",
|
"//beacon-chain/db/filters:go_default_library",
|
||||||
"//beacon-chain/db/iface:go_default_library",
|
"//beacon-chain/db/iface:go_default_library",
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//beacon-chain/state/genesis:go_default_library",
|
|
||||||
"//beacon-chain/state/state-native:go_default_library",
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
@@ -120,6 +119,7 @@ go_test(
|
|||||||
"//consensus-types/light-client:go_default_library",
|
"//consensus-types/light-client:go_default_library",
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//proto/dbval:go_default_library",
|
"//proto/dbval:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
dbIface "github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
dbIface "github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -97,8 +98,22 @@ func (s *Store) EnsureEmbeddedGenesis(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if gs != nil && !gs.IsNil() {
|
if !state.IsNil(gs) {
|
||||||
return s.SaveGenesisData(ctx, gs)
|
return s.SaveGenesisData(ctx, gs)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LegacyGenesisProvider struct {
|
||||||
|
store *Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLegacyGenesisProvider(store *Store) *LegacyGenesisProvider {
|
||||||
|
return &LegacyGenesisProvider{store: store}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ genesis.Provider = &LegacyGenesisProvider{}
|
||||||
|
|
||||||
|
func (p *LegacyGenesisProvider) Genesis(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
return p.store.LegacyGenesisState(ctx)
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/iface"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
@@ -152,6 +153,7 @@ func TestEnsureEmbeddedGenesis(t *testing.T) {
|
|||||||
require.NoError(t, undo())
|
require.NoError(t, undo())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
genesis.StoreEmbeddedDuringTest(t, params.BeaconConfig().ConfigName)
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
db := setupDB(t)
|
db := setupDB(t)
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
statenative "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
statenative "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing"
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
"github.com/OffchainLabs/prysm/v6/monitoring/tracing/trace"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
"github.com/OffchainLabs/prysm/v6/runtime/version"
|
||||||
@@ -65,21 +63,21 @@ func (s *Store) StateOrError(ctx context.Context, blockRoot [32]byte) (state.Bea
|
|||||||
return st, nil
|
return st, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisState returns the genesis state in beacon chain.
|
|
||||||
func (s *Store) GenesisState(ctx context.Context) (state.BeaconState, error) {
|
func (s *Store) GenesisState(ctx context.Context) (state.BeaconState, error) {
|
||||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState")
|
st, err := genesis.State()
|
||||||
|
if errors.Is(err, genesis.ErrGenesisStateNotInitialized) {
|
||||||
|
log.WithError(err).Error("genesis state not initialized, returning nil state. this should only happen in tests")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return st, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenesisState returns the genesis state in beacon chain.
|
||||||
|
func (s *Store) LegacyGenesisState(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
ctx, span := trace.StartSpan(ctx, "BeaconDB.LegacyGenesisState")
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
cached, err := genesis.State(params.BeaconConfig().ConfigName)
|
var err error
|
||||||
if err != nil {
|
|
||||||
tracing.AnnotateError(span, err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
span.SetAttributes(trace.BoolAttribute("cache_hit", cached != nil))
|
|
||||||
if cached != nil {
|
|
||||||
return cached, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var st state.BeaconState
|
var st state.BeaconState
|
||||||
err = s.db.View(func(tx *bolt.Tx) error {
|
err = s.db.View(func(tx *bolt.Tx) error {
|
||||||
// Retrieve genesis block's signing root from blocks bucket,
|
// Retrieve genesis block's signing root from blocks bucket,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/interfaces"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
enginev1 "github.com/OffchainLabs/prysm/v6/proto/engine/v1"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
@@ -488,7 +489,7 @@ func TestGenesisState_CanSaveRetrieve(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, st.SetSlot(1))
|
require.NoError(t, st.SetSlot(1))
|
||||||
require.NoError(t, db.SaveGenesisBlockRoot(t.Context(), headRoot))
|
require.NoError(t, db.SaveGenesisBlockRoot(t.Context(), headRoot))
|
||||||
require.NoError(t, db.SaveState(t.Context(), st, headRoot))
|
genesis.StoreStateDuringTest(t, st)
|
||||||
|
|
||||||
savedGenesisS, err := db.GenesisState(t.Context())
|
savedGenesisS, err := db.GenesisState(t.Context())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -661,7 +662,7 @@ func TestStore_GenesisState_CanGetHighestBelow(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
genesisRoot := [32]byte{'a'}
|
genesisRoot := [32]byte{'a'}
|
||||||
require.NoError(t, db.SaveGenesisBlockRoot(t.Context(), genesisRoot))
|
require.NoError(t, db.SaveGenesisBlockRoot(t.Context(), genesisRoot))
|
||||||
require.NoError(t, db.SaveState(t.Context(), genesisState, genesisRoot))
|
genesis.StoreStateDuringTest(t, genesisState)
|
||||||
|
|
||||||
b := util.NewBeaconBlock()
|
b := util.NewBeaconBlock()
|
||||||
b.Block.Slot = 1
|
b.Block.Slot = 1
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package kv
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/blocks"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/util"
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
)
|
)
|
||||||
@@ -18,7 +18,11 @@ func TestSaveOrigin(t *testing.T) {
|
|||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
db := setupDB(t)
|
db := setupDB(t)
|
||||||
|
|
||||||
st, err := genesis.State(params.MainnetName)
|
// Initialize genesis with mainnet config - this will load the embedded mainnet state
|
||||||
|
require.NoError(t, genesis.Initialize(ctx, t.TempDir()))
|
||||||
|
|
||||||
|
// Get the initialized genesis state
|
||||||
|
st, err := genesis.State()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sb, err := st.MarshalSSZ()
|
sb, err := st.MarshalSSZ()
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ go_test(
|
|||||||
"//contracts/deposit/mock:go_default_library",
|
"//contracts/deposit/mock:go_default_library",
|
||||||
"//crypto/bls:go_default_library",
|
"//crypto/bls:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//monitoring/clientstats:go_default_library",
|
"//monitoring/clientstats:go_default_library",
|
||||||
"//proto/engine/v1:go_default_library",
|
"//proto/engine/v1:go_default_library",
|
||||||
"//proto/prysm/v1alpha1:go_default_library",
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
contracts "github.com/OffchainLabs/prysm/v6/contracts/deposit"
|
contracts "github.com/OffchainLabs/prysm/v6/contracts/deposit"
|
||||||
"github.com/OffchainLabs/prysm/v6/contracts/deposit/mock"
|
"github.com/OffchainLabs/prysm/v6/contracts/deposit/mock"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/clientstats"
|
"github.com/OffchainLabs/prysm/v6/monitoring/clientstats"
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
"github.com/OffchainLabs/prysm/v6/testing/assert"
|
||||||
@@ -381,6 +382,7 @@ func TestInitDepositCache_OK(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(t.Context(), blockRootA))
|
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(t.Context(), blockRootA))
|
||||||
require.NoError(t, s.cfg.beaconDB.SaveState(t.Context(), emptyState, blockRootA))
|
require.NoError(t, s.cfg.beaconDB.SaveState(t.Context(), emptyState, blockRootA))
|
||||||
|
genesis.StoreStateDuringTest(t, emptyState)
|
||||||
s.chainStartData.Chainstarted = true
|
s.chainStartData.Chainstarted = true
|
||||||
require.NoError(t, s.initDepositCaches(t.Context(), ctrs))
|
require.NoError(t, s.initDepositCaches(t.Context(), ctrs))
|
||||||
require.Equal(t, 3, len(s.cfg.depositCache.PendingContainers(t.Context(), nil)))
|
require.Equal(t, 3, len(s.cfg.depositCache.PendingContainers(t.Context(), nil)))
|
||||||
@@ -446,6 +448,7 @@ func TestInitDepositCacheWithFinalization_OK(t *testing.T) {
|
|||||||
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(t.Context(), headRoot))
|
require.NoError(t, s.cfg.beaconDB.SaveGenesisBlockRoot(t.Context(), headRoot))
|
||||||
require.NoError(t, s.cfg.beaconDB.SaveState(t.Context(), emptyState, headRoot))
|
require.NoError(t, s.cfg.beaconDB.SaveState(t.Context(), emptyState, headRoot))
|
||||||
require.NoError(t, stateGen.SaveState(t.Context(), headRoot, emptyState))
|
require.NoError(t, stateGen.SaveState(t.Context(), headRoot, emptyState))
|
||||||
|
genesis.StoreStateDuringTest(t, emptyState)
|
||||||
s.cfg.stateGen = stateGen
|
s.cfg.stateGen = stateGen
|
||||||
require.NoError(t, emptyState.SetEth1DepositIndex(3))
|
require.NoError(t, emptyState.SetEth1DepositIndex(3))
|
||||||
|
|
||||||
@@ -594,6 +597,7 @@ func TestService_EnsureConsistentPowchainData(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NoError(t, genState.SetSlot(1000))
|
assert.NoError(t, genState.SetSlot(1000))
|
||||||
|
|
||||||
|
genesis.StoreStateDuringTest(t, genState)
|
||||||
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(t.Context(), genState))
|
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(t.Context(), genState))
|
||||||
_, err = s1.validPowchainData(t.Context())
|
_, err = s1.validPowchainData(t.Context())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -655,6 +659,7 @@ func TestService_EnsureValidPowchainData(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.NoError(t, genState.SetSlot(1000))
|
assert.NoError(t, genState.SetSlot(1000))
|
||||||
|
|
||||||
|
genesis.StoreStateDuringTest(t, genState)
|
||||||
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(t.Context(), genState))
|
require.NoError(t, s1.cfg.beaconDB.SaveGenesisData(t.Context(), genState))
|
||||||
|
|
||||||
err = s1.cfg.beaconDB.SaveExecutionChainData(t.Context(), ðpb.ETH1ChainData{
|
err = s1.cfg.beaconDB.SaveExecutionChainData(t.Context(), ðpb.ETH1ChainData{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"clear_db.go",
|
||||||
"config.go",
|
"config.go",
|
||||||
"log.go",
|
"log.go",
|
||||||
"node.go",
|
"node.go",
|
||||||
@@ -49,7 +50,6 @@ go_library(
|
|||||||
"//beacon-chain/sync/backfill:go_default_library",
|
"//beacon-chain/sync/backfill:go_default_library",
|
||||||
"//beacon-chain/sync/backfill/coverage:go_default_library",
|
"//beacon-chain/sync/backfill/coverage:go_default_library",
|
||||||
"//beacon-chain/sync/checkpoint:go_default_library",
|
"//beacon-chain/sync/checkpoint:go_default_library",
|
||||||
"//beacon-chain/sync/genesis:go_default_library",
|
|
||||||
"//beacon-chain/sync/initial-sync:go_default_library",
|
"//beacon-chain/sync/initial-sync:go_default_library",
|
||||||
"//beacon-chain/verification:go_default_library",
|
"//beacon-chain/verification:go_default_library",
|
||||||
"//cmd:go_default_library",
|
"//cmd:go_default_library",
|
||||||
@@ -59,6 +59,7 @@ go_library(
|
|||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//container/slice:go_default_library",
|
"//container/slice:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//monitoring/prometheus:go_default_library",
|
"//monitoring/prometheus:go_default_library",
|
||||||
"//monitoring/tracing:go_default_library",
|
"//monitoring/tracing:go_default_library",
|
||||||
"//runtime:go_default_library",
|
"//runtime:go_default_library",
|
||||||
|
|||||||
101
beacon-chain/node/clear_db.go
Normal file
101
beacon-chain/node/clear_db.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/kv"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/slasherkv"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type dbClearer struct {
|
||||||
|
shouldClear bool
|
||||||
|
force bool
|
||||||
|
confirmed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
clearConfirmation = "This will delete your beacon chain database stored in your data directory. " +
|
||||||
|
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
||||||
|
|
||||||
|
clearDeclined = "Database will not be deleted. No changes have been made."
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *dbClearer) clearKV(ctx context.Context, db *kv.Store) (*kv.Store, error) {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing database")
|
||||||
|
if err := db.ClearDB(); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear database")
|
||||||
|
}
|
||||||
|
return kv.NewKVStore(ctx, db.DatabasePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearBlobs(bs *filesystem.BlobStorage) error {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing blob storage")
|
||||||
|
if err := bs.Clear(); err != nil {
|
||||||
|
return errors.Wrap(err, "could not clear blob storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearColumns(cs *filesystem.DataColumnStorage) error {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing data columns storage")
|
||||||
|
if err := cs.Clear(); err != nil {
|
||||||
|
return errors.Wrap(err, "could not clear data columns storage")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) clearSlasher(ctx context.Context, db *slasherkv.Store) (*slasherkv.Store, error) {
|
||||||
|
if !c.shouldProceed() {
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Warning("Removing slasher database")
|
||||||
|
if err := db.ClearDB(); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear slasher database")
|
||||||
|
}
|
||||||
|
return slasherkv.NewKVStore(ctx, db.DatabasePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *dbClearer) shouldProceed() bool {
|
||||||
|
if !c.shouldClear {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if c.force {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !c.confirmed {
|
||||||
|
confirmed, err := cmd.ConfirmAction(clearConfirmation, clearDeclined)
|
||||||
|
if err != nil {
|
||||||
|
log.WithError(err).Error("Not clearing db due to confirmation error")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.confirmed = confirmed
|
||||||
|
}
|
||||||
|
return c.confirmed
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDbClearer(cliCtx *cli.Context) *dbClearer {
|
||||||
|
force := cliCtx.Bool(cmd.ForceClearDB.Name)
|
||||||
|
return &dbClearer{
|
||||||
|
shouldClear: cliCtx.Bool(cmd.ClearDB.Name) || force,
|
||||||
|
force: force,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,7 +52,6 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill/coverage"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/backfill/coverage"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/checkpoint"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/checkpoint"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/genesis"
|
|
||||||
initialsync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync"
|
initialsync "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/initial-sync"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/verification"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd"
|
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
@@ -62,6 +61,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
"github.com/OffchainLabs/prysm/v6/container/slice"
|
"github.com/OffchainLabs/prysm/v6/container/slice"
|
||||||
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/monitoring/prometheus"
|
"github.com/OffchainLabs/prysm/v6/monitoring/prometheus"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime"
|
"github.com/OffchainLabs/prysm/v6/runtime"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/prereqs"
|
"github.com/OffchainLabs/prysm/v6/runtime/prereqs"
|
||||||
@@ -113,7 +113,7 @@ type BeaconNode struct {
|
|||||||
slasherAttestationsFeed *event.Feed
|
slasherAttestationsFeed *event.Feed
|
||||||
finalizedStateAtStartUp state.BeaconState
|
finalizedStateAtStartUp state.BeaconState
|
||||||
serviceFlagOpts *serviceFlagOpts
|
serviceFlagOpts *serviceFlagOpts
|
||||||
GenesisInitializer genesis.Initializer
|
GenesisProviders []genesis.Provider
|
||||||
CheckpointInitializer checkpoint.Initializer
|
CheckpointInitializer checkpoint.Initializer
|
||||||
forkChoicer forkchoice.ForkChoicer
|
forkChoicer forkchoice.ForkChoicer
|
||||||
clockWaiter startup.ClockWaiter
|
clockWaiter startup.ClockWaiter
|
||||||
@@ -127,6 +127,7 @@ type BeaconNode struct {
|
|||||||
syncChecker *initialsync.SyncChecker
|
syncChecker *initialsync.SyncChecker
|
||||||
slasherEnabled bool
|
slasherEnabled bool
|
||||||
lcStore *lightclient.Store
|
lcStore *lightclient.Store
|
||||||
|
ConfigOptions []params.Option
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new node instance, sets up configuration options, and registers
|
// New creates a new node instance, sets up configuration options, and registers
|
||||||
@@ -135,18 +136,13 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
if err := configureBeacon(cliCtx); err != nil {
|
if err := configureBeacon(cliCtx); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not set beacon configuration options")
|
return nil, errors.Wrap(err, "could not set beacon configuration options")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes any forks here.
|
|
||||||
params.BeaconConfig().InitializeForkSchedule()
|
|
||||||
|
|
||||||
registry := runtime.NewServiceRegistry()
|
|
||||||
ctx := cliCtx.Context
|
ctx := cliCtx.Context
|
||||||
|
|
||||||
beacon := &BeaconNode{
|
beacon := &BeaconNode{
|
||||||
cliCtx: cliCtx,
|
cliCtx: cliCtx,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
services: registry,
|
services: runtime.NewServiceRegistry(),
|
||||||
stop: make(chan struct{}),
|
stop: make(chan struct{}),
|
||||||
stateFeed: new(event.Feed),
|
stateFeed: new(event.Feed),
|
||||||
blockFeed: new(event.Feed),
|
blockFeed: new(event.Feed),
|
||||||
@@ -173,6 +169,24 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbClearer := newDbClearer(cliCtx)
|
||||||
|
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
|
||||||
|
boltFname := filepath.Join(dataDir, kv.BeaconNodeDbDirName)
|
||||||
|
kvdb, err := openDB(ctx, boltFname, dbClearer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not open database")
|
||||||
|
}
|
||||||
|
beacon.db = kvdb
|
||||||
|
|
||||||
|
providers := append(beacon.GenesisProviders, kv.NewLegacyGenesisProvider(kvdb))
|
||||||
|
if err := genesis.Initialize(ctx, dataDir, providers...); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not initialize genesis state")
|
||||||
|
}
|
||||||
|
|
||||||
|
beacon.ConfigOptions = append([]params.Option{params.WithGenesisValidatorsRoot(genesis.ValidatorsRoot())}, beacon.ConfigOptions...)
|
||||||
|
params.BeaconConfig().ApplyOptions(beacon.ConfigOptions...)
|
||||||
|
params.BeaconConfig().InitializeForkSchedule()
|
||||||
|
|
||||||
synchronizer := startup.NewClockSynchronizer()
|
synchronizer := startup.NewClockSynchronizer()
|
||||||
beacon.clockWaiter = synchronizer
|
beacon.clockWaiter = synchronizer
|
||||||
beacon.forkChoicer = doublylinkedtree.New()
|
beacon.forkChoicer = doublylinkedtree.New()
|
||||||
@@ -191,6 +205,9 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
}
|
}
|
||||||
beacon.BlobStorage = blobs
|
beacon.BlobStorage = blobs
|
||||||
}
|
}
|
||||||
|
if err := dbClearer.clearBlobs(beacon.BlobStorage); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear blob storage")
|
||||||
|
}
|
||||||
|
|
||||||
if beacon.DataColumnStorage == nil {
|
if beacon.DataColumnStorage == nil {
|
||||||
dataColumnStorage, err := filesystem.NewDataColumnStorage(cliCtx.Context, beacon.DataColumnStorageOptions...)
|
dataColumnStorage, err := filesystem.NewDataColumnStorage(cliCtx.Context, beacon.DataColumnStorageOptions...)
|
||||||
@@ -200,8 +217,11 @@ func New(cliCtx *cli.Context, cancel context.CancelFunc, opts ...Option) (*Beaco
|
|||||||
|
|
||||||
beacon.DataColumnStorage = dataColumnStorage
|
beacon.DataColumnStorage = dataColumnStorage
|
||||||
}
|
}
|
||||||
|
if err := dbClearer.clearColumns(beacon.DataColumnStorage); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not clear data column storage")
|
||||||
|
}
|
||||||
|
|
||||||
bfs, err := startBaseServices(cliCtx, beacon, depositAddress)
|
bfs, err := startBaseServices(cliCtx, beacon, depositAddress, dbClearer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not start modules")
|
return nil, errors.Wrap(err, "could not start modules")
|
||||||
}
|
}
|
||||||
@@ -289,7 +309,7 @@ func configureBeacon(cliCtx *cli.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress string) (*backfill.Store, error) {
|
func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress string, clearer *dbClearer) (*backfill.Store, error) {
|
||||||
ctx := cliCtx.Context
|
ctx := cliCtx.Context
|
||||||
log.Debugln("Starting DB")
|
log.Debugln("Starting DB")
|
||||||
if err := beacon.startDB(cliCtx, depositAddress); err != nil {
|
if err := beacon.startDB(cliCtx, depositAddress); err != nil {
|
||||||
@@ -299,7 +319,7 @@ func startBaseServices(cliCtx *cli.Context, beacon *BeaconNode, depositAddress s
|
|||||||
beacon.BlobStorage.WarmCache()
|
beacon.BlobStorage.WarmCache()
|
||||||
|
|
||||||
log.Debugln("Starting Slashing DB")
|
log.Debugln("Starting Slashing DB")
|
||||||
if err := beacon.startSlasherDB(cliCtx); err != nil {
|
if err := beacon.startSlasherDB(cliCtx, clearer); err != nil {
|
||||||
return nil, errors.Wrap(err, "could not start slashing DB")
|
return nil, errors.Wrap(err, "could not start slashing DB")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,43 +499,6 @@ func (b *BeaconNode) Close() {
|
|||||||
close(b.stop)
|
close(b.stop)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BeaconNode) clearDB(clearDB, forceClearDB bool, d *kv.Store, dbPath string) (*kv.Store, error) {
|
|
||||||
var err error
|
|
||||||
clearDBConfirmed := false
|
|
||||||
|
|
||||||
if clearDB && !forceClearDB {
|
|
||||||
const (
|
|
||||||
actionText = "This will delete your beacon chain database stored in your data directory. " +
|
|
||||||
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
|
||||||
|
|
||||||
deniedText = "Database will not be deleted. No changes have been made."
|
|
||||||
)
|
|
||||||
|
|
||||||
clearDBConfirmed, err = cmd.ConfirmAction(actionText, deniedText)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "could not confirm action")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if clearDBConfirmed || forceClearDB {
|
|
||||||
log.Warning("Removing database")
|
|
||||||
if err := d.ClearDB(); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.BlobStorage.Clear(); err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not clear blob storage")
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err = kv.NewKVStore(b.ctx, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "could not create new database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
||||||
knownContract, err := b.db.DepositContractAddress(b.ctx)
|
knownContract, err := b.db.DepositContractAddress(b.ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -539,60 +522,36 @@ func (b *BeaconNode) checkAndSaveDepositContract(depositAddress string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
func openDB(ctx context.Context, dbPath string, clearer *dbClearer) (*kv.Store, error) {
|
||||||
var depositCache cache.DepositCache
|
|
||||||
|
|
||||||
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
|
||||||
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
|
||||||
clearDBRequired := cliCtx.Bool(cmd.ClearDB.Name)
|
|
||||||
forceClearDBRequired := cliCtx.Bool(cmd.ForceClearDB.Name)
|
|
||||||
|
|
||||||
log.WithField("databasePath", dbPath).Info("Checking DB")
|
log.WithField("databasePath", dbPath).Info("Checking DB")
|
||||||
|
|
||||||
d, err := kv.NewKVStore(b.ctx, dbPath)
|
d, err := kv.NewKVStore(ctx, dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not create database at %s", dbPath)
|
return nil, errors.Wrapf(err, "could not create database at %s", dbPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
if clearDBRequired || forceClearDBRequired {
|
d, err = clearer.clearKV(ctx, d)
|
||||||
d, err = b.clearDB(clearDBRequired, forceClearDBRequired, d, dbPath)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, errors.Wrap(err, "could not clear database")
|
||||||
return errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.RunMigrations(b.ctx); err != nil {
|
return d, d.RunMigrations(ctx)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
b.db = d
|
func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
||||||
|
depositCache, err := depositsnapshot.New()
|
||||||
depositCache, err = depositsnapshot.New()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "could not create deposit cache")
|
return errors.Wrap(err, "could not create deposit cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
b.depositCache = depositCache
|
b.depositCache = depositCache
|
||||||
|
|
||||||
if b.GenesisInitializer != nil {
|
|
||||||
if err := b.GenesisInitializer.Initialize(b.ctx, d); err != nil {
|
|
||||||
if errors.Is(err, db.ErrExistingGenesisState) {
|
|
||||||
return errors.Errorf("Genesis state flag specified but a genesis state "+
|
|
||||||
"exists already. Run again with --%s and/or ensure you are using the "+
|
|
||||||
"appropriate testnet flag to load the given genesis state.", cmd.ClearDB.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.Wrap(err, "could not load genesis from file")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.db.EnsureEmbeddedGenesis(b.ctx); err != nil {
|
if err := b.db.EnsureEmbeddedGenesis(b.ctx); err != nil {
|
||||||
return errors.Wrap(err, "could not ensure embedded genesis")
|
return errors.Wrap(err, "could not ensure embedded genesis")
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.CheckpointInitializer != nil {
|
if b.CheckpointInitializer != nil {
|
||||||
log.Info("Checkpoint sync - Downloading origin state and block")
|
log.Info("Checkpoint sync - Downloading origin state and block")
|
||||||
if err := b.CheckpointInitializer.Initialize(b.ctx, d); err != nil {
|
if err := b.CheckpointInitializer.Initialize(b.ctx, b.db); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,49 +563,25 @@ func (b *BeaconNode) startDB(cliCtx *cli.Context, depositAddress string) error {
|
|||||||
log.WithField("address", depositAddress).Info("Deposit contract")
|
log.WithField("address", depositAddress).Info("Deposit contract")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (b *BeaconNode) startSlasherDB(cliCtx *cli.Context, clearer *dbClearer) error {
|
||||||
func (b *BeaconNode) startSlasherDB(cliCtx *cli.Context) error {
|
|
||||||
if !b.slasherEnabled {
|
if !b.slasherEnabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
baseDir := cliCtx.String(cmd.DataDirFlag.Name)
|
||||||
|
|
||||||
if cliCtx.IsSet(flags.SlasherDirFlag.Name) {
|
if cliCtx.IsSet(flags.SlasherDirFlag.Name) {
|
||||||
baseDir = cliCtx.String(flags.SlasherDirFlag.Name)
|
baseDir = cliCtx.String(flags.SlasherDirFlag.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
dbPath := filepath.Join(baseDir, kv.BeaconNodeDbDirName)
|
||||||
clearDB := cliCtx.Bool(cmd.ClearDB.Name)
|
|
||||||
forceClearDB := cliCtx.Bool(cmd.ForceClearDB.Name)
|
|
||||||
|
|
||||||
log.WithField("databasePath", dbPath).Info("Checking DB")
|
log.WithField("databasePath", dbPath).Info("Checking DB")
|
||||||
|
|
||||||
d, err := slasherkv.NewKVStore(b.ctx, dbPath)
|
d, err := slasherkv.NewKVStore(b.ctx, dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
clearDBConfirmed := false
|
d, err = clearer.clearSlasher(b.ctx, d)
|
||||||
if clearDB && !forceClearDB {
|
if err != nil {
|
||||||
actionText := "This will delete your beacon chain database stored in your data directory. " +
|
return errors.Wrap(err, "could not clear slasher database")
|
||||||
"Your database backups will not be removed - do you want to proceed? (Y/N)"
|
|
||||||
deniedText := "Database will not be deleted. No changes have been made."
|
|
||||||
clearDBConfirmed, err = cmd.ConfirmAction(actionText, deniedText)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if clearDBConfirmed || forceClearDB {
|
|
||||||
log.Warning("Removing database")
|
|
||||||
if err := d.ClearDB(); err != nil {
|
|
||||||
return errors.Wrap(err, "could not clear database")
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err = slasherkv.NewKVStore(b.ctx, dbPath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "could not create new database")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.slasherDB = d
|
b.slasherDB = d
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/builder"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/builder"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/db/filesystem"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/execution"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option for beacon node configuration.
|
// Option for beacon node configuration.
|
||||||
@@ -51,6 +52,13 @@ func WithBlobStorageOptions(opt ...filesystem.BlobStorageOption) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WithConfigOptions(opt ...params.Option) Option {
|
||||||
|
return func(bn *BeaconNode) error {
|
||||||
|
bn.ConfigOptions = append(bn.ConfigOptions, opt...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithDataColumnStorage sets the DataColumnStorage backend for the BeaconNode
|
// WithDataColumnStorage sets the DataColumnStorage backend for the BeaconNode
|
||||||
func WithDataColumnStorage(bs *filesystem.DataColumnStorage) Option {
|
func WithDataColumnStorage(bs *filesystem.DataColumnStorage) Option {
|
||||||
return func(bn *BeaconNode) error {
|
return func(bn *BeaconNode) error {
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package genesis
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
|
||||||
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
|
||||||
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
|
||||||
"github.com/golang/snappy"
|
|
||||||
)
|
|
||||||
|
|
||||||
var embeddedStates = map[string]*[]byte{}
|
|
||||||
|
|
||||||
// State returns a copy of the genesis state from a hardcoded value.
|
|
||||||
func State(name string) (state.BeaconState, error) {
|
|
||||||
sb, exists := embeddedStates[name]
|
|
||||||
if exists {
|
|
||||||
return load(*sb)
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// load a compressed ssz state file into a beacon state struct.
|
|
||||||
func load(b []byte) (state.BeaconState, error) {
|
|
||||||
st := ðpb.BeaconState{}
|
|
||||||
b, err := snappy.Decode(nil /*dst*/, b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := st.UnmarshalSSZ(b); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return state_native.InitializeFromProtoUnsafePhase0(st)
|
|
||||||
}
|
|
||||||
@@ -351,3 +351,7 @@ type WriteOnlyDeposits interface {
|
|||||||
type WriteOnlyProposerLookahead interface {
|
type WriteOnlyProposerLookahead interface {
|
||||||
SetProposerLookahead([]primitives.ValidatorIndex) error
|
SetProposerLookahead([]primitives.ValidatorIndex) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNil(s BeaconState) bool {
|
||||||
|
return s == nil || s.IsNil()
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,3 +34,7 @@ var fieldMap map[types.FieldIndex]types.DataType
|
|||||||
func errNotSupported(funcName string, ver int) error {
|
func errNotSupported(funcName string, ver int) error {
|
||||||
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
|
return fmt.Errorf("%s is not supported for %s", funcName, version.String(ver))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNil(s state.BeaconState) bool {
|
||||||
|
return s == nil || s.IsNil()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
load("@prysm//tools/go:def.bzl", "go_library")
|
|
||||||
|
|
||||||
go_library(
|
|
||||||
name = "go_default_library",
|
|
||||||
srcs = [
|
|
||||||
"api.go",
|
|
||||||
"file.go",
|
|
||||||
"log.go",
|
|
||||||
],
|
|
||||||
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/sync/genesis",
|
|
||||||
visibility = ["//visibility:public"],
|
|
||||||
deps = [
|
|
||||||
"//api/client:go_default_library",
|
|
||||||
"//api/client/beacon:go_default_library",
|
|
||||||
"//beacon-chain/db:go_default_library",
|
|
||||||
"//crypto/hash:go_default_library",
|
|
||||||
"//io/file:go_default_library",
|
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
|
||||||
"@com_github_sirupsen_logrus//:go_default_library",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package genesis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/api/client"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/api/client/beacon"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// APIInitializer manages initializing the genesis state and block to prepare the beacon node for syncing.
|
|
||||||
// The genesis state is retrieved from the remote beacon node api, using the debug state retrieval endpoint.
|
|
||||||
type APIInitializer struct {
|
|
||||||
c *beacon.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAPIInitializer creates an APIInitializer, handling the set up of a beacon node api client
|
|
||||||
// using the provided host string.
|
|
||||||
func NewAPIInitializer(beaconNodeHost string) (*APIInitializer, error) {
|
|
||||||
c, err := beacon.NewClient(beaconNodeHost, client.WithMaxBodySize(client.MaxBodySizeState))
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "unable to parse beacon node url or hostname - %s", beaconNodeHost)
|
|
||||||
}
|
|
||||||
return &APIInitializer{c: c}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize downloads origin state and block for checkpoint sync and initializes database records to
|
|
||||||
// prepare the node to begin syncing from that point.
|
|
||||||
func (dl *APIInitializer) Initialize(ctx context.Context, d db.Database) error {
|
|
||||||
existing, err := d.GenesisState(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if existing != nil && !existing.IsNil() {
|
|
||||||
htr, err := existing.HashTreeRoot(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "error while computing hash_tree_root of existing genesis state")
|
|
||||||
}
|
|
||||||
log.Warnf("database contains genesis with htr=%#x, ignoring remote genesis state parameter", htr)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
sb, err := dl.c.GetState(ctx, beacon.IdGenesis)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "Error retrieving genesis state from %s", dl.c.NodeURL())
|
|
||||||
}
|
|
||||||
return d.LoadGenesis(ctx, sb)
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package genesis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/db"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/crypto/hash"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/io/file"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Initializer describes a type that is able to obtain the checkpoint sync data (BeaconState and SignedBeaconBlock)
|
|
||||||
// in some way and perform database setup to prepare the beacon node for syncing from the given checkpoint.
|
|
||||||
// See FileInitializer and APIInitializer.
|
|
||||||
type Initializer interface {
|
|
||||||
Initialize(ctx context.Context, d db.Database) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFileInitializer validates the given path information and creates an Initializer which will
|
|
||||||
// use the provided state and block files to prepare the node for checkpoint sync.
|
|
||||||
func NewFileInitializer(statePath string) (*FileInitializer, error) {
|
|
||||||
var err error
|
|
||||||
if err = existsAndIsFile(statePath); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// stat just to make sure it actually exists and is a file
|
|
||||||
return &FileInitializer{statePath: statePath}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileInitializer initializes a beacon-node database genesis state and block
|
|
||||||
// using ssz-encoded state data stored in files on the local filesystem.
|
|
||||||
type FileInitializer struct {
|
|
||||||
statePath string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize is called in the BeaconNode db startup code if an Initializer is present.
|
|
||||||
// Initialize prepares the beacondb using the provided genesis state.
|
|
||||||
func (fi *FileInitializer) Initialize(ctx context.Context, d db.Database) error {
|
|
||||||
serState, err := file.ReadFileAsBytes(fi.statePath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error reading state file %s for checkpoint sync init", fi.statePath)
|
|
||||||
}
|
|
||||||
log.WithField(
|
|
||||||
"hash", fmt.Sprintf("%#x", hash.FastSum256(serState)),
|
|
||||||
).Info("Loading genesis state from disk.")
|
|
||||||
return d.LoadGenesis(ctx, serState)
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Initializer = &FileInitializer{}
|
|
||||||
|
|
||||||
func existsAndIsFile(path string) error {
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "error checking existence of ssz-encoded file %s for genesis state init", path)
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
|
||||||
return fmt.Errorf("%s is a directory, please specify full path to file", path)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
3
changelog/kasey_init-genesis-asap.md
Normal file
3
changelog/kasey_init-genesis-asap.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
## Fixed
|
||||||
|
|
||||||
|
- Genesis state, timestamp and validators root now ubiquitously available at node startup, supporting tech debt cleanup.
|
||||||
@@ -19,12 +19,12 @@ go_library(
|
|||||||
"//cmd/beacon-chain/db:go_default_library",
|
"//cmd/beacon-chain/db:go_default_library",
|
||||||
"//cmd/beacon-chain/execution:go_default_library",
|
"//cmd/beacon-chain/execution:go_default_library",
|
||||||
"//cmd/beacon-chain/flags:go_default_library",
|
"//cmd/beacon-chain/flags:go_default_library",
|
||||||
|
"//cmd/beacon-chain/genesis:go_default_library",
|
||||||
"//cmd/beacon-chain/jwt:go_default_library",
|
"//cmd/beacon-chain/jwt:go_default_library",
|
||||||
"//cmd/beacon-chain/storage:go_default_library",
|
"//cmd/beacon-chain/storage:go_default_library",
|
||||||
"//cmd/beacon-chain/sync/backfill:go_default_library",
|
"//cmd/beacon-chain/sync/backfill:go_default_library",
|
||||||
"//cmd/beacon-chain/sync/backfill/flags:go_default_library",
|
"//cmd/beacon-chain/sync/backfill/flags:go_default_library",
|
||||||
"//cmd/beacon-chain/sync/checkpoint:go_default_library",
|
"//cmd/beacon-chain/sync/checkpoint:go_default_library",
|
||||||
"//cmd/beacon-chain/sync/genesis:go_default_library",
|
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//io/file:go_default_library",
|
"//io/file:go_default_library",
|
||||||
"//io/logs:go_default_library",
|
"//io/logs:go_default_library",
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["options.go"],
|
srcs = ["options.go"],
|
||||||
importpath = "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/genesis",
|
importpath = "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/genesis",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//beacon-chain/node:go_default_library",
|
"//beacon-chain/node:go_default_library",
|
||||||
"//beacon-chain/sync/genesis:go_default_library",
|
|
||||||
"//cmd/beacon-chain/sync/checkpoint:go_default_library",
|
"//cmd/beacon-chain/sync/checkpoint:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"@com_github_pkg_errors//:go_default_library",
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
"@com_github_sirupsen_logrus//:go_default_library",
|
"@com_github_sirupsen_logrus//:go_default_library",
|
||||||
"@com_github_urfave_cli_v2//:go_default_library",
|
"@com_github_urfave_cli_v2//:go_default_library",
|
||||||
@@ -2,8 +2,8 @@ package genesis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/node"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/node"
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/sync/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@@ -24,11 +24,21 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// BeaconNodeOptions is responsible for determining if the checkpoint sync options have been used, and if so,
|
// BeaconNodeOptions handles options for customizing the source of the genesis state.
|
||||||
// reading the block and state ssz-serialized values from the filesystem locations specified and preparing a
|
|
||||||
// checkpoint.Initializer, which uses the provided io.ReadClosers to initialize the beacon node database.
|
|
||||||
func BeaconNodeOptions(c *cli.Context) ([]node.Option, error) {
|
func BeaconNodeOptions(c *cli.Context) ([]node.Option, error) {
|
||||||
statePath := c.Path(StatePath.Name)
|
statePath := c.Path(StatePath.Name)
|
||||||
|
if statePath != "" {
|
||||||
|
opt := func(node *node.BeaconNode) (err error) {
|
||||||
|
provider, err := genesis.NewFileProvider(statePath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error preparing to initialize genesis db state from local ssz files")
|
||||||
|
}
|
||||||
|
node.GenesisProviders = append(node.GenesisProviders, provider)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return []node.Option{opt}, nil
|
||||||
|
}
|
||||||
|
|
||||||
remoteURL := c.String(BeaconAPIURL.Name)
|
remoteURL := c.String(BeaconAPIURL.Name)
|
||||||
if remoteURL == "" && c.String(checkpoint.RemoteURL.Name) != "" {
|
if remoteURL == "" && c.String(checkpoint.RemoteURL.Name) != "" {
|
||||||
log.Infof("Using checkpoint sync url %s for value in --%s flag", c.String(checkpoint.RemoteURL.Name), BeaconAPIURL.Name)
|
log.Infof("Using checkpoint sync url %s for value in --%s flag", c.String(checkpoint.RemoteURL.Name), BeaconAPIURL.Name)
|
||||||
@@ -36,26 +46,16 @@ func BeaconNodeOptions(c *cli.Context) ([]node.Option, error) {
|
|||||||
}
|
}
|
||||||
if remoteURL != "" {
|
if remoteURL != "" {
|
||||||
opt := func(node *node.BeaconNode) error {
|
opt := func(node *node.BeaconNode) error {
|
||||||
var err error
|
provider, err := genesis.NewAPIProvider(remoteURL)
|
||||||
node.GenesisInitializer, err = genesis.NewAPIInitializer(remoteURL)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "error constructing beacon node api client for genesis state init")
|
return errors.Wrap(err, "error constructing beacon node api client for genesis state init")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.GenesisProviders = append(node.GenesisProviders, provider)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return []node.Option{opt}, nil
|
return []node.Option{opt}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if statePath == "" {
|
return nil, nil
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
opt := func(node *node.BeaconNode) (err error) {
|
|
||||||
node.GenesisInitializer, err = genesis.NewFileInitializer(statePath)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "error preparing to initialize genesis db state from local ssz files")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return []node.Option{opt}, nil
|
|
||||||
}
|
}
|
||||||
@@ -15,12 +15,12 @@ import (
|
|||||||
dbcommands "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/db"
|
dbcommands "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/db"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/execution"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/execution"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/genesis"
|
||||||
jwtcommands "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/jwt"
|
jwtcommands "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/jwt"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/storage"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/storage"
|
||||||
backfill "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill"
|
backfill "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill"
|
||||||
bflags "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill/flags"
|
bflags "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill/flags"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/io/file"
|
"github.com/OffchainLabs/prysm/v6/io/file"
|
||||||
"github.com/OffchainLabs/prysm/v6/io/logs"
|
"github.com/OffchainLabs/prysm/v6/io/logs"
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd"
|
"github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/storage"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/storage"
|
||||||
backfill "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill/flags"
|
backfill "github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/backfill/flags"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/checkpoint"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/runtime/debug"
|
"github.com/OffchainLabs/prysm/v6/runtime/debug"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ go_library(
|
|||||||
"mainnet_config.go",
|
"mainnet_config.go",
|
||||||
"minimal_config.go",
|
"minimal_config.go",
|
||||||
"network_config.go",
|
"network_config.go",
|
||||||
|
"opts.go",
|
||||||
"testnet_custom_network_config.go",
|
"testnet_custom_network_config.go",
|
||||||
"testnet_e2e_config.go",
|
"testnet_e2e_config.go",
|
||||||
"testnet_holesky_config.go",
|
"testnet_holesky_config.go",
|
||||||
@@ -70,9 +71,9 @@ go_test(
|
|||||||
gotags = ["develop"],
|
gotags = ["develop"],
|
||||||
tags = ["CI_race_detection"],
|
tags = ["CI_race_detection"],
|
||||||
deps = [
|
deps = [
|
||||||
"//beacon-chain/state/genesis:go_default_library",
|
|
||||||
"//consensus-types/primitives:go_default_library",
|
"//consensus-types/primitives:go_default_library",
|
||||||
"//encoding/bytesutil:go_default_library",
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//genesis:go_default_library",
|
||||||
"//io/file:go_default_library",
|
"//io/file:go_default_library",
|
||||||
"//testing/assert:go_default_library",
|
"//testing/assert:go_default_library",
|
||||||
"//testing/require:go_default_library",
|
"//testing/require:go_default_library",
|
||||||
|
|||||||
@@ -340,6 +340,12 @@ type BlobScheduleEntry struct {
|
|||||||
MaxBlobsPerBlock uint64 `yaml:"MAX_BLOBS_PER_BLOCK" json:"MAX_BLOBS_PER_BLOCK"`
|
MaxBlobsPerBlock uint64 `yaml:"MAX_BLOBS_PER_BLOCK" json:"MAX_BLOBS_PER_BLOCK"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BeaconChainConfig) ApplyOptions(opts ...Option) {
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InitializeForkSchedule initializes the schedules forks baked into the config.
|
// InitializeForkSchedule initializes the schedules forks baked into the config.
|
||||||
func (b *BeaconChainConfig) InitializeForkSchedule() {
|
func (b *BeaconChainConfig) InitializeForkSchedule() {
|
||||||
// Reset Fork Version Schedule.
|
// Reset Fork Version Schedule.
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/testing/require"
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,14 +97,14 @@ func TestConfig_WithinDAPeriod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigGenesisValidatorRoot(t *testing.T) {
|
func TestConfigGenesisValidatorRoot(t *testing.T) {
|
||||||
g, err := genesis.State(params.MainnetName)
|
params.SetActiveTestCleanup(t, params.MainnetBeaconConfig)
|
||||||
require.NoError(t, err)
|
genesis.StoreEmbeddedDuringTest(t, params.BeaconConfig().ConfigName)
|
||||||
|
g, err := genesis.State()
|
||||||
gvr := g.GenesisValidatorsRoot()
|
require.NoError(t, err, "failed to load genesis state")
|
||||||
|
if !bytes.Equal(g.GenesisValidatorsRoot(), params.BeaconConfig().GenesisValidatorsRoot[:]) {
|
||||||
if !bytes.Equal(gvr, params.BeaconConfig().GenesisValidatorsRoot[:]) {
|
|
||||||
t.Fatal("mainnet params genesis validator root does not match the mainnet genesis state value")
|
t.Fatal("mainnet params genesis validator root does not match the mainnet genesis state value")
|
||||||
}
|
}
|
||||||
|
require.Equal(t, params.BeaconConfig().GenesisValidatorsRoot, genesis.ValidatorsRoot())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxBlobsPerBlock(t *testing.T) {
|
func TestMaxBlobsPerBlock(t *testing.T) {
|
||||||
|
|||||||
16
config/params/opts.go
Normal file
16
config/params/opts.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package params
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Option func(*BeaconChainConfig)
|
||||||
|
|
||||||
|
func WithGenesisValidatorsRoot(gvr [32]byte) Option {
|
||||||
|
return func(cfg *BeaconChainConfig) {
|
||||||
|
cfg.GenesisValidatorsRoot = gvr
|
||||||
|
log.WithField("genesis_validators_root", fmt.Sprintf("%#x", gvr)).Info("Overriding genesis validators root")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -292,3 +292,11 @@ func (cf *VersionedUnmarshaler) validateVersion(slot primitives.Slot) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func UnmarshalState(marshaled []byte) (state.BeaconState, error) {
|
||||||
|
vu, err := FromState(marshaled)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to detect version from state")
|
||||||
|
}
|
||||||
|
return vu.UnmarshalBeaconState(marshaled)
|
||||||
|
}
|
||||||
|
|||||||
@@ -728,3 +728,111 @@ func signedTestBlindedBlockFulu(t *testing.T, slot primitives.Slot) interfaces.R
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalStateStandalone(t *testing.T) {
|
||||||
|
ctx := t.Context()
|
||||||
|
defer util.HackForksMaxuint(t, []int{version.Electra, version.Fulu})()
|
||||||
|
|
||||||
|
bc := params.BeaconConfig()
|
||||||
|
altairSlot, err := slots.EpochStart(bc.AltairForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
bellaSlot, err := slots.EpochStart(bc.BellatrixForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
capellaSlot, err := slots.EpochStart(bc.CapellaForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
denebSlot, err := slots.EpochStart(bc.DenebForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
electraSlot, err := slots.EpochStart(bc.ElectraForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
fuluSlot, err := slots.EpochStart(bc.FuluForkEpoch)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
version int
|
||||||
|
slot primitives.Slot
|
||||||
|
forkversion [4]byte
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "phase0",
|
||||||
|
version: version.Phase0,
|
||||||
|
slot: 0,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.GenesisForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "altair",
|
||||||
|
version: version.Altair,
|
||||||
|
slot: altairSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.AltairForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bellatrix",
|
||||||
|
version: version.Bellatrix,
|
||||||
|
slot: bellaSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.BellatrixForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "capella",
|
||||||
|
version: version.Capella,
|
||||||
|
slot: capellaSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.CapellaForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deneb",
|
||||||
|
version: version.Deneb,
|
||||||
|
slot: denebSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.DenebForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "electra",
|
||||||
|
version: version.Electra,
|
||||||
|
slot: electraSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.ElectraForkVersion),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "fulu",
|
||||||
|
version: version.Fulu,
|
||||||
|
slot: fuluSlot,
|
||||||
|
forkversion: bytesutil.ToBytes4(bc.FuluForkVersion),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
// Create a state for the specific version
|
||||||
|
originalState, err := stateForVersion(c.version)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, originalState.SetFork(ðpb.Fork{
|
||||||
|
PreviousVersion: make([]byte, 4),
|
||||||
|
CurrentVersion: c.forkversion[:],
|
||||||
|
Epoch: 0,
|
||||||
|
}))
|
||||||
|
require.NoError(t, originalState.SetSlot(c.slot))
|
||||||
|
|
||||||
|
marshaled, err := originalState.MarshalSSZ()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
unmarshaledState, err := UnmarshalState(marshaled)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, unmarshaledState)
|
||||||
|
|
||||||
|
// Verify the unmarshaled state matches the original
|
||||||
|
expectedRoot, err := originalState.HashTreeRoot(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
actualRoot, err := unmarshaledState.HashTreeRoot(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.DeepEqual(t, expectedRoot, actualRoot)
|
||||||
|
|
||||||
|
// Verify basic state properties
|
||||||
|
require.Equal(t, c.slot, unmarshaledState.Slot())
|
||||||
|
fork := unmarshaledState.Fork()
|
||||||
|
require.DeepEqual(t, c.forkversion[:], fork.CurrentVersion)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("invalid state data", func(t *testing.T) {
|
||||||
|
invalidData := []byte("bad")
|
||||||
|
_, err := UnmarshalState(invalidData)
|
||||||
|
require.ErrorContains(t, "failed to detect version from state", err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
49
genesis/BUILD.bazel
Normal file
49
genesis/BUILD.bazel
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"embedded.go",
|
||||||
|
"errors.go",
|
||||||
|
"initialize.go",
|
||||||
|
"log.go",
|
||||||
|
"providers.go",
|
||||||
|
"storage.go",
|
||||||
|
"testing.go",
|
||||||
|
],
|
||||||
|
importpath = "github.com/OffchainLabs/prysm/v6/genesis",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//api/client:go_default_library",
|
||||||
|
"//api/client/beacon:go_default_library",
|
||||||
|
"//beacon-chain/state:go_default_library",
|
||||||
|
"//config/params:go_default_library",
|
||||||
|
"//encoding/bytesutil:go_default_library",
|
||||||
|
"//encoding/ssz/detect:go_default_library",
|
||||||
|
"//genesis/internal/embedded:go_default_library",
|
||||||
|
"//io/file:go_default_library",
|
||||||
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
|
"@com_github_pkg_errors//:go_default_library",
|
||||||
|
"@com_github_sirupsen_logrus//:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"embedded_test.go",
|
||||||
|
"initialize_test.go",
|
||||||
|
],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//beacon-chain/state:go_default_library",
|
||||||
|
"//beacon-chain/state/state-native:go_default_library",
|
||||||
|
"//config/params:go_default_library",
|
||||||
|
"//consensus-types/primitives:go_default_library",
|
||||||
|
"//genesis/internal/embedded:go_default_library",
|
||||||
|
"//proto/prysm/v1alpha1:go_default_library",
|
||||||
|
"//testing/require:go_default_library",
|
||||||
|
"//testing/util:go_default_library",
|
||||||
|
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
25
genesis/embedded.go
Normal file
25
genesis/embedded.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis/internal/embedded"
|
||||||
|
)
|
||||||
|
|
||||||
|
var embeddedGenesisData map[string]GenesisData
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
embeddedGenesisData = make(map[string]GenesisData)
|
||||||
|
embeddedGenesisData[params.MainnetName] = GenesisData{
|
||||||
|
ValidatorsRoot: [32]byte{75, 54, 61, 185, 78, 40, 97, 32, 215, 110, 185, 5, 52, 15, 221, 78, 84, 191, 233, 240, 107, 243, 63, 246, 207, 90, 210, 127, 81, 27, 254, 149},
|
||||||
|
Time: time.Unix(1606824023, 0),
|
||||||
|
embeddedBytes: func() ([]byte, error) {
|
||||||
|
return embedded.BytesByName(params.MainnetName)
|
||||||
|
},
|
||||||
|
embeddedState: func() (state.BeaconState, error) {
|
||||||
|
return embedded.ByName(params.MainnetName)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
19
genesis/embedded_test.go
Normal file
19
genesis/embedded_test.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis/internal/embedded"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEmbededGenesisDataMatchesMainnet(t *testing.T) {
|
||||||
|
st, err := embedded.ByName(params.MainnetName)
|
||||||
|
require.NoError(t, err)
|
||||||
|
gvr := st.GenesisValidatorsRoot()
|
||||||
|
|
||||||
|
data := embeddedGenesisData[params.MainnetName]
|
||||||
|
require.DeepEqual(t, gvr, data.ValidatorsRoot[:])
|
||||||
|
require.Equal(t, st.GenesisTime(), data.Time)
|
||||||
|
}
|
||||||
8
genesis/errors.go
Normal file
8
genesis/errors.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var ErrFilePathUnset = errors.New("path to genesis data directory is not set")
|
||||||
|
var ErrGenesisStateNotInitialized = errors.New("genesis state has not been initialized")
|
||||||
|
var ErrNotGenesisStateFile = errors.New("file is not a genesis state file")
|
||||||
|
var ErrGenesisFileNotFound = errors.New("genesis state file not found")
|
||||||
111
genesis/initialize.go
Normal file
111
genesis/initialize.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/encoding/bytesutil"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Initialize is mainly exported for the node initialization process to specify providers of the genesis data
|
||||||
|
// and the path to the local storage location via cli flags.
|
||||||
|
func Initialize(ctx context.Context, dir string, providers ...Provider) error {
|
||||||
|
emb, ok := embeddedGenesisData[params.BeaconConfig().ConfigName]
|
||||||
|
if ok {
|
||||||
|
setPkgVar(emb, true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
gd, err := findGenesisFile(dir)
|
||||||
|
if err == nil {
|
||||||
|
setPkgVar(gd, true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !errors.Is(err, ErrGenesisFileNotFound) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return initializeFromProviders(ctx, dir, providers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeFromProviders(ctx context.Context, dir string, providers ...Provider) error {
|
||||||
|
for _, get := range providers {
|
||||||
|
gs, err := get.Genesis(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.WithField("provider", fmt.Sprintf("%T", get)).Warn("genesis provider failed")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
gd, err := newGenesisData(gs, dir)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "new genesis data")
|
||||||
|
}
|
||||||
|
return Store(gd)
|
||||||
|
}
|
||||||
|
return ErrGenesisStateNotInitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGenesisData(st state.BeaconState, dir string) (GenesisData, error) {
|
||||||
|
if state.IsNil(st) {
|
||||||
|
return GenesisData{}, ErrGenesisStateNotInitialized
|
||||||
|
}
|
||||||
|
if dir == "" {
|
||||||
|
return GenesisData{}, ErrFilePathUnset
|
||||||
|
}
|
||||||
|
return GenesisData{
|
||||||
|
FileDir: dir,
|
||||||
|
State: st,
|
||||||
|
ValidatorsRoot: bytesutil.ToBytes32(st.GenesisValidatorsRoot()),
|
||||||
|
Time: st.GenesisTime(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findGenesisFile(dir string) (GenesisData, error) {
|
||||||
|
if dir == "" {
|
||||||
|
return GenesisData{}, ErrFilePathUnset
|
||||||
|
}
|
||||||
|
files, err := os.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return GenesisData{}, fmt.Errorf("%w: %w", ErrGenesisFileNotFound, err)
|
||||||
|
}
|
||||||
|
for _, f := range files {
|
||||||
|
gd, err := tryParseFname(dir, f)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return gd, nil
|
||||||
|
}
|
||||||
|
return GenesisData{}, ErrGenesisFileNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryParseFname(dir string, f os.DirEntry) (GenesisData, error) {
|
||||||
|
gd := GenesisData{FileDir: dir}
|
||||||
|
if f.IsDir() {
|
||||||
|
return gd, ErrNotGenesisStateFile
|
||||||
|
}
|
||||||
|
extParts := strings.Split(f.Name(), ".")
|
||||||
|
if len(extParts) != 2 || extParts[1] != "ssz" {
|
||||||
|
return gd, ErrNotGenesisStateFile
|
||||||
|
}
|
||||||
|
parts := strings.Split(extParts[0], "-")
|
||||||
|
if len(parts) != 3 || parts[genesisPart] != "genesis" {
|
||||||
|
return gd, ErrNotGenesisStateFile
|
||||||
|
}
|
||||||
|
ts, err := strconv.ParseInt(parts[timePart], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return gd, errors.Wrap(err, "parse genesis time")
|
||||||
|
}
|
||||||
|
if ts < 0 {
|
||||||
|
return gd, errors.New("genesis time cannot be negative")
|
||||||
|
}
|
||||||
|
gd.Time = time.Unix(ts, 0)
|
||||||
|
if err := hexutil.UnmarshalFixedText("genesis_validators_root", []byte(parts[gvrPart]), gd.ValidatorsRoot[:]); err != nil {
|
||||||
|
return gd, errors.Wrap(err, "unmarshal genesis validators root")
|
||||||
|
}
|
||||||
|
return gd, nil
|
||||||
|
}
|
||||||
312
genesis/initialize_test.go
Normal file
312
genesis/initialize_test.go
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
package genesis_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis"
|
||||||
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/testing/require"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/testing/util"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestInitialize(t *testing.T) {
|
||||||
|
require.NoError(t, genesis.Initialize(t.Context(), "testdata"))
|
||||||
|
require.Equal(t, params.MainnetName, params.BeaconConfig().ConfigName)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmbeddedMainnetHardcodedValues(t *testing.T) {
|
||||||
|
// Initialize genesis with mainnet config to load embedded state
|
||||||
|
require.NoError(t, genesis.Initialize(t.Context(), t.TempDir()))
|
||||||
|
|
||||||
|
// Get the initialized genesis state
|
||||||
|
state, err := genesis.State()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, state)
|
||||||
|
|
||||||
|
// Verify hardcoded validators root matches the computed value from the state
|
||||||
|
expectedValidatorsRoot := [32]byte{75, 54, 61, 185, 78, 40, 97, 32, 215, 110, 185, 5, 52, 15, 221, 78, 84, 191, 233, 240, 107, 243, 63, 246, 207, 90, 210, 127, 81, 27, 254, 149}
|
||||||
|
actualValidatorsRoot := state.GenesisValidatorsRoot()
|
||||||
|
require.Equal(t, expectedValidatorsRoot, [32]byte(actualValidatorsRoot), "hardcoded validators root does not match embedded state")
|
||||||
|
|
||||||
|
// Verify hardcoded genesis time matches the computed value from the state
|
||||||
|
expectedTime := time.Unix(1606824023, 0)
|
||||||
|
actualTime := state.GenesisTime()
|
||||||
|
require.Equal(t, expectedTime, actualTime, "hardcoded genesis time does not match embedded state")
|
||||||
|
}
|
||||||
|
|
||||||
|
// mockProvider is a test provider for genesis state
|
||||||
|
type mockProvider struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
state state.BeaconState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mockProvider) Genesis(context.Context) (state.BeaconState, error) {
|
||||||
|
if m.err != nil {
|
||||||
|
return nil, m.err
|
||||||
|
}
|
||||||
|
return m.state, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createTestGenesisState creates a deterministic genesis state for testing.
|
||||||
|
// This avoids using the embedded mainnet state which could cause false positives.
|
||||||
|
func createTestGenesisState(t *testing.T, numValidators uint64, slot primitives.Slot) state.BeaconState {
|
||||||
|
// Create a deterministic genesis state using test utilities
|
||||||
|
deposits, _, err := util.DeterministicDepositsAndKeys(numValidators)
|
||||||
|
require.NoError(t, err)
|
||||||
|
eth1Data, err := util.DeterministicEth1Data(len(deposits))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create a minimal beacon state directly
|
||||||
|
pb := ðpb.BeaconState{
|
||||||
|
Slot: slot,
|
||||||
|
GenesisTime: uint64(time.Unix(2000000000, 0).Unix()), // Use a different time than mainnet
|
||||||
|
GenesisValidatorsRoot: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32},
|
||||||
|
Eth1Data: eth1Data,
|
||||||
|
Validators: make([]*ethpb.Validator, numValidators),
|
||||||
|
Balances: make([]uint64, numValidators),
|
||||||
|
Fork: ðpb.Fork{
|
||||||
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
||||||
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
||||||
|
Epoch: 0,
|
||||||
|
},
|
||||||
|
LatestBlockHeader: ðpb.BeaconBlockHeader{
|
||||||
|
Slot: 0,
|
||||||
|
ParentRoot: make([]byte, 32),
|
||||||
|
StateRoot: make([]byte, 32),
|
||||||
|
BodyRoot: make([]byte, 32),
|
||||||
|
},
|
||||||
|
BlockRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||||
|
StateRoots: make([][]byte, params.BeaconConfig().SlotsPerHistoricalRoot),
|
||||||
|
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||||
|
Slashings: make([]uint64, params.BeaconConfig().EpochsPerSlashingsVector),
|
||||||
|
JustificationBits: []byte{0},
|
||||||
|
PreviousJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||||
|
CurrentJustifiedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||||
|
FinalizedCheckpoint: ðpb.Checkpoint{Root: make([]byte, 32)},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize validators and balances
|
||||||
|
for i := uint64(0); i < numValidators; i++ {
|
||||||
|
pb.Validators[i] = ðpb.Validator{
|
||||||
|
PublicKey: deposits[i].Data.PublicKey,
|
||||||
|
WithdrawalCredentials: deposits[i].Data.WithdrawalCredentials,
|
||||||
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
||||||
|
Slashed: false,
|
||||||
|
ActivationEligibilityEpoch: 0,
|
||||||
|
ActivationEpoch: 0,
|
||||||
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||||
|
}
|
||||||
|
pb.Balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize arrays with proper sizes
|
||||||
|
for i := 0; i < len(pb.BlockRoots); i++ {
|
||||||
|
pb.BlockRoots[i] = make([]byte, 32)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(pb.StateRoots); i++ {
|
||||||
|
pb.StateRoots[i] = make([]byte, 32)
|
||||||
|
}
|
||||||
|
for i := 0; i < len(pb.RandaoMixes); i++ {
|
||||||
|
pb.RandaoMixes[i] = make([]byte, 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := state_native.InitializeFromProtoUnsafePhase0(pb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return st
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInitializeWithProviders(t *testing.T) {
|
||||||
|
originalConfig := params.BeaconConfig().Copy()
|
||||||
|
defer params.OverrideBeaconConfig(originalConfig)
|
||||||
|
|
||||||
|
t.Run("providers_used_when_no_embedded_or_file", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MainnetConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-no-embedded"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Use a deterministic test state instead of mainnet to avoid false positives
|
||||||
|
testState := createTestGenesisState(t, 64, 0)
|
||||||
|
|
||||||
|
provider := &mockProvider{
|
||||||
|
state: testState,
|
||||||
|
name: "test-provider",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := genesis.Initialize(t.Context(), t.TempDir(), provider)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify the state was stored
|
||||||
|
storedState, err := genesis.State()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, storedState)
|
||||||
|
require.DeepEqual(t, testState.GenesisValidatorsRoot(), storedState.GenesisValidatorsRoot())
|
||||||
|
// Verify it's not the mainnet state
|
||||||
|
require.NotEqual(t, uint64(1606824023), storedState.GenesisTime().Unix())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple_providers_first_success_wins", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MainnetConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-multiple-providers"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Use deterministic test states with different slots
|
||||||
|
state1 := createTestGenesisState(t, 64, 50)
|
||||||
|
state2 := createTestGenesisState(t, 32, 100)
|
||||||
|
|
||||||
|
// Create providers - first fails, second succeeds
|
||||||
|
failingProvider := &mockProvider{
|
||||||
|
err: errors.New("provider failed"),
|
||||||
|
name: "failing-provider",
|
||||||
|
}
|
||||||
|
successProvider1 := &mockProvider{
|
||||||
|
state: state1,
|
||||||
|
name: "success-provider-1",
|
||||||
|
}
|
||||||
|
successProvider2 := &mockProvider{
|
||||||
|
state: state2,
|
||||||
|
name: "success-provider-2",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with multiple providers
|
||||||
|
err := genesis.Initialize(t.Context(), t.TempDir(), failingProvider, successProvider1, successProvider2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify first successful provider's state was used
|
||||||
|
storedState, err := genesis.State()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, storedState)
|
||||||
|
// state1 has slot 50, state2 has slot 100
|
||||||
|
require.Equal(t, primitives.Slot(50), storedState.Slot())
|
||||||
|
// Verify it's state1 by checking validator count
|
||||||
|
require.Equal(t, 64, storedState.NumValidators())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("all_providers_fail_returns_error", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MinimalSpecConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-all-fail"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Create failing providers
|
||||||
|
provider1 := &mockProvider{
|
||||||
|
err: errors.New("provider 1 failed"),
|
||||||
|
name: "failing-provider-1",
|
||||||
|
}
|
||||||
|
provider2 := &mockProvider{
|
||||||
|
err: errors.New("provider 2 failed"),
|
||||||
|
name: "failing-provider-2",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize should fail when all providers fail
|
||||||
|
err := genesis.Initialize(t.Context(), t.TempDir(), provider1, provider2)
|
||||||
|
require.ErrorIs(t, err, genesis.ErrGenesisStateNotInitialized)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no_providers_and_no_data_returns_error", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MinimalSpecConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-no-providers"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Initialize with no providers should fail
|
||||||
|
err := genesis.Initialize(t.Context(), t.TempDir())
|
||||||
|
require.ErrorIs(t, err, genesis.ErrGenesisStateNotInitialized)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("provider_returns_nil_state", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MinimalSpecConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-nil-state"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Create provider that returns nil state
|
||||||
|
provider := &mockProvider{
|
||||||
|
state: nil,
|
||||||
|
name: "nil-state-provider",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize should fail
|
||||||
|
err := genesis.Initialize(t.Context(), t.TempDir(), provider)
|
||||||
|
require.ErrorIs(t, err, genesis.ErrGenesisStateNotInitialized)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty_dir_path_with_providers", func(t *testing.T) {
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MainnetConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-empty-dir"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Use a deterministic test state
|
||||||
|
testState := createTestGenesisState(t, 16, 0)
|
||||||
|
|
||||||
|
// Create successful provider
|
||||||
|
provider := &mockProvider{
|
||||||
|
state: testState,
|
||||||
|
name: "test-provider",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with empty dir should fail
|
||||||
|
err := genesis.Initialize(t.Context(), "", provider)
|
||||||
|
require.ErrorIs(t, err, genesis.ErrFilePathUnset)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("genesis_file_takes_precedence_over_providers", func(t *testing.T) {
|
||||||
|
// Create temp directory with genesis file
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
// Use a custom config that won't have embedded data
|
||||||
|
customConfig := params.MainnetConfig().Copy()
|
||||||
|
customConfig.ConfigName = "test-config-file-precedence"
|
||||||
|
params.OverrideBeaconConfig(customConfig)
|
||||||
|
|
||||||
|
// Create deterministic test states for file and provider
|
||||||
|
fileState := createTestGenesisState(t, 128, 75)
|
||||||
|
fileTime := time.Unix(1234567890, 0)
|
||||||
|
require.NoError(t, fileState.SetGenesisTime(fileTime))
|
||||||
|
|
||||||
|
// Save state to file with proper naming convention
|
||||||
|
marshaled, err := fileState.MarshalSSZ()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
gvr := fileState.GenesisValidatorsRoot()
|
||||||
|
gvrHex := hexutil.Encode(gvr)
|
||||||
|
filename := filepath.Join(tmpDir, "genesis-1234567890-"+gvrHex+".ssz")
|
||||||
|
err = os.WriteFile(filename, marshaled, 0644)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Create a provider with different state
|
||||||
|
providerState := createTestGenesisState(t, 256, 200)
|
||||||
|
provider := &mockProvider{
|
||||||
|
state: providerState,
|
||||||
|
name: "test-provider",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize should use file, not provider
|
||||||
|
err = genesis.Initialize(t.Context(), tmpDir, provider)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Verify file state was used, not provider state
|
||||||
|
storedState, err := genesis.State()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, storedState)
|
||||||
|
// fileState has slot 75 and 128 validators, providerState has slot 200 and 256 validators
|
||||||
|
require.Equal(t, primitives.Slot(75), storedState.Slot())
|
||||||
|
require.Equal(t, 128, storedState.NumValidators())
|
||||||
|
require.Equal(t, fileTime, storedState.GenesisTime())
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -3,14 +3,13 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"genesis.go",
|
"lookup.go",
|
||||||
"genesis_mainnet.go",
|
"mainnet.go",
|
||||||
],
|
],
|
||||||
embedsrcs = ["mainnet.ssz.snappy"],
|
embedsrcs = ["mainnet.ssz.snappy"],
|
||||||
importpath = "github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis",
|
importpath = "github.com/OffchainLabs/prysm/v6/genesis/internal/embedded",
|
||||||
visibility = [
|
visibility = [
|
||||||
"//beacon-chain/db:__subpackages__",
|
"//genesis:__pkg__",
|
||||||
"//config/params:__pkg__",
|
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
@@ -23,7 +22,7 @@ go_library(
|
|||||||
|
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = ["genesis_test.go"],
|
srcs = ["lookup_test.go"],
|
||||||
deps = [
|
deps = [
|
||||||
":go_default_library",
|
":go_default_library",
|
||||||
"//config/params:go_default_library",
|
"//config/params:go_default_library",
|
||||||
65
genesis/internal/embedded/lookup.go
Normal file
65
genesis/internal/embedded/lookup.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package embedded
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
state_native "github.com/OffchainLabs/prysm/v6/beacon-chain/state/state-native"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
ethpb "github.com/OffchainLabs/prysm/v6/proto/prysm/v1alpha1"
|
||||||
|
"github.com/golang/snappy"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("embedded genesis state not found")
|
||||||
|
|
||||||
|
var embeddedStates = map[string]*[]byte{}
|
||||||
|
|
||||||
|
// ByName returns a copy of the genesis state from a hardcoded value.
|
||||||
|
func ByName(name string) (state.BeaconState, error) {
|
||||||
|
sb, exists := embeddedStates[name]
|
||||||
|
if exists {
|
||||||
|
return load(*sb)
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func BytesByName(name string) ([]byte, error) {
|
||||||
|
sb, exists := embeddedStates[name]
|
||||||
|
if exists {
|
||||||
|
return *sb, nil
|
||||||
|
}
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
func Has(name string) bool {
|
||||||
|
_, exists := embeddedStates[name]
|
||||||
|
return exists
|
||||||
|
}
|
||||||
|
|
||||||
|
// load a compressed ssz state file into a beacon state struct.
|
||||||
|
func load(b []byte) (state.BeaconState, error) {
|
||||||
|
st := ðpb.BeaconState{}
|
||||||
|
b, err := snappy.Decode(nil /*dst*/, b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := st.UnmarshalSSZ(b); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return state_native.InitializeFromProtoUnsafePhase0(st)
|
||||||
|
}
|
||||||
|
|
||||||
|
type embeddedProvider struct{}
|
||||||
|
|
||||||
|
func (p embeddedProvider) Genesis(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
// Use the mainnet genesis state as default
|
||||||
|
st, err := ByName(params.BeaconConfig().ConfigName)
|
||||||
|
if err == nil && st == nil {
|
||||||
|
return nil, ErrNotFound
|
||||||
|
}
|
||||||
|
return st, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var EmbeddedProvider = &embeddedProvider{}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package genesis_test
|
package embedded_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state/genesis"
|
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/genesis/internal/embedded"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGenesisState(t *testing.T) {
|
func TestGenesisState(t *testing.T) {
|
||||||
@@ -17,7 +17,7 @@ func TestGenesisState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
st, err := genesis.State(tt.name)
|
st, err := embedded.ByName(tt.name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
//go:build !noMainnetGenesis
|
//go:build !noMainnetGenesis
|
||||||
// +build !noMainnetGenesis
|
// +build !noMainnetGenesis
|
||||||
|
|
||||||
package genesis
|
package embedded
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
77
genesis/providers.go
Normal file
77
genesis/providers.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/api/client"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/api/client/beacon"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Provider is a type that can provide the genesis state for the initialization of the genesis package.
|
||||||
|
// Examples are getting the state from a beacon node API, reading it from a file, or from the legacy database.
|
||||||
|
type Provider interface {
|
||||||
|
Genesis(context.Context) (state.BeaconState, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ Provider = &FileProvider{}
|
||||||
|
var _ Provider = &APIProvider{}
|
||||||
|
|
||||||
|
// APIProvider provides a genesis state using the given beacon node API url.
|
||||||
|
type APIProvider struct {
|
||||||
|
c *beacon.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIProvider creates an APIProvider, handling the set up of a beacon node api client.
|
||||||
|
func NewAPIProvider(beaconNodeHost string) (*APIProvider, error) {
|
||||||
|
c, err := beacon.NewClient(beaconNodeHost, client.WithMaxBodySize(client.MaxBodySizeState))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "unable to parse beacon node url or hostname - %s", beaconNodeHost)
|
||||||
|
}
|
||||||
|
return &APIProvider{c: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Genesis satisfies the Provider interface by retrieving the genesis state from the beacon node API and unmarshaling it into a phase0 beacon state.
|
||||||
|
func (dl *APIProvider) Genesis(ctx context.Context) (state.BeaconState, error) {
|
||||||
|
sb, err := dl.c.GetState(ctx, beacon.IdGenesis)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return detect.UnmarshalState(sb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileProvider provides the genesis state by reading the given ssz-encoded beacon state file path.
|
||||||
|
type FileProvider struct {
|
||||||
|
statePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileProvider validates the given path information and creates a Provider which sources
|
||||||
|
// the genesis state from an ssz-encoded file on the local filesystem.
|
||||||
|
func NewFileProvider(statePath string) (*FileProvider, error) {
|
||||||
|
var err error
|
||||||
|
if err = existsAndIsFile(statePath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// stat just to make sure it actually exists and is a file
|
||||||
|
return &FileProvider{statePath: statePath}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Genesis satisfies the Provider interface by reading the genesis state from a file and unmarshaling it.
|
||||||
|
func (fi *FileProvider) Genesis(_ context.Context) (state.BeaconState, error) {
|
||||||
|
return stateFromFile(fi.statePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func existsAndIsFile(path string) error {
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error checking existence of ssz-encoded file %s for genesis state init", path)
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return fmt.Errorf("%s is a directory, please specify full path to file", path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
178
genesis/storage.go
Normal file
178
genesis/storage.go
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/encoding/ssz/detect"
|
||||||
|
"github.com/OffchainLabs/prysm/v6/io/file"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidatorsRoot returns the genesis validators root.
|
||||||
|
func ValidatorsRoot() [32]byte {
|
||||||
|
return data.ValidatorsRoot
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time returns the genesis time.
|
||||||
|
func Time() time.Time {
|
||||||
|
return data.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// State returns the full genesis BeaconState. It can return an error because this value is lazy loaded.
|
||||||
|
// The returned value will always be a copy of the underlying value.
|
||||||
|
func State() (state.BeaconState, error) {
|
||||||
|
st, err := stateInternal()
|
||||||
|
if state.IsNil(st) || err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return st.Copy(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateInternal() (state.BeaconState, error) {
|
||||||
|
gd := getPkgVar()
|
||||||
|
if !gd.initialized {
|
||||||
|
// If the state is not explicitly initialized, try to load embedded states if available.
|
||||||
|
name := params.BeaconConfig().ConfigName
|
||||||
|
if ed, ok := embeddedGenesisData[name]; ok {
|
||||||
|
return ed.embeddedState()
|
||||||
|
}
|
||||||
|
return nil, ErrGenesisStateNotInitialized
|
||||||
|
}
|
||||||
|
if !state.IsNil(gd.State) {
|
||||||
|
return gd.State, nil
|
||||||
|
}
|
||||||
|
if gd.embeddedState != nil {
|
||||||
|
st, err := gd.embeddedState()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "load embedded genesis state")
|
||||||
|
}
|
||||||
|
if !state.IsNil(st) {
|
||||||
|
gd.State = st
|
||||||
|
return gd.State, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loadState()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store is an exported method that allows another package to set the genesis data value and persist it to disk.
|
||||||
|
// It is exported to be used by implementations of the Provider interface.
|
||||||
|
func Store(d GenesisData) error {
|
||||||
|
if err := ensureWritable(d.FileDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := persist(d); err != nil {
|
||||||
|
return errors.Wrap(err, "persist genesis data")
|
||||||
|
}
|
||||||
|
setPkgVar(d, true)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fnamePart int
|
||||||
|
|
||||||
|
const (
|
||||||
|
genesisPart fnamePart = 0
|
||||||
|
timePart fnamePart = 1
|
||||||
|
gvrPart fnamePart = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
// data is a private package level variable that holds the genesis data.
|
||||||
|
// Other packages interact with it via wrapper functions like Set() and State().
|
||||||
|
var data GenesisData
|
||||||
|
var stateMu sync.Mutex
|
||||||
|
|
||||||
|
// GenesisData bundles all the package level data. It is exported to allow implementations of the Provider interface to set genesis data.
|
||||||
|
type GenesisData struct {
|
||||||
|
ValidatorsRoot [32]byte
|
||||||
|
Time time.Time
|
||||||
|
FileDir string
|
||||||
|
State state.BeaconState
|
||||||
|
embeddedBytes func() ([]byte, error)
|
||||||
|
embeddedState func() (state.BeaconState, error)
|
||||||
|
initialized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d GenesisData) filePath() string {
|
||||||
|
parts := [3]string{}
|
||||||
|
parts[genesisPart] = "genesis"
|
||||||
|
parts[timePart] = strconv.FormatInt(d.Time.Unix(), 10)
|
||||||
|
parts[gvrPart] = hexutil.Encode(d.ValidatorsRoot[:])
|
||||||
|
return path.Join(d.FileDir, strings.Join(parts[:], "-")+".ssz")
|
||||||
|
}
|
||||||
|
|
||||||
|
func persist(d GenesisData) error {
|
||||||
|
if state.IsNil(d.State) {
|
||||||
|
return ErrGenesisStateNotInitialized
|
||||||
|
}
|
||||||
|
if d.FileDir == "" {
|
||||||
|
return ErrFilePathUnset
|
||||||
|
}
|
||||||
|
fpath := d.filePath()
|
||||||
|
sb, err := d.State.MarshalSSZ()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "marshal ssz")
|
||||||
|
}
|
||||||
|
if err := file.WriteFile(fpath, sb); err != nil {
|
||||||
|
return fmt.Errorf("error writing genesis state to %s: %w", fpath, err)
|
||||||
|
}
|
||||||
|
log.WithField("filePath", fpath).Info("Genesis state written to disk.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPkgVar() GenesisData {
|
||||||
|
stateMu.Lock()
|
||||||
|
defer stateMu.Unlock()
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPkgVar(d GenesisData, initialized bool) {
|
||||||
|
stateMu.Lock()
|
||||||
|
defer stateMu.Unlock()
|
||||||
|
d.initialized = initialized
|
||||||
|
data = d
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadState() (state.BeaconState, error) {
|
||||||
|
stateMu.Lock()
|
||||||
|
defer stateMu.Unlock()
|
||||||
|
|
||||||
|
s, err := stateFromFile(data.filePath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "InitializeFromProtoUnsafePhase0")
|
||||||
|
}
|
||||||
|
|
||||||
|
data.State = s
|
||||||
|
return data.State, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stateFromFile(fpath string) (state.BeaconState, error) {
|
||||||
|
sb, err := file.ReadFileAsBytes(fpath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error reading genesis state from %s", fpath)
|
||||||
|
}
|
||||||
|
return detect.UnmarshalState(sb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureWritable(dir string) (err error) {
|
||||||
|
if dir == "" {
|
||||||
|
return ErrFilePathUnset
|
||||||
|
}
|
||||||
|
if err := file.MkdirAll(dir); err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating genesis data directory %s", dir)
|
||||||
|
}
|
||||||
|
lockPath := path.Join(dir, "genesis.lock")
|
||||||
|
defer func() {
|
||||||
|
if err == nil {
|
||||||
|
err = os.Remove(lockPath)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return os.WriteFile(lockPath, []byte{1}, 0600)
|
||||||
|
}
|
||||||
38
genesis/testing.go
Normal file
38
genesis/testing.go
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package genesis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StoreDuringTest temporarily replaces the package level GenesisData with the provided GenesisData
|
||||||
|
func StoreDuringTest(t *testing.T, gd GenesisData) {
|
||||||
|
prev := getPkgVar()
|
||||||
|
t.Cleanup(func() {
|
||||||
|
setPkgVar(prev, prev.initialized)
|
||||||
|
})
|
||||||
|
setPkgVar(gd, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreEmbeddedDuringTest sets the named embedded genesis file as the genesis data for the lifecycle of the current test.
|
||||||
|
func StoreEmbeddedDuringTest(t *testing.T, name string) {
|
||||||
|
gd, ok := embeddedGenesisData[name]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("embedded genesis data for %s not found", name)
|
||||||
|
}
|
||||||
|
StoreDuringTest(t, gd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreStateDuringTest creates and stores genesis data from a beacon state for the duration of a test.
|
||||||
|
// This is essential for testing components that depend on genesis information being globally available,
|
||||||
|
// The function automatically cleans up after the test completes, restoring the previous
|
||||||
|
// genesis state to prevent test interference. Without this setup, many blockchain
|
||||||
|
// components would fail during testing due to uninitialized genesis data.
|
||||||
|
func StoreStateDuringTest(t *testing.T, st state.BeaconState) {
|
||||||
|
gd, err := newGenesisData(st, "testdata")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create genesis data: %v", err)
|
||||||
|
}
|
||||||
|
StoreDuringTest(t, gd)
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ go_library(
|
|||||||
"//beacon-chain/state:go_default_library",
|
"//beacon-chain/state:go_default_library",
|
||||||
"//cmd:go_default_library",
|
"//cmd:go_default_library",
|
||||||
"//cmd/beacon-chain/flags:go_default_library",
|
"//cmd/beacon-chain/flags:go_default_library",
|
||||||
"//cmd/beacon-chain/sync/genesis:go_default_library",
|
"//cmd/beacon-chain/genesis:go_default_library",
|
||||||
"//cmd/validator/flags:go_default_library",
|
"//cmd/validator/flags:go_default_library",
|
||||||
"//config/features:go_default_library",
|
"//config/features:go_default_library",
|
||||||
"//config/fieldparams:go_default_library",
|
"//config/fieldparams:go_default_library",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
"github.com/OffchainLabs/prysm/v6/beacon-chain/state"
|
||||||
cmdshared "github.com/OffchainLabs/prysm/v6/cmd"
|
cmdshared "github.com/OffchainLabs/prysm/v6/cmd"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/flags"
|
||||||
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/sync/genesis"
|
"github.com/OffchainLabs/prysm/v6/cmd/beacon-chain/genesis"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/features"
|
"github.com/OffchainLabs/prysm/v6/config/features"
|
||||||
"github.com/OffchainLabs/prysm/v6/config/params"
|
"github.com/OffchainLabs/prysm/v6/config/params"
|
||||||
"github.com/OffchainLabs/prysm/v6/io/file"
|
"github.com/OffchainLabs/prysm/v6/io/file"
|
||||||
|
|||||||
Reference in New Issue
Block a user