diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index a3016c4b091..c89f736169e 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -61,9 +61,10 @@ It expects the genesis file as argument.`, Name: "dumpgenesis", Usage: "Dumps genesis block JSON configuration to stdout", ArgsUsage: "", - Flags: utils.NetworkFlags, + Flags: append([]cli.Flag{utils.DataDirFlag}, utils.NetworkFlags...), Description: ` -The dumpgenesis command dumps the genesis block configuration in JSON format to stdout.`, +The dumpgenesis command prints the genesis configuration of the network preset +if one is set. Otherwise it prints the genesis from the datadir.`, } importCommand = &cli.Command{ Action: importChain, @@ -203,14 +204,39 @@ func initGenesis(ctx *cli.Context) error { } func dumpGenesis(ctx *cli.Context) error { - // TODO(rjl493456442) support loading from the custom datadir - genesis := utils.MakeGenesis(ctx) - if genesis == nil { - genesis = core.DefaultGenesisBlock() + // if there is a testnet preset enabled, dump that + if utils.IsNetworkPreset(ctx) { + genesis := utils.MakeGenesis(ctx) + if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil { + utils.Fatalf("could not encode genesis: %s", err) + } + return nil + } + // dump whatever already exists in the datadir + stack, _ := makeConfigNode(ctx) + for _, name := range []string{"chaindata", "lightchaindata"} { + db, err := stack.OpenDatabase(name, 0, 0, "", true) + if err != nil { + if !os.IsNotExist(err) { + return err + } + continue + } + genesis, err := core.ReadGenesis(db) + if err != nil { + utils.Fatalf("failed to read genesis: %s", err) + } + db.Close() + + if err := json.NewEncoder(os.Stdout).Encode(*genesis); err != nil { + utils.Fatalf("could not encode stored genesis: %s", err) + } + return nil } - if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil { - utils.Fatalf("could not encode genesis") + if ctx.IsSet(utils.DataDirFlag.Name) { + utils.Fatalf("no existing datadir at %s", stack.Config().DataDir) } + utils.Fatalf("no network preset provided. no exisiting genesis in the default datadir") return nil } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 595fe3360fe..745b9f088eb 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -988,9 +988,7 @@ var ( KilnFlag, } // NetworkFlags is the flag group of all built-in supported networks. - NetworkFlags = append([]cli.Flag{ - MainnetFlag, - }, TestnetFlags...) + NetworkFlags = append([]cli.Flag{MainnetFlag}, TestnetFlags...) // DatabasePathFlags is the flag group of all database path flags. DatabasePathFlags = []cli.Flag{ @@ -2140,6 +2138,16 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb. return chainDb } +func IsNetworkPreset(ctx *cli.Context) bool { + for _, flag := range NetworkFlags { + bFlag, _ := flag.(*cli.BoolFlag) + if ctx.IsSet(bFlag.Name) { + return true + } + } + return false +} + func MakeGenesis(ctx *cli.Context) *core.Genesis { var genesis *core.Genesis switch { diff --git a/core/genesis.go b/core/genesis.go index 1c62bb1a137..8b855147972 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -65,6 +65,41 @@ type Genesis struct { BaseFee *big.Int `json:"baseFeePerGas"` } +func ReadGenesis(db ethdb.Database) (*Genesis, error) { + var genesis Genesis + stored := rawdb.ReadCanonicalHash(db, 0) + if (stored == common.Hash{}) { + return nil, fmt.Errorf("invalid genesis hash in database: %x", stored) + } + blob := rawdb.ReadGenesisStateSpec(db, stored) + if blob == nil { + return nil, fmt.Errorf("genesis state missing from db") + } + if len(blob) != 0 { + if err := genesis.Alloc.UnmarshalJSON(blob); err != nil { + return nil, fmt.Errorf("could not unmarshal genesis state json: %s", err) + } + } + genesis.Config = rawdb.ReadChainConfig(db, stored) + if genesis.Config == nil { + return nil, fmt.Errorf("genesis config missing from db") + } + genesisBlock := rawdb.ReadBlock(db, stored, 0) + if genesisBlock == nil { + return nil, fmt.Errorf("genesis block missing from db") + } + genesisHeader := genesisBlock.Header() + genesis.Nonce = genesisHeader.Nonce.Uint64() + genesis.Timestamp = genesisHeader.Time + genesis.ExtraData = genesisHeader.Extra + genesis.GasLimit = genesisHeader.GasLimit + genesis.Difficulty = genesisHeader.Difficulty + genesis.Mixhash = genesisHeader.MixDigest + genesis.Coinbase = genesisHeader.Coinbase + + return &genesis, nil +} + // GenesisAlloc specifies the initial state that is part of the genesis block. type GenesisAlloc map[common.Address]GenesisAccount