package genesis import ( "context" "fmt" "os" "strconv" "strings" "time" "github.com/OffchainLabs/prysm/v7/beacon-chain/state" "github.com/OffchainLabs/prysm/v7/config/params" "github.com/OffchainLabs/prysm/v7/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 := FindStateFile(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 } // FindStateFile searches for a valid genesis state file in the specified directory. func FindStateFile(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 }