2021-12-09 22:23:00 +00:00
package kv
import (
"context"
2022-03-28 21:01:55 +00:00
"fmt"
2021-12-09 22:23:00 +00:00
"github.com/pkg/errors"
2022-08-16 12:20:13 +00:00
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/encoding/ssz/detect"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/runtime/version"
2021-12-09 22:23:00 +00:00
)
// SaveOrigin loads an ssz serialized Block & BeaconState from an io.Reader
// (ex: an open file) prepares the database so that the beacon node can begin
// syncing, using the provided values as their point of origin. This is an alternative
// to syncing from genesis, and should only be run on an empty database.
2022-03-28 21:01:55 +00:00
func ( s * Store ) SaveOrigin ( ctx context . Context , serState , serBlock [ ] byte ) error {
genesisRoot , err := s . GenesisBlockRoot ( ctx )
2022-03-21 19:43:41 +00:00
if err != nil {
2022-03-28 21:01:55 +00:00
if errors . Is ( err , ErrNotFoundGenesisBlockRoot ) {
return errors . Wrap ( err , "genesis block root not found: genesis must be provided for checkpoint sync" )
}
return errors . Wrap ( err , "genesis block root query error: checkpoint sync must verify genesis to proceed" )
2022-03-21 19:43:41 +00:00
}
2022-03-28 21:01:55 +00:00
err = s . SaveBackfillBlockRoot ( ctx , genesisRoot )
2021-12-09 22:23:00 +00:00
if err != nil {
2022-03-28 21:01:55 +00:00
return errors . Wrap ( err , "unable to save genesis root as initial backfill starting point for checkpoint sync" )
2021-12-09 22:23:00 +00:00
}
2022-03-21 19:43:41 +00:00
2022-03-28 21:01:55 +00:00
cf , err := detect . FromState ( serState )
2022-03-21 19:43:41 +00:00
if err != nil {
2022-03-28 21:01:55 +00:00
return errors . Wrap ( err , "could not sniff config+fork for origin state bytes" )
2021-12-09 22:23:00 +00:00
}
2022-03-28 21:01:55 +00:00
_ , ok := params . BeaconConfig ( ) . ForkVersionSchedule [ cf . Version ]
if ! ok {
return fmt . Errorf ( "config mismatch, beacon node configured to connect to %s, detected state is for %s" , params . BeaconConfig ( ) . ConfigName , cf . Config . ConfigName )
}
log . Infof ( "detected supported config for state & block version, config name=%s, fork name=%s" , cf . Config . ConfigName , version . String ( cf . Fork ) )
state , err := cf . UnmarshalBeaconState ( serState )
2021-12-09 22:23:00 +00:00
if err != nil {
2022-03-28 21:01:55 +00:00
return errors . Wrap ( err , "failed to initialize origin state w/ bytes + config+fork" )
2021-12-09 22:23:00 +00:00
}
2022-03-28 21:01:55 +00:00
wblk , err := cf . UnmarshalBeaconBlock ( serBlock )
2021-12-09 22:23:00 +00:00
if err != nil {
2022-03-28 21:01:55 +00:00
return errors . Wrap ( err , "failed to initialize origin block w/ bytes + config+fork" )
2021-12-09 22:23:00 +00:00
}
2022-03-28 21:01:55 +00:00
blk := wblk . Block ( )
2021-12-09 22:23:00 +00:00
2022-03-28 21:01:55 +00:00
// save block
blockRoot , err := blk . HashTreeRoot ( )
2022-03-21 19:43:41 +00:00
if err != nil {
return errors . Wrap ( err , "could not compute HashTreeRoot of checkpoint block" )
}
2022-03-28 21:01:55 +00:00
log . Infof ( "saving checkpoint block to db, w/ root=%#x" , blockRoot )
2021-12-09 22:23:00 +00:00
if err := s . SaveBlock ( ctx , wblk ) ; err != nil {
return errors . Wrap ( err , "could not save checkpoint block" )
}
// save state
2022-03-28 21:01:55 +00:00
log . Infof ( "calling SaveState w/ blockRoot=%x" , blockRoot )
if err = s . SaveState ( ctx , state , blockRoot ) ; err != nil {
2021-12-09 22:23:00 +00:00
return errors . Wrap ( err , "could not save state" )
}
if err = s . SaveStateSummary ( ctx , & ethpb . StateSummary {
2022-03-28 21:01:55 +00:00
Slot : state . Slot ( ) ,
2021-12-09 22:23:00 +00:00
Root : blockRoot [ : ] ,
} ) ; err != nil {
return errors . Wrap ( err , "could not save state summary" )
}
// mark block as head of chain, so that processing will pick up from this point
if err = s . SaveHeadBlockRoot ( ctx , blockRoot ) ; err != nil {
return errors . Wrap ( err , "could not save head block root" )
}
2022-04-05 17:13:53 +00:00
// save origin block root in a special key, to be used when the canonical
// origin (start of chain, ie alternative to genesis) block or state is needed
if err = s . SaveOriginCheckpointBlockRoot ( ctx , blockRoot ) ; err != nil {
return errors . Wrap ( err , "could not save origin block root" )
}
2021-12-09 22:23:00 +00:00
// rebuild the checkpoint from the block
// use it to mark the block as justified and finalized
2022-03-21 19:43:41 +00:00
slotEpoch , err := wblk . Block ( ) . Slot ( ) . SafeDivSlot ( params . BeaconConfig ( ) . SlotsPerEpoch )
2021-12-09 22:23:00 +00:00
if err != nil {
return err
}
chkpt := & ethpb . Checkpoint {
Epoch : types . Epoch ( slotEpoch ) ,
Root : blockRoot [ : ] ,
}
if err = s . SaveJustifiedCheckpoint ( ctx , chkpt ) ; err != nil {
return errors . Wrap ( err , "could not mark checkpoint sync block as justified" )
}
if err = s . SaveFinalizedCheckpoint ( ctx , chkpt ) ; err != nil {
return errors . Wrap ( err , "could not mark checkpoint sync block as finalized" )
}
return nil
}