Skip to content

Commit e477fdf

Browse files
prestonvanloonrauljordanterencechain
authored
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>
1 parent a921455 commit e477fdf

35 files changed

+520
-74
lines changed

beacon-chain/blockchain/BUILD.bazel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ go_library(
2727
deps = [
2828
"//beacon-chain/cache:go_default_library",
2929
"//beacon-chain/cache/depositcache:go_default_library",
30-
"//beacon-chain/core/blocks:go_default_library",
3130
"//beacon-chain/core/epoch/precompute:go_default_library",
3231
"//beacon-chain/core/feed:go_default_library",
3332
"//beacon-chain/core/feed/state:go_default_library",
@@ -84,6 +83,7 @@ go_test(
8483
"checktags_test.go",
8584
"head_test.go",
8685
"info_test.go",
86+
"init_test.go",
8787
"metrics_test.go",
8888
"process_attestation_test.go",
8989
"process_block_test.go",
@@ -130,6 +130,7 @@ go_test(
130130
srcs = [
131131
"chain_info_norace_test.go",
132132
"checktags_test.go",
133+
"init_test.go",
133134
"receive_block_test.go",
134135
"service_norace_test.go",
135136
],
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package blockchain
2+
3+
import (
4+
"github.com/prysmaticlabs/prysm/shared/params"
5+
)
6+
7+
func init() {
8+
// Override network name so that hardcoded genesis files are not loaded.
9+
cfg := params.BeaconConfig()
10+
cfg.ConfigName = "test"
11+
params.OverrideBeaconConfig(cfg)
12+
}

beacon-chain/blockchain/service.go

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
1616
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
1717
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
18-
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
1918
"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
2019
statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
2120
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
@@ -32,7 +31,6 @@ import (
3231
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
3332
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
3433
"github.com/prysmaticlabs/prysm/cmd/beacon-chain/flags"
35-
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
3634
"github.com/prysmaticlabs/prysm/shared/bytesutil"
3735
"github.com/prysmaticlabs/prysm/shared/params"
3836
"github.com/prysmaticlabs/prysm/shared/slotutil"
@@ -336,38 +334,20 @@ func (s *Service) Status() error {
336334

337335
// This gets called when beacon chain is first initialized to save genesis data (state, block, and more) in db.
338336
func (s *Service) saveGenesisData(ctx context.Context, genesisState iface.BeaconState) error {
339-
stateRoot, err := genesisState.HashTreeRoot(ctx)
340-
if err != nil {
341-
return err
337+
if err := s.cfg.BeaconDB.SaveGenesisData(ctx, genesisState); err != nil {
338+
return errors.Wrap(err, "could not save genesis data")
339+
}
340+
genesisBlk, err := s.cfg.BeaconDB.GenesisBlock(ctx)
341+
if err != nil || genesisBlk == nil {
342+
return fmt.Errorf("could not load genesis block: %v", err)
342343
}
343-
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
344344
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
345345
if err != nil {
346346
return errors.Wrap(err, "could not get genesis block root")
347347
}
348-
s.genesisRoot = genesisBlkRoot
349-
350-
if err := s.cfg.BeaconDB.SaveBlock(ctx, genesisBlk); err != nil {
351-
return errors.Wrap(err, "could not save genesis block")
352-
}
353-
if err := s.cfg.BeaconDB.SaveState(ctx, genesisState, genesisBlkRoot); err != nil {
354-
return errors.Wrap(err, "could not save genesis state")
355-
}
356-
if err := s.cfg.BeaconDB.SaveStateSummary(ctx, &pb.StateSummary{
357-
Slot: 0,
358-
Root: genesisBlkRoot[:],
359-
}); err != nil {
360-
return err
361-
}
362348

363-
s.cfg.StateGen.SaveFinalizedState(0, genesisBlkRoot, genesisState)
364-
365-
if err := s.cfg.BeaconDB.SaveHeadBlockRoot(ctx, genesisBlkRoot); err != nil {
366-
return errors.Wrap(err, "could not save head block root")
367-
}
368-
if err := s.cfg.BeaconDB.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
369-
return errors.Wrap(err, "could not save genesis block root")
370-
}
349+
s.genesisRoot = genesisBlkRoot
350+
s.cfg.StateGen.SaveFinalizedState(0 /*slot*/, genesisBlkRoot, genesisState)
371351

372352
// Finalized checkpoint at genesis is a zero hash.
373353
genesisCheckpoint := genesisState.FinalizedCheckpoint()
@@ -392,7 +372,6 @@ func (s *Service) saveGenesisData(ctx context.Context, genesisState iface.Beacon
392372
}
393373

394374
s.setHead(genesisBlkRoot, genesisBlk, genesisState)
395-
396375
return nil
397376
}
398377

beacon-chain/db/alias.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ type HeadAccessDatabase = iface.HeadAccessDatabase
2222
// key-value or relational database in practice. This is the full database interface which should
2323
// not be used often. Prefer a more restrictive interface in this package.
2424
type Database = iface.Database
25+
26+
// ErrExistingGenesisState is an error when the user attempts to save a different genesis state
27+
// when one already exists in a database.
28+
var ErrExistingGenesisState = iface.ErrExistingGenesisState

beacon-chain/db/iface/BUILD.bazel

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ load("@prysm//tools/go:def.bzl", "go_library")
22

33
go_library(
44
name = "go_default_library",
5-
srcs = ["interface.go"],
5+
srcs = [
6+
"errors.go",
7+
"interface.go",
8+
],
69
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/db/iface",
710
# Other packages must use github.com/prysmaticlabs/prysm/beacon-chain/db.Database alias.
811
visibility = ["//beacon-chain/db:__subpackages__"],

beacon-chain/db/iface/errors.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package iface
2+
3+
import (
4+
"errors"
5+
)
6+
7+
var (
8+
// ErrExistingGenesisState is an error when the user attempts to save a different genesis state
9+
// when one already exists in a database.
10+
ErrExistingGenesisState = errors.New("genesis state exists already in the DB")
11+
)

beacon-chain/db/iface/interface.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ type HeadAccessDatabase interface {
9999
// Block related methods.
100100
HeadBlock(ctx context.Context) (*eth.SignedBeaconBlock, error)
101101
SaveHeadBlockRoot(ctx context.Context, blockRoot [32]byte) error
102+
103+
// Genesis operations.
104+
LoadGenesis(ctx context.Context, r io.Reader) error
105+
SaveGenesisData(ctx context.Context, state iface.BeaconState) error
106+
EnsureEmbeddedGenesis(ctx context.Context) error
102107
}
103108

104109
// Database interface with full access.

beacon-chain/db/kafka/passthrough.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kafka
22

33
import (
44
"context"
5+
"io"
56

67
"github.com/ethereum/go-ethereum/common"
78
types "github.com/prysmaticlabs/eth2-types"
@@ -266,3 +267,18 @@ func (e Exporter) RunMigrations(ctx context.Context) error {
266267
func (e Exporter) CleanUpDirtyStates(ctx context.Context, slotsPerArchivedPoint types.Slot) error {
267268
return e.db.RunMigrations(ctx)
268269
}
270+
271+
// LoadGenesisFromFile -- passthrough
272+
func (e Exporter) LoadGenesis(ctx context.Context, r io.Reader) error {
273+
return e.db.LoadGenesis(ctx, r)
274+
}
275+
276+
// SaveGenesisData -- passthrough
277+
func (e Exporter) SaveGenesisData(ctx context.Context, state iface.BeaconState) error {
278+
return e.db.SaveGenesisData(ctx, state)
279+
}
280+
281+
// EnsureEmbeddedGenesis -- passthrough.
282+
func (e Exporter) EnsureEmbeddedGenesis(ctx context.Context) error {
283+
return e.db.EnsureEmbeddedGenesis(ctx)
284+
}

beacon-chain/db/kv/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ go_library(
1111
"deposit_contract.go",
1212
"encoding.go",
1313
"finalized_block_roots.go",
14+
"genesis.go",
1415
"kv.go",
1516
"log.go",
1617
"migration.go",
@@ -32,9 +33,11 @@ go_library(
3233
"//tools:__subpackages__",
3334
],
3435
deps = [
36+
"//beacon-chain/core/blocks:go_default_library",
3537
"//beacon-chain/core/helpers:go_default_library",
3638
"//beacon-chain/db/filters:go_default_library",
3739
"//beacon-chain/db/iface:go_default_library",
40+
"//beacon-chain/state/genesis:go_default_library",
3841
"//beacon-chain/state/interface:go_default_library",
3942
"//beacon-chain/state/stateV0:go_default_library",
4043
"//proto/beacon/db:go_default_library",
@@ -70,6 +73,8 @@ go_test(
7073
"deposit_contract_test.go",
7174
"encoding_test.go",
7275
"finalized_block_roots_test.go",
76+
"genesis_test.go",
77+
"init_test.go",
7378
"kv_test.go",
7479
"migration_archived_index_test.go",
7580
"migration_block_slot_index_test.go",
@@ -80,9 +85,11 @@ go_test(
8085
"state_test.go",
8186
"utils_test.go",
8287
],
88+
data = glob(["testdata/**"]),
8389
embed = [":go_default_library"],
8490
deps = [
8591
"//beacon-chain/db/filters:go_default_library",
92+
"//beacon-chain/db/iface:go_default_library",
8693
"//beacon-chain/state/interface:go_default_library",
8794
"//proto/beacon/db:go_default_library",
8895
"//proto/beacon/p2p/v1:go_default_library",
@@ -97,6 +104,7 @@ go_test(
97104
"@com_github_prysmaticlabs_eth2_types//:go_default_library",
98105
"@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library",
99106
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
107+
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
100108
"@io_etcd_go_bbolt//:go_default_library",
101109
],
102110
)

beacon-chain/db/kv/genesis.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package kv
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"io"
8+
"io/ioutil"
9+
10+
"github.com/pkg/errors"
11+
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
12+
dbIface "github.com/prysmaticlabs/prysm/beacon-chain/db/iface"
13+
iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface"
14+
state "github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
15+
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
16+
"github.com/prysmaticlabs/prysm/shared/params"
17+
)
18+
19+
// SaveGenesisData bootstraps the beaconDB with a given genesis state.
20+
func (s *Store) SaveGenesisData(ctx context.Context, genesisState iface.BeaconState) error {
21+
stateRoot, err := genesisState.HashTreeRoot(ctx)
22+
if err != nil {
23+
return err
24+
}
25+
genesisBlk := blocks.NewGenesisBlock(stateRoot[:])
26+
genesisBlkRoot, err := genesisBlk.Block.HashTreeRoot()
27+
if err != nil {
28+
return errors.Wrap(err, "could not get genesis block root")
29+
}
30+
if err := s.SaveBlock(ctx, genesisBlk); err != nil {
31+
return errors.Wrap(err, "could not save genesis block")
32+
}
33+
if err := s.SaveState(ctx, genesisState, genesisBlkRoot); err != nil {
34+
return errors.Wrap(err, "could not save genesis state")
35+
}
36+
if err := s.SaveStateSummary(ctx, &pbp2p.StateSummary{
37+
Slot: 0,
38+
Root: genesisBlkRoot[:],
39+
}); err != nil {
40+
return err
41+
}
42+
43+
if err := s.SaveHeadBlockRoot(ctx, genesisBlkRoot); err != nil {
44+
return errors.Wrap(err, "could not save head block root")
45+
}
46+
if err := s.SaveGenesisBlockRoot(ctx, genesisBlkRoot); err != nil {
47+
return errors.Wrap(err, "could not save genesis block root")
48+
}
49+
50+
return nil
51+
}
52+
53+
// LoadGenesisFromFile loads a genesis state from a given file path, if no genesis exists already.
54+
func (s *Store) LoadGenesis(ctx context.Context, r io.Reader) error {
55+
b, err := ioutil.ReadAll(r)
56+
if err != nil {
57+
return err
58+
}
59+
st := &pbp2p.BeaconState{}
60+
if err := st.UnmarshalSSZ(b); err != nil {
61+
return err
62+
}
63+
gs, err := state.InitializeFromProtoUnsafe(st)
64+
if err != nil {
65+
return err
66+
}
67+
existing, err := s.GenesisState(ctx)
68+
if err != nil {
69+
return err
70+
}
71+
// If some different genesis state existed already, return an error. The same genesis state is
72+
// considered a no-op.
73+
if existing != nil {
74+
a, err := existing.HashTreeRoot(ctx)
75+
if err != nil {
76+
return err
77+
}
78+
b, err := gs.HashTreeRoot(ctx)
79+
if err != nil {
80+
return err
81+
}
82+
if a == b {
83+
return nil
84+
}
85+
return dbIface.ErrExistingGenesisState
86+
}
87+
88+
if !bytes.Equal(gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion) {
89+
return fmt.Errorf("loaded genesis fork version (%#x) does not match config genesis "+
90+
"fork version (%#x)", gs.Fork().CurrentVersion, params.BeaconConfig().GenesisForkVersion)
91+
}
92+
93+
return s.SaveGenesisData(ctx, gs)
94+
}
95+
96+
// EnsureEmbeddedGenesis checks that a genesis block has been generated when an embedded genesis
97+
// state is used. If a genesis block does not exist, but a genesis state does, then we should call
98+
// SaveGenesisData on the existing genesis state.
99+
func (s *Store) EnsureEmbeddedGenesis(ctx context.Context) error {
100+
gb, err := s.GenesisBlock(ctx)
101+
if err != nil {
102+
return err
103+
}
104+
if gb != nil {
105+
return nil
106+
}
107+
gs, err := s.GenesisState(ctx)
108+
if err != nil {
109+
return err
110+
}
111+
if gs != nil {
112+
return s.SaveGenesisData(ctx, gs)
113+
}
114+
return nil
115+
}

0 commit comments

Comments
 (0)