mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Embedded mainnet genesis state + load genesis.ssz from file (#8614)
* Update rules_go and fix proto conflicts * gaz * Update generated code * First pass inclusion of using baked states * more emptypb fixes * remove testnet genesis files, only embed mainnet * Refactoring for SaveGenesisData, fix tests that use mainnet config but do not support mainnet genesis values * a bit more refactoring, load genesis from a file. Needs tests still * Add method to ensure an embedded genesis file also has the appropriate genesis block * gofmt * more clear error * Check genesis fork version to ensure testnet config matches genesis file * viz * test for SaveGenesisData * More genesis db method tests * Merge * Minor tweaks, lint, fmt, etc * Add more test to genesis db methods * Revert beacon-chain/state/stateV0/BUILD.bazel * Update beacon-chain/db/iface/errors.go Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * PR feedback * Update beacon-chain/db/kv/genesis.go Co-authored-by: terence tsao <terence@prysmaticlabs.com> * fmt.Errorf works better for nil errors Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: terence tsao <terence@prysmaticlabs.com>
This commit is contained in:
parent
a921455836
commit
e477fdfd6d
@ -27,7 +27,6 @@ go_library(
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/epoch/precompute:go_default_library",
|
||||
"//beacon-chain/core/feed:go_default_library",
|
||||
"//beacon-chain/core/feed/state:go_default_library",
|
||||
@ -84,6 +83,7 @@ go_test(
|
||||
"checktags_test.go",
|
||||
"head_test.go",
|
||||
"info_test.go",
|
||||
"init_test.go",
|
||||
"metrics_test.go",
|
||||
"process_attestation_test.go",
|
||||
"process_block_test.go",
|
||||
@ -130,6 +130,7 @@ go_test(
|
||||
srcs = [
|
||||
"chain_info_norace_test.go",
|
||||
"checktags_test.go",
|
||||
"init_test.go",
|
||||
"receive_block_test.go",
|
||||
"service_norace_test.go",
|
||||
],
|
||||
|
12
beacon-chain/blockchain/init_test.go
Normal file
12
beacon-chain/blockchain/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package blockchain
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
@ -15,7 +15,6 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
|
||||
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
@ -32,7 +31,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
|
||||
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
@ -336,38 +334,20 @@ func (s *Service) Status() error {
|
||||
|
||||
// This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db.
|
||||
func (s *Service) saveGenesisData(ctx context.Context, genesisState iface.BeaconState) error {
|
||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := s.cfg.BeaconDB.SaveGenesisData(ctx, genesisState); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis data")
|
||||
}
|
||||
genesisBlk, err := s.cfg.BeaconDB.GenesisBlock(ctx)
|
||||
if err != nil || genesisBlk == nil {
|
||||
return fmt.Errorf("could not load genesis block: %v", err)
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
|
||||
s.genesisRoot = genesisBlkRoot
|
||||
|
||||
if err := s.cfg.BeaconDB.SaveBlock(ctx, genesisBlk); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block")
|
||||
}
|
||||
if err := s.cfg.BeaconDB.SaveState(ctx, genesisState, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis state")
|
||||
}
|
||||
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{
|
||||
Slot: 0,
|
||||
Root: genesisBlkRoot[:],
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.cfg.StateGen.SaveFinalizedState(0, genesisBlkRoot, genesisState)
|
||||
|
||||
if err := s.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save head block root")
|
||||
}
|
||||
if err := s.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block root")
|
||||
}
|
||||
s.cfg.StateGen.SaveFinalizedState(0 /*slot*/, genesisBlkRoot, genesisState)
|
||||
|
||||
// Finalized checkpoint at genesis is a zero hash.
|
||||
genesisCheckpoint := genesisState.FinalizedCheckpoint()
|
||||
@ -392,7 +372,6 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState iface.Beacon
|
||||
}
|
||||
|
||||
s.setHead(genesisBlkRoot, genesisBlk, genesisState)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -22,3 +22,7 @@ type HeadAccessDatabase = iface.HeadAccessDatabase
|
||||
// key-value or relational database in practice. This is the full database interface which should
|
||||
// not be used often. Prefer a more restrictive interface in this package.
|
||||
type Database = iface.Database
|
||||
|
||||
// ErrExistingGenesisState is an error when the user attempts to save a different genesis state
|
||||
// when one already exists in a database.
|
||||
var ErrExistingGenesisState = iface.ErrExistingGenesisState
|
||||
|
@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["interface.go"],
|
||||
srcs = [
|
||||
"errors.go",
|
||||
"interface.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/db/iface",
|
||||
# Other packages must use github.com/prysmaticlabs/prysm/beacon-chain/db.Database alias.
|
||||
visibility = ["//beacon-chain/db:__subpackages__"],
|
||||
|
11
beacon-chain/db/iface/errors.go
Normal file
11
beacon-chain/db/iface/errors.go
Normal file
@ -0,0 +1,11 @@
|
||||
package iface
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrExistingGenesisState is an error when the user attempts to save a different genesis state
|
||||
// when one already exists in a database.
|
||||
ErrExistingGenesisState = errors.New("genesis state exists already in the DB")
|
||||
)
|
@ -99,6 +99,11 @@ type HeadAccessDatabase interface {
|
||||
// Block related methods.
|
||||
HeadBlock(ctx context.Context) (*eth.SignedBeaconBlock, error)
|
||||
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
|
||||
|
||||
// Genesis operations.
|
||||
LoadGenesis(ctx context.Context, r io.Reader) error
|
||||
SaveGenesisData(ctx context.Context, state iface.BeaconState) error
|
||||
EnsureEmbeddedGenesis(ctx context.Context) error
|
||||
}
|
||||
|
||||
// Database interface with full access.
|
||||
|
@ -2,6 +2,7 @@ package kafka
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
@ -266,3 +267,18 @@ func (e Exporter) RunMigrations(ctx context.Context) error {
|
||||
func (e Exporter) CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint types.Slot) error {
|
||||
return e.db.RunMigrations(ctx)
|
||||
}
|
||||
|
||||
// LoadGenesisFromFile -- passthrough
|
||||
func (e Exporter) LoadGenesis(ctx context.Context, r io.Reader) error {
|
||||
return e.db.LoadGenesis(ctx, r)
|
||||
}
|
||||
|
||||
// SaveGenesisData -- passthrough
|
||||
func (e Exporter) SaveGenesisData(ctx context.Context, state iface.BeaconState) error {
|
||||
return e.db.SaveGenesisData(ctx, state)
|
||||
}
|
||||
|
||||
// EnsureEmbeddedGenesis -- passthrough.
|
||||
func (e Exporter) EnsureEmbeddedGenesis(ctx context.Context) error {
|
||||
return e.db.EnsureEmbeddedGenesis(ctx)
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ go_library(
|
||||
"deposit_contract.go",
|
||||
"encoding.go",
|
||||
"finalized_block_roots.go",
|
||||
"genesis.go",
|
||||
"kv.go",
|
||||
"log.go",
|
||||
"migration.go",
|
||||
@ -32,9 +33,11 @@ go_library(
|
||||
"//tools:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/db/iface:go_default_library",
|
||||
"//beacon-chain/state/genesis:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//beacon-chain/state/stateV0:go_default_library",
|
||||
"//proto/beacon/db:go_default_library",
|
||||
@ -70,6 +73,8 @@ go_test(
|
||||
"deposit_contract_test.go",
|
||||
"encoding_test.go",
|
||||
"finalized_block_roots_test.go",
|
||||
"genesis_test.go",
|
||||
"init_test.go",
|
||||
"kv_test.go",
|
||||
"migration_archived_index_test.go",
|
||||
"migration_block_slot_index_test.go",
|
||||
@ -80,9 +85,11 @@ go_test(
|
||||
"state_test.go",
|
||||
"utils_test.go",
|
||||
],
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/db/filters:go_default_library",
|
||||
"//beacon-chain/db/iface:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
"//proto/beacon/db:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
@ -97,6 +104,7 @@ go_test(
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
"@io_etcd_go_bbolt//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
115
beacon-chain/db/kv/genesis.go
Normal file
115
beacon-chain/db/kv/genesis.go
Normal file
@ -0,0 +1,115 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
dbIface "github.com/prysmaticlabs/prysm/beacon-chain/db/iface"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
state "github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// SaveGenesisData bootstraps the beaconDB with a given genesis state.
|
||||
func (s *Store) SaveGenesisData(ctx context.Context, genesisState iface.BeaconState) error {
|
||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
if err := s.SaveBlock(ctx, genesisBlk); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block")
|
||||
}
|
||||
if err := s.SaveState(ctx, genesisState, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis state")
|
||||
}
|
||||
if err := s.SaveStateSummary(ctx, &pbp2p.StateSummary{
|
||||
Slot: 0,
|
||||
Root: genesisBlkRoot[:],
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.SaveHeadBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save head block root")
|
||||
}
|
||||
if err := s.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block root")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadGenesisFromFile loads a genesis state from a given file path, if no genesis exists already.
|
||||
func (s *Store) LoadGenesis(ctx context.Context, r io.Reader) error {
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st := &pbp2p.BeaconState{}
|
||||
if err := st.UnmarshalSSZ(b); err != nil {
|
||||
return err
|
||||
}
|
||||
gs, err := state.InitializeFromProtoUnsafe(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existing, err := s.GenesisState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If some different genesis state existed already, return an error. The same genesis state is
|
||||
// considered a no-op.
|
||||
if existing != nil {
|
||||
a, err := existing.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := gs.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if a == b {
|
||||
return nil
|
||||
}
|
||||
return dbIface.ErrExistingGenesisState
|
||||
}
|
||||
|
||||
if !bytes.Equal(gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion) {
|
||||
return fmt.Errorf("loaded genesis fork version (%#x) does not match config genesis "+
|
||||
"fork version (%#x)", gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion)
|
||||
}
|
||||
|
||||
return s.SaveGenesisData(ctx, gs)
|
||||
}
|
||||
|
||||
// EnsureEmbeddedGenesis checks that a genesis block has been generated when an embedded genesis
|
||||
// state is used. If a genesis block does not exist, but a genesis state does, then we should call
|
||||
// SaveGenesisData on the existing genesis state.
|
||||
func (s *Store) EnsureEmbeddedGenesis(ctx context.Context) error {
|
||||
gb, err := s.GenesisBlock(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if gb != nil {
|
||||
return nil
|
||||
}
|
||||
gs, err := s.GenesisState(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if gs != nil {
|
||||
return s.SaveGenesisData(ctx, gs)
|
||||
}
|
||||
return nil
|
||||
}
|
117
beacon-chain/db/kv/genesis_test.go
Normal file
117
beacon-chain/db/kv/genesis_test.go
Normal file
@ -0,0 +1,117 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db/iface"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
||||
)
|
||||
|
||||
func TestStore_SaveGenesisData(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
|
||||
gs, err := testutil.NewBeaconState()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.NoError(t, db.SaveGenesisData(ctx, gs))
|
||||
|
||||
testGenesisDataSaved(t, db)
|
||||
}
|
||||
|
||||
func testGenesisDataSaved(t *testing.T, db iface.Database) {
|
||||
ctx := context.Background()
|
||||
|
||||
gb, err := db.GenesisBlock(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gb)
|
||||
|
||||
gbHTR, err := gb.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
|
||||
gss, err := db.StateSummary(ctx, gbHTR)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gss)
|
||||
|
||||
head, err := db.HeadBlock(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, head)
|
||||
|
||||
headHTR, err := head.Block.HashTreeRoot()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, gbHTR, headHTR, "head block does not match genesis block")
|
||||
}
|
||||
|
||||
func TestLoadGenesisFromFile(t *testing.T) {
|
||||
fp := "testdata/mainnet.genesis.ssz"
|
||||
rfp, err := bazel.Runfile(fp)
|
||||
if err == nil {
|
||||
fp = rfp
|
||||
}
|
||||
|
||||
r, err := os.Open(fp)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, r.Close())
|
||||
}()
|
||||
|
||||
db := setupDB(t)
|
||||
assert.NoError(t, db.LoadGenesis(context.Background(), r))
|
||||
testGenesisDataSaved(t, db)
|
||||
|
||||
// Loading the same genesis again should not throw an error
|
||||
_, err = r.Seek(0, 0)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, db.LoadGenesis(context.Background(), r))
|
||||
}
|
||||
|
||||
func TestLoadGenesisFromFile_mismatchedForkVersion(t *testing.T) {
|
||||
fp := "testdata/altona.genesis.ssz"
|
||||
rfp, err := bazel.Runfile(fp)
|
||||
if err == nil {
|
||||
fp = rfp
|
||||
}
|
||||
r, err := os.Open(fp)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, r.Close())
|
||||
}()
|
||||
|
||||
// Loading a genesis with the wrong fork version as beacon config should throw an error.
|
||||
db := setupDB(t)
|
||||
assert.ErrorContains(t, "does not match config genesis fork version", db.LoadGenesis(context.Background(), r))
|
||||
}
|
||||
|
||||
func TestEnsureEmbeddedGenesis(t *testing.T) {
|
||||
// Embedded Genesis works with Mainnet config
|
||||
params.SetupTestConfigCleanup(t)
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = params.ConfigNames[params.Mainnet]
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
|
||||
gb, err := db.GenesisBlock(ctx)
|
||||
assert.NoError(t, err)
|
||||
if gb != nil {
|
||||
t.Fatal("Genesis block exists already")
|
||||
}
|
||||
|
||||
gs, err := db.GenesisState(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gs, "an embedded genesis state does not exist")
|
||||
|
||||
assert.NoError(t, db.EnsureEmbeddedGenesis(ctx))
|
||||
|
||||
gb, err = db.GenesisBlock(ctx)
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, gb)
|
||||
|
||||
testGenesisDataSaved(t, db)
|
||||
}
|
12
beacon-chain/db/kv/init_test.go
Normal file
12
beacon-chain/db/kv/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package kv
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
@ -8,10 +8,13 @@ import (
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/traceutil"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@ -42,8 +45,19 @@ func (s *Store) State(ctx context.Context, blockRoot [32]byte) (iface.BeaconStat
|
||||
func (s *Store) GenesisState(ctx context.Context) (iface.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.GenesisState")
|
||||
defer span.End()
|
||||
|
||||
cached, err := genesis.State(params.BeaconConfig().ConfigName)
|
||||
if err != nil {
|
||||
traceutil.AnnotateError(span, err)
|
||||
return nil, err
|
||||
}
|
||||
span.AddAttributes(trace.BoolAttribute("cache_hit", cached != nil))
|
||||
if cached != nil {
|
||||
return cached, nil
|
||||
}
|
||||
|
||||
var st *pb.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,
|
||||
// to look up what the genesis state is.
|
||||
bucket := tx.Bucket(blocksBucket)
|
||||
|
BIN
beacon-chain/db/kv/testdata/altona.genesis.ssz
vendored
Normal file
BIN
beacon-chain/db/kv/testdata/altona.genesis.ssz
vendored
Normal file
Binary file not shown.
BIN
beacon-chain/db/kv/testdata/mainnet.genesis.ssz
vendored
Normal file
BIN
beacon-chain/db/kv/testdata/mainnet.genesis.ssz
vendored
Normal file
Binary file not shown.
@ -10,7 +10,6 @@ go_library(
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/cache/depositcache:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/powchain:go_default_library",
|
||||
"//beacon-chain/state/interface:go_default_library",
|
||||
@ -19,7 +18,6 @@ go_library(
|
||||
"//shared:go_default_library",
|
||||
"//shared/interop:go_default_library",
|
||||
"//shared/slotutil:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
|
||||
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
@ -9,11 +9,9 @@ import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
|
||||
@ -172,42 +170,11 @@ func (s *Service) NonFinalizedDeposits(_ context.Context, _ *big.Int) []*ethpb.D
|
||||
}
|
||||
|
||||
func (s *Service) saveGenesisState(ctx context.Context, genesisState iface.BeaconState) error {
|
||||
s.chainStartDeposits = make([]*ethpb.Deposit, genesisState.NumValidators())
|
||||
stateRoot, err := genesisState.HashTreeRoot(ctx)
|
||||
if err != nil {
|
||||
if err := s.beaconDB.SaveGenesisData(ctx, genesisState); err != nil {
|
||||
return err
|
||||
}
|
||||
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get genesis block root")
|
||||
}
|
||||
|
||||
if err := s.beaconDB.SaveBlock(ctx, genesisBlk); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block")
|
||||
}
|
||||
if err := s.beaconDB.SaveStateSummary(ctx, &pb.StateSummary{
|
||||
Slot: 0,
|
||||
Root: genesisBlkRoot[:],
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.beaconDB.SaveState(ctx, genesisState, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis state")
|
||||
}
|
||||
if err := s.beaconDB.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save genesis block root")
|
||||
}
|
||||
if err := s.beaconDB.SaveHeadBlockRoot(ctx, genesisBlkRoot); err != nil {
|
||||
return errors.Wrap(err, "could not save head block root")
|
||||
}
|
||||
genesisCheckpoint := ðpb.Checkpoint{Root: genesisBlkRoot[:]}
|
||||
if err := s.beaconDB.SaveJustifiedCheckpoint(ctx, genesisCheckpoint); err != nil {
|
||||
return errors.Wrap(err, "could not save justified checkpoint")
|
||||
}
|
||||
if err := s.beaconDB.SaveFinalizedCheckpoint(ctx, genesisCheckpoint); err != nil {
|
||||
return errors.Wrap(err, "could not save finalized checkpoint")
|
||||
}
|
||||
s.chainStartDeposits = make([]*ethpb.Deposit, genesisState.NumValidators())
|
||||
|
||||
for i := types.ValidatorIndex(0); uint64(i) < uint64(genesisState.NumValidators()); i++ {
|
||||
pk := genesisState.PubkeyAtIndex(i)
|
||||
|
@ -343,6 +343,31 @@ func (b *BeaconNode) startDB(cliCtx *cli.Context) error {
|
||||
}
|
||||
|
||||
b.depositCache = depositCache
|
||||
|
||||
if cliCtx.IsSet(flags.GenesisStatePath.Name) {
|
||||
r, err := os.Open(cliCtx.String(flags.GenesisStatePath.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := r.Close(); err != nil {
|
||||
log.WithError(err).Error("Failed to close genesis file")
|
||||
}
|
||||
}()
|
||||
if err := b.db.LoadGenesis(b.ctx, r); err != nil {
|
||||
if err == db.ErrExistingGenesisState {
|
||||
return errors.New("Genesis state flag specified but a genesis state " +
|
||||
"exists already. Run again with --clear-db and/or ensure you are using the " +
|
||||
"appropriate testnet flag to load the given genesis state.")
|
||||
}
|
||||
return errors.Wrap(err, "could not load genesis from file")
|
||||
}
|
||||
}
|
||||
|
||||
if err := b.db.EnsureEmbeddedGenesis(b.ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -61,6 +61,7 @@ go_test(
|
||||
"block_cache_test.go",
|
||||
"block_reader_test.go",
|
||||
"deposit_test.go",
|
||||
"init_test.go",
|
||||
"log_processing_test.go",
|
||||
"powchain_test.go",
|
||||
"service_test.go",
|
||||
|
12
beacon-chain/powchain/init_test.go
Normal file
12
beacon-chain/powchain/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package powchain
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
@ -70,6 +70,7 @@ go_test(
|
||||
"blocks_test.go",
|
||||
"committees_test.go",
|
||||
"config_test.go",
|
||||
"init_test.go",
|
||||
"slashings_test.go",
|
||||
"validators_stream_test.go",
|
||||
"validators_test.go",
|
||||
|
12
beacon-chain/rpc/beacon/init_test.go
Normal file
12
beacon-chain/rpc/beacon/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package beacon
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
@ -56,6 +56,7 @@ go_test(
|
||||
srcs = [
|
||||
"blocks_test.go",
|
||||
"config_test.go",
|
||||
"init_test.go",
|
||||
"pool_test.go",
|
||||
"server_test.go",
|
||||
"state_test.go",
|
||||
|
12
beacon-chain/rpc/beaconv1/init_test.go
Normal file
12
beacon-chain/rpc/beaconv1/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package beaconv1
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
25
beacon-chain/state/genesis/BUILD.bazel
Normal file
25
beacon-chain/state/genesis/BUILD.bazel
Normal file
@ -0,0 +1,25 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_test")
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["genesis.go"],
|
||||
embedsrcs = ["mainnet.ssz.snappy"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/state/genesis",
|
||||
visibility = ["//beacon-chain/db:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/state/stateV0:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_golang_snappy//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["genesis_test.go"],
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
39
beacon-chain/state/genesis/genesis.go
Normal file
39
beacon-chain/state/genesis/genesis.go
Normal file
@ -0,0 +1,39 @@
|
||||
package genesis
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
state "github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed mainnet.ssz.snappy
|
||||
mainnetRawSSZCompressed []byte // 1.8Mb
|
||||
)
|
||||
|
||||
// State returns a copy of the genesis state from a hardcoded value.
|
||||
func State(name string) (*state.BeaconState, error) {
|
||||
switch name {
|
||||
case params.ConfigNames[params.Mainnet]:
|
||||
return load(mainnetRawSSZCompressed)
|
||||
default:
|
||||
// No state found.
|
||||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
// load a compressed ssz state file into a beacon state struct.
|
||||
func load(b []byte) (*state.BeaconState, error) {
|
||||
st := &pbp2p.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.InitializeFromProtoUnsafe(st)
|
||||
}
|
32
beacon-chain/state/genesis/genesis_test.go
Normal file
32
beacon-chain/state/genesis/genesis_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package genesis_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/genesis"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestGenesisState(t *testing.T) {
|
||||
tests := []struct {
|
||||
name params.ConfigName
|
||||
}{
|
||||
{
|
||||
name: params.Mainnet,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(params.ConfigNames[tt.name], func(t *testing.T) {
|
||||
st, err := genesis.State(params.ConfigNames[tt.name])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if st == nil {
|
||||
t.Fatal("nil state")
|
||||
}
|
||||
if st.NumValidators() <= 0 {
|
||||
t.Error("No validators present in state")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
BIN
beacon-chain/state/genesis/mainnet.ssz.snappy
Normal file
BIN
beacon-chain/state/genesis/mainnet.ssz.snappy
Normal file
Binary file not shown.
@ -48,6 +48,7 @@ go_test(
|
||||
"epoch_boundary_state_cache_test.go",
|
||||
"getter_test.go",
|
||||
"hot_state_cache_test.go",
|
||||
"init_test.go",
|
||||
"migrate_test.go",
|
||||
"replay_test.go",
|
||||
"service_test.go",
|
||||
|
12
beacon-chain/state/stategen/init_test.go
Normal file
12
beacon-chain/state/stategen/init_test.go
Normal file
@ -0,0 +1,12 @@
|
||||
package stategen
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Override network name so that hardcoded genesis files are not loaded.
|
||||
cfg := params.BeaconConfig()
|
||||
cfg.ConfigName = "test"
|
||||
params.OverrideBeaconConfig(cfg)
|
||||
}
|
@ -166,4 +166,10 @@ var (
|
||||
Usage: "Sets the maximum number of headers that a deposit log query can fetch.",
|
||||
Value: uint64(1000),
|
||||
}
|
||||
// GenesisStatePath defines a flag to start the beacon chain from a give genesis state file.
|
||||
GenesisStatePath = &cli.StringFlag{
|
||||
Name: "genesis-state",
|
||||
Usage: "Load a genesis state from ssz file. Testnet genesis files can be found in the " +
|
||||
"eth2-clients/eth2-testnets repository on github.",
|
||||
}
|
||||
)
|
||||
|
@ -7,8 +7,10 @@ import (
|
||||
var (
|
||||
// InteropGenesisStateFlag defines a flag for the beacon node to load genesis state via file.
|
||||
InteropGenesisStateFlag = &cli.StringFlag{
|
||||
Name: "interop-genesis-state",
|
||||
Usage: "The genesis state file (.SSZ) to load from",
|
||||
Name: "interop-genesis-state",
|
||||
Usage: "The genesis state file (.SSZ) to load from. Note: loading from an interop genesis " +
|
||||
"state does not use a web3 connection to read any deposits. This interop " +
|
||||
"functionality should not be used with public testnets.",
|
||||
}
|
||||
// InteropMockEth1DataVotesFlag enables mocking the eth1 proof-of-work chain data put into blocks by proposers.
|
||||
InteropMockEth1DataVotesFlag = &cli.BoolFlag{
|
||||
|
@ -60,6 +60,7 @@ var appFlags = []cli.Flag{
|
||||
flags.NetworkID,
|
||||
flags.WeakSubjectivityCheckpt,
|
||||
flags.Eth1HeaderReqLimit,
|
||||
flags.GenesisStatePath,
|
||||
cmd.EnableBackupWebhookFlag,
|
||||
cmd.BackupWebhookOutputDir,
|
||||
cmd.MinimalConfigFlag,
|
||||
|
@ -119,6 +119,7 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.NetworkID,
|
||||
flags.WeakSubjectivityCheckpt,
|
||||
flags.Eth1HeaderReqLimit,
|
||||
flags.GenesisStatePath,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
package params
|
||||
|
||||
const (
|
||||
Mainnet configName = iota
|
||||
Mainnet ConfigName = iota
|
||||
EndToEnd
|
||||
Pyrmont
|
||||
Toledo
|
||||
@ -9,7 +9,7 @@ const (
|
||||
)
|
||||
|
||||
// ConfigNames provides network configuration names.
|
||||
var ConfigNames = map[configName]string{
|
||||
var ConfigNames = map[ConfigName]string{
|
||||
Mainnet: "mainnet",
|
||||
EndToEnd: "end-to-end",
|
||||
Pyrmont: "pyrmont",
|
||||
@ -17,4 +17,5 @@ var ConfigNames = map[configName]string{
|
||||
Prater: "prater",
|
||||
}
|
||||
|
||||
type configName = int
|
||||
// ConfigName enum describes the type of known network in use.
|
||||
type ConfigName = int
|
||||
|
Loading…
Reference in New Issue
Block a user