2021-03-18 21:00:00 +00:00
|
|
|
package kv
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
|
|
|
dbIface "github.com/prysmaticlabs/prysm/beacon-chain/db/iface"
|
2021-07-23 16:11:21 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
|
|
statev1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
|
2021-09-21 19:59:25 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/config/params"
|
2022-05-02 15:43:40 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/consensus-types/wrapper"
|
2021-07-29 21:45:17 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
2021-03-18 21:00:00 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// SaveGenesisData bootstraps the beaconDB with a given genesis state.
|
2021-07-23 16:11:21 +00:00
|
|
|
func (s *Store) SaveGenesisData(ctx context.Context, genesisState state.BeaconState) error {
|
2021-03-18 21:00:00 +00:00
|
|
|
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")
|
|
|
|
}
|
2022-03-25 23:00:44 +00:00
|
|
|
wsb, err := wrapper.WrappedSignedBeaconBlock(genesisBlk)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "could not wrap genesis block")
|
|
|
|
}
|
|
|
|
if err := s.SaveBlock(ctx, wsb); err != nil {
|
2021-03-18 21:00:00 +00:00
|
|
|
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")
|
|
|
|
}
|
2021-07-29 21:45:17 +00:00
|
|
|
if err := s.SaveStateSummary(ctx, ðpb.StateSummary{
|
2021-03-18 21:00:00 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-03-30 22:23:34 +00:00
|
|
|
// LoadGenesis loads a genesis state from a ssz-serialized byte slice, if no genesis exists already.
|
|
|
|
func (s *Store) LoadGenesis(ctx context.Context, sb []byte) error {
|
2021-07-29 21:45:17 +00:00
|
|
|
st := ðpb.BeaconState{}
|
2022-03-30 22:23:34 +00:00
|
|
|
if err := st.UnmarshalSSZ(sb); err != nil {
|
2021-03-18 21:00:00 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-07-23 16:11:21 +00:00
|
|
|
gs, err := statev1.InitializeFromProtoUnsafe(st)
|
2021-03-18 21:00:00 +00:00
|
|
|
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.
|
2021-05-24 04:55:42 +00:00
|
|
|
if existing != nil && !existing.IsNil() {
|
2021-03-18 21:00:00 +00:00
|
|
|
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
|
|
|
|
}
|
2021-05-26 16:19:54 +00:00
|
|
|
if gb != nil && !gb.IsNil() {
|
2021-03-18 21:00:00 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
gs, err := s.GenesisState(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-24 04:55:42 +00:00
|
|
|
if gs != nil && !gs.IsNil() {
|
2021-03-18 21:00:00 +00:00
|
|
|
return s.SaveGenesisData(ctx, gs)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|