diff --git a/beacon-chain/core/altair/BUILD.bazel b/beacon-chain/core/altair/BUILD.bazel index 6d0e14bab234..990f9a9fa60c 100644 --- a/beacon-chain/core/altair/BUILD.bazel +++ b/beacon-chain/core/altair/BUILD.bazel @@ -16,6 +16,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair", visibility = [ "//beacon-chain:__subpackages__", + "//cmd/prysmctl/testnet:__pkg__", "//testing/endtoend/evaluators:__subpackages__", "//testing/spectest:__subpackages__", "//testing/util:__pkg__", diff --git a/beacon-chain/core/execution/BUILD.bazel b/beacon-chain/core/execution/BUILD.bazel index f67f3e1124ca..cf4efff737af 100644 --- a/beacon-chain/core/execution/BUILD.bazel +++ b/beacon-chain/core/execution/BUILD.bazel @@ -6,6 +6,7 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/execution", visibility = [ "//beacon-chain:__subpackages__", + "//cmd/prysmctl/testnet:__pkg__", "//testing/spectest:__subpackages__", "//validator/client:__pkg__", ], diff --git a/cmd/flags/BUILD.bazel b/cmd/flags/BUILD.bazel new file mode 100644 index 000000000000..bbc1a8c67621 --- /dev/null +++ b/cmd/flags/BUILD.bazel @@ -0,0 +1,9 @@ +load("@prysm//tools/go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["enum.go"], + importpath = "github.com/prysmaticlabs/prysm/v3/cmd/flags", + visibility = ["//visibility:public"], + deps = ["@com_github_urfave_cli_v2//:go_default_library"], +) diff --git a/cmd/flags/enum.go b/cmd/flags/enum.go new file mode 100644 index 000000000000..7864c63e7e83 --- /dev/null +++ b/cmd/flags/enum.go @@ -0,0 +1,47 @@ +package flags + +// via https://github.com/urfave/cli/issues/602 + +import ( + "fmt" + "strings" + + "github.com/urfave/cli/v2" +) + +// EnumValue allows the cli to present a fixed set of string values. +type EnumValue struct { + Name string + Usage string + Destination *string + Enum []string + Value string +} + +func (e *EnumValue) Set(value string) error { + for _, enum := range e.Enum { + if enum == value { + *e.Destination = value + return nil + } + } + + return fmt.Errorf("allowed values are %s", strings.Join(e.Enum, ", ")) +} + +func (e *EnumValue) String() string { + if e.Destination == nil { + return e.Value + } + if *e.Destination == "" { + return e.Value + } + return *e.Destination +} + +// Wraps the EnumValue in a GenericFlag value so that it satisfies the cli.Flag interface. +func (e EnumValue) GenericFlag() *cli.GenericFlag { + *e.Destination = e.Value + var i cli.Generic = &e + return &cli.GenericFlag{Name: e.Name, Usage: e.Usage, Destination: &i, Value: i} +} diff --git a/cmd/prysmctl/testnet/BUILD.bazel b/cmd/prysmctl/testnet/BUILD.bazel index 81206492c396..7d4c98d87bb5 100644 --- a/cmd/prysmctl/testnet/BUILD.bazel +++ b/cmd/prysmctl/testnet/BUILD.bazel @@ -9,13 +9,19 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/testnet", visibility = ["//visibility:public"], deps = [ + "//beacon-chain/core/altair:go_default_library", + "//beacon-chain/core/capella:go_default_library", + "//beacon-chain/core/execution:go_default_library", + "//beacon-chain/state:go_default_library", + "//beacon-chain/state/state-native:go_default_library", + "//cmd/flags:go_default_library", "//config/params:go_default_library", "//io/file:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/interop:go_default_library", + "//runtime/version:go_default_library", "@com_github_ghodss_yaml//:go_default_library", "@com_github_pkg_errors//:go_default_library", - "@com_github_prysmaticlabs_fastssz//:go_default_library", "@com_github_sirupsen_logrus//:go_default_library", "@com_github_urfave_cli_v2//:go_default_library", ], diff --git a/cmd/prysmctl/testnet/generate_genesis.go b/cmd/prysmctl/testnet/generate_genesis.go index ade0f7a371cd..e03beb8b516d 100644 --- a/cmd/prysmctl/testnet/generate_genesis.go +++ b/cmd/prysmctl/testnet/generate_genesis.go @@ -9,9 +9,16 @@ import ( "os" "strings" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/altair" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/capella" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/execution" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" + state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" + "github.com/prysmaticlabs/prysm/v3/cmd/flags" + "github.com/prysmaticlabs/prysm/v3/runtime/version" + "github.com/ghodss/yaml" "github.com/pkg/errors" - fastssz "github.com/prysmaticlabs/fastssz" "github.com/prysmaticlabs/prysm/v3/config/params" "github.com/prysmaticlabs/prysm/v3/io/file" ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -30,6 +37,7 @@ var ( OutputSSZ string OutputJSON string OutputYaml string + ForkName string }{} log = logrus.WithField("prefix", "genesis") outputSSZFlag = &cli.StringFlag{ @@ -82,6 +90,13 @@ var ( Destination: &generateGenesisStateFlags.GenesisTime, Usage: "Unix timestamp seconds used as the genesis time in the genesis state. If unset, defaults to now()", }, + flags.EnumValue{ + Name: "fork", + Usage: fmt.Sprintf("Name of the BeaconState schema to use in output encoding [%s]", strings.Join(versionNames(), ",")), + Enum: versionNames(), + Value: versionNames()[0], + Destination: &generateGenesisStateFlags.ForkName, + }.GenericFlag(), outputSSZFlag, outputYamlFlag, outputJsonFlag, @@ -89,6 +104,15 @@ var ( } ) +func versionNames() []string { + enum := version.All() + names := make([]string, len(enum)) + for i := range enum { + names[i] = version.String(enum[i]) + } + return names +} + // Represents a json object of hex string and uint64 values for // validators on Ethereum. This file can be generated using the official staking-deposit-cli. type depositDataJSON struct { @@ -122,25 +146,33 @@ func cliActionGenerateGenesisState(cliCtx *cli.Context) error { if err != nil { return fmt.Errorf("could not generate genesis state: %v", err) } + st, err := upgradeStateToForkName(cliCtx.Context, genesisState, generateGenesisStateFlags.ForkName) + if err != nil { + return err + } + if outputJson != "" { - if err := writeToOutputFile(outputJson, genesisState, json.Marshal); err != nil { + if err := writeToOutputFile(outputJson, st, json.Marshal); err != nil { return err } } if outputYaml != "" { - if err := writeToOutputFile(outputYaml, genesisState, yaml.Marshal); err != nil { + if err := writeToOutputFile(outputYaml, st, yaml.Marshal); err != nil { return err } } if outputSSZ != "" { + type MinimumSSZMarshal interface { + MarshalSSZ() ([]byte, error) + } marshalFn := func(o interface{}) ([]byte, error) { - marshaler, ok := o.(fastssz.Marshaler) + marshaler, ok := o.(MinimumSSZMarshal) if !ok { return nil, errors.New("not a marshaler") } return marshaler.MarshalSSZ() } - if err := writeToOutputFile(outputSSZ, genesisState, marshalFn); err != nil { + if err := writeToOutputFile(outputSSZ, st, marshalFn); err != nil { return err } } @@ -148,6 +180,42 @@ func cliActionGenerateGenesisState(cliCtx *cli.Context) error { return nil } +func upgradeStateToForkName(ctx context.Context, pbst *ethpb.BeaconState, name string) (state.BeaconState, error) { + st, err := state_native.InitializeFromProtoUnsafePhase0(pbst) + if err != nil { + return nil, err + } + if name == "" || name == "phase0" { + return st, nil + } + + st, err = altair.UpgradeToAltair(ctx, st) + if err != nil { + return nil, err + } + if name == "altair" { + return st, nil + } + + st, err = execution.UpgradeToBellatrix(st) + if err != nil { + return nil, err + } + if name == "bellatrix" { + return st, nil + } + + st, err = capella.UpgradeToCapella(st) + if err != nil { + return nil, err + } + if name == "capella" { + return st, nil + } + + return nil, fmt.Errorf("unrecognized fork name '%s'", name) +} + func setGlobalParams() error { chainConfigFile := generateGenesisStateFlags.ChainConfigFile if chainConfigFile != "" { diff --git a/runtime/version/fork.go b/runtime/version/fork.go index 4a2e4fa922e8..6d4e0d7abd56 100644 --- a/runtime/version/fork.go +++ b/runtime/version/fork.go @@ -21,3 +21,8 @@ func String(version int) string { return "unknown version" } } + +// All returns a list of all known fork versions. +func All() []int { + return []int{Phase0, Altair, Bellatrix, Capella} +}