forked from cerc-io/plugeth
manual geth v1.11.1 merge
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// Copyright 2022 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type testHandler struct {
|
||||
body func(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
func (t *testHandler) ServeHTTP(out http.ResponseWriter, in *http.Request) {
|
||||
t.body(out, in)
|
||||
}
|
||||
|
||||
// TestAttachWithHeaders tests that 'geth attach' with custom headers works, i.e
|
||||
// that custom headers are forwarded to the target.
|
||||
func TestAttachWithHeaders(t *testing.T) {
|
||||
t.Parallel()
|
||||
ln, err := net.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
testReceiveHeaders(t, ln, "attach", "-H", "first: one", "-H", "second: two", fmt.Sprintf("http://localhost:%d", port))
|
||||
// This way to do it fails due to flag ordering:
|
||||
//
|
||||
// testReceiveHeaders(t, ln, "-H", "first: one", "-H", "second: two", "attach", fmt.Sprintf("http://localhost:%d", port))
|
||||
// This is fixed in a follow-up PR.
|
||||
}
|
||||
|
||||
// TestAttachWithHeaders tests that 'geth db --remotedb' with custom headers works, i.e
|
||||
// that custom headers are forwarded to the target.
|
||||
func TestRemoteDbWithHeaders(t *testing.T) {
|
||||
t.Parallel()
|
||||
ln, err := net.Listen("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
port := ln.Addr().(*net.TCPAddr).Port
|
||||
testReceiveHeaders(t, ln, "db", "metadata", "--remotedb", fmt.Sprintf("http://localhost:%d", port), "-H", "first: one", "-H", "second: two")
|
||||
}
|
||||
|
||||
func testReceiveHeaders(t *testing.T, ln net.Listener, gethArgs ...string) {
|
||||
var ok uint32
|
||||
server := &http.Server{
|
||||
Addr: "localhost:0",
|
||||
Handler: &testHandler{func(w http.ResponseWriter, r *http.Request) {
|
||||
// We expect two headers
|
||||
if have, want := r.Header.Get("first"), "one"; have != want {
|
||||
t.Fatalf("missing header, have %v want %v", have, want)
|
||||
}
|
||||
if have, want := r.Header.Get("second"), "two"; have != want {
|
||||
t.Fatalf("missing header, have %v want %v", have, want)
|
||||
}
|
||||
atomic.StoreUint32(&ok, 1)
|
||||
}}}
|
||||
go server.Serve(ln)
|
||||
defer server.Close()
|
||||
runGeth(t, gethArgs...).WaitExit()
|
||||
if atomic.LoadUint32(&ok) != 1 {
|
||||
t.Fatal("Test fail, expected invocation to succeed")
|
||||
}
|
||||
}
|
||||
+47
-13
@@ -39,6 +39,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -48,7 +49,7 @@ var (
|
||||
Name: "init",
|
||||
Usage: "Bootstrap and initialize a new genesis block",
|
||||
ArgsUsage: "<genesisPath>",
|
||||
Flags: utils.DatabasePathFlags,
|
||||
Flags: flags.Merge([]cli.Flag{utils.CachePreimagesFlag}, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
The init command initializes a new genesis block and definition for the network.
|
||||
This is a destructive action and changes the network in which you will be
|
||||
@@ -61,9 +62,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,
|
||||
@@ -187,12 +189,16 @@ func initGenesis(ctx *cli.Context) error {
|
||||
// Open and initialise both full and light databases
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
for _, name := range []string{"chaindata", "lightchaindata"} {
|
||||
chaindb, err := stack.OpenDatabaseWithFreezer(name, 0, 0, ctx.String(utils.AncientFlag.Name), "", false)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to open database: %v", err)
|
||||
}
|
||||
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
|
||||
triedb := trie.NewDatabaseWithConfig(chaindb, &trie.Config{
|
||||
Preimages: ctx.Bool(utils.CachePreimagesFlag.Name),
|
||||
})
|
||||
_, hash, err := core.SetupGenesisBlock(chaindb, triedb, genesis)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to write genesis block: %v", err)
|
||||
}
|
||||
@@ -203,14 +209,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
|
||||
}
|
||||
if err := json.NewEncoder(os.Stdout).Encode(genesis); err != nil {
|
||||
utils.Fatalf("could not encode genesis")
|
||||
// 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 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
|
||||
}
|
||||
|
||||
@@ -226,7 +257,7 @@ func importChain(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
chain, db := utils.MakeChain(ctx, stack)
|
||||
chain, db := utils.MakeChain(ctx, stack, false)
|
||||
defer db.Close()
|
||||
|
||||
// Start periodically gathering memory profiles
|
||||
@@ -301,7 +332,7 @@ func exportChain(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
chain, _ := utils.MakeChain(ctx, stack)
|
||||
chain, _ := utils.MakeChain(ctx, stack, true)
|
||||
start := time.Now()
|
||||
|
||||
var err error
|
||||
@@ -434,7 +465,10 @@ func dump(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
state, err := state.New(root, state.NewDatabase(db), nil)
|
||||
config := &trie.Config{
|
||||
Preimages: true, // always enable preimage lookup
|
||||
}
|
||||
state, err := state.New(root, state.NewDatabaseWithConfig(db, config), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+12
-27
@@ -31,10 +31,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
||||
"github.com/ethereum/go-ethereum/accounts/usbwallet"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/internal/version"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
@@ -108,9 +109,10 @@ func loadConfig(file string, cfg *gethConfig) error {
|
||||
}
|
||||
|
||||
func defaultNodeConfig() node.Config {
|
||||
git, _ := version.VCS()
|
||||
cfg := node.DefaultConfig
|
||||
cfg.Name = clientIdentifier
|
||||
cfg.Version = params.VersionWithCommit(gitCommit, gitDate)
|
||||
cfg.Version = params.VersionWithCommit(git.Commit, git.Date)
|
||||
cfg.HTTPModules = append(cfg.HTTPModules, "eth")
|
||||
cfg.WSModules = append(cfg.WSModules, "eth")
|
||||
cfg.IPCPath = "geth.ipc"
|
||||
@@ -156,34 +158,12 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
|
||||
// makeFullNode loads geth configuration and creates the Ethereum backend.
|
||||
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
stack, cfg := makeConfigNode(ctx)
|
||||
if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) {
|
||||
cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name)
|
||||
if ctx.IsSet(utils.OverrideShanghai.Name) {
|
||||
v := ctx.Uint64(utils.OverrideShanghai.Name)
|
||||
cfg.Eth.OverrideShanghai = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideTerminalTotalDifficultyPassed.Name) {
|
||||
override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name)
|
||||
cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override
|
||||
}
|
||||
|
||||
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
|
||||
|
||||
// Warn users to migrate if they have a legacy freezer format.
|
||||
if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) {
|
||||
firstIdx := uint64(0)
|
||||
// Hack to speed up check for mainnet because we know
|
||||
// the first non-empty block.
|
||||
ghash := rawdb.ReadCanonicalHash(eth.ChainDb(), 0)
|
||||
if cfg.Eth.NetworkId == 1 && ghash == params.MainnetGenesisHash {
|
||||
firstIdx = 46147
|
||||
}
|
||||
isLegacy, _, err := dbHasLegacyReceipts(eth.ChainDb(), firstIdx)
|
||||
if err != nil {
|
||||
log.Error("Failed to check db for legacy receipts", "err", err)
|
||||
} else if isLegacy {
|
||||
stack.Close()
|
||||
utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.")
|
||||
}
|
||||
}
|
||||
|
||||
// Configure log filter RPC API.
|
||||
filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth)
|
||||
|
||||
@@ -196,6 +176,11 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
if cfg.Ethstats.URL != "" {
|
||||
utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL)
|
||||
}
|
||||
|
||||
// Configure full-sync tester service if requested
|
||||
if ctx.IsSet(utils.SyncTargetFlag.Name) && cfg.Eth.SyncMode == downloader.FullSync {
|
||||
utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name))
|
||||
}
|
||||
return stack, backend
|
||||
}
|
||||
|
||||
|
||||
+4
-21
@@ -23,8 +23,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/console"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -47,7 +45,7 @@ See https://geth.ethereum.org/docs/interface/javascript-console.`,
|
||||
Name: "attach",
|
||||
Usage: "Start an interactive JavaScript environment (connect to node)",
|
||||
ArgsUsage: "[endpoint]",
|
||||
Flags: flags.Merge([]cli.Flag{utils.DataDirFlag}, consoleFlags),
|
||||
Flags: flags.Merge([]cli.Flag{utils.DataDirFlag, utils.HttpHeaderFlag}, consoleFlags),
|
||||
Description: `
|
||||
The Geth console is an interactive shell for the JavaScript runtime environment
|
||||
which exposes a node admin interface as well as the Ðapp JavaScript API.
|
||||
@@ -79,7 +77,7 @@ func localConsole(ctx *cli.Context) error {
|
||||
// Attach to the newly started node and create the JavaScript console.
|
||||
client, err := stack.Attach()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to attach to the inproc geth: %v", err)
|
||||
return fmt.Errorf("failed to attach to the inproc geth: %v", err)
|
||||
}
|
||||
config := console.Config{
|
||||
DataDir: utils.MakeDataDir(ctx),
|
||||
@@ -89,7 +87,7 @@ func localConsole(ctx *cli.Context) error {
|
||||
}
|
||||
console, err := console.New(config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to start the JavaScript console: %v", err)
|
||||
return fmt.Errorf("failed to start the JavaScript console: %v", err)
|
||||
}
|
||||
defer console.Stop(false)
|
||||
|
||||
@@ -118,14 +116,13 @@ func remoteConsole(ctx *cli.Context) error {
|
||||
if ctx.Args().Len() > 1 {
|
||||
utils.Fatalf("invalid command-line: too many arguments")
|
||||
}
|
||||
|
||||
endpoint := ctx.Args().First()
|
||||
if endpoint == "" {
|
||||
cfg := defaultNodeConfig()
|
||||
utils.SetDataDir(ctx, &cfg)
|
||||
endpoint = cfg.IPCEndpoint()
|
||||
}
|
||||
client, err := dialRPC(endpoint)
|
||||
client, err := utils.DialRPCWithHeaders(endpoint, ctx.StringSlice(utils.HttpHeaderFlag.Name))
|
||||
if err != nil {
|
||||
utils.Fatalf("Unable to attach to remote geth: %v", err)
|
||||
}
|
||||
@@ -164,17 +161,3 @@ func ephemeralConsole(ctx *cli.Context) error {
|
||||
geth --exec "%s" console`, b.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
// dialRPC returns a RPC client which connects to the given endpoint.
|
||||
// The check for empty endpoint implements the defaulting logic
|
||||
// for "geth attach" with no argument.
|
||||
func dialRPC(endpoint string) (*rpc.Client, error) {
|
||||
if endpoint == "" {
|
||||
endpoint = node.DefaultIPCEndpoint(clientIdentifier)
|
||||
} else if strings.HasPrefix(endpoint, "rpc:") || strings.HasPrefix(endpoint, "ipc:") {
|
||||
// Backwards compatibility with geth < 1.5 which required
|
||||
// these prefixes.
|
||||
endpoint = endpoint[4:]
|
||||
}
|
||||
return rpc.Dial(endpoint)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
ipcAPIs = "admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
@@ -38,10 +38,10 @@ const (
|
||||
// memory and disk IO. If the args don't set --datadir, the
|
||||
// child g gets a temporary data directory.
|
||||
func runMinimalGeth(t *testing.T, args ...string) *testgeth {
|
||||
// --ropsten to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --goerli to make the 'writing genesis to disk' faster (no accounts)
|
||||
// --networkid=1337 to avoid cache bump
|
||||
// --syncmode=full to avoid allocating fast sync bloom
|
||||
allArgs := []string{"--ropsten", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
allArgs := []string{"--goerli", "--networkid", "1337", "--authrpc.port", "0", "--syncmode=full", "--port", "0",
|
||||
"--nat", "none", "--nodiscover", "--maxpeers", "0", "--cache", "64",
|
||||
"--datadir.minfreedisk", "0"}
|
||||
return runGeth(t, append(allArgs, args...)...)
|
||||
@@ -61,7 +61,7 @@ func TestConsoleWelcome(t *testing.T) {
|
||||
geth.SetTemplateFunc("gover", runtime.Version)
|
||||
geth.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
geth.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
geth.SetTemplateFunc("apis", func() string { return ipcAPIs })
|
||||
|
||||
@@ -120,7 +120,7 @@ func TestAttachWelcome(t *testing.T) {
|
||||
}
|
||||
|
||||
func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
||||
// Attach to a running geth note and terminate immediately
|
||||
// Attach to a running geth node and terminate immediately
|
||||
attach := runGeth(t, "attach", endpoint)
|
||||
defer attach.ExpectExit()
|
||||
attach.CloseStdin()
|
||||
@@ -132,7 +132,7 @@ func testAttachWelcome(t *testing.T, geth *testgeth, endpoint, apis string) {
|
||||
attach.SetTemplateFunc("gethver", func() string { return params.VersionWithCommit("", "") })
|
||||
attach.SetTemplateFunc("etherbase", func() string { return geth.Etherbase })
|
||||
attach.SetTemplateFunc("niltime", func() string {
|
||||
return time.Unix(0, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
return time.Unix(1548854791, 0).Format("Mon Jan 02 2006 15:04:05 GMT-0700 (MST)")
|
||||
})
|
||||
attach.SetTemplateFunc("ipc", func() bool { return strings.HasPrefix(endpoint, "ipc") })
|
||||
attach.SetTemplateFunc("datadir", func() string { return geth.Datadir })
|
||||
|
||||
+27
-122
@@ -33,7 +33,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/console/prompt"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
@@ -69,7 +68,6 @@ Remove blockchain and state databases`,
|
||||
dbImportCmd,
|
||||
dbExportCmd,
|
||||
dbMetadataCmd,
|
||||
dbMigrateFreezerCmd,
|
||||
dbCheckStateContentCmd,
|
||||
},
|
||||
}
|
||||
@@ -150,7 +148,7 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||
Action: dbDumpTrie,
|
||||
Name: "dumptrie",
|
||||
Usage: "Show the storage key/values of a given storage trie",
|
||||
ArgsUsage: "<hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
|
||||
ArgsUsage: "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.SyncModeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
@@ -195,17 +193,6 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: "Shows metadata about the chain status.",
|
||||
}
|
||||
dbMigrateFreezerCmd = &cli.Command{
|
||||
Action: freezerMigrate,
|
||||
Name: "freezer-migrate",
|
||||
Usage: "Migrate legacy parts of the freezer. (WARNING: may take a long time)",
|
||||
ArgsUsage: "",
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.SyncModeFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `The freezer-migrate command checks your database for receipts in a legacy format and updates those.
|
||||
WARNING: please back-up the receipt files in your ancients before running this command.`,
|
||||
}
|
||||
)
|
||||
|
||||
func removeDB(ctx *cli.Context) error {
|
||||
@@ -486,7 +473,7 @@ func dbPut(ctx *cli.Context) error {
|
||||
|
||||
// dbDumpTrie shows the key-value slots of a given storage trie
|
||||
func dbDumpTrie(ctx *cli.Context) error {
|
||||
if ctx.NArg() < 1 {
|
||||
if ctx.NArg() < 3 {
|
||||
return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
|
||||
}
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
@@ -494,30 +481,41 @@ func dbDumpTrie(ctx *cli.Context) error {
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
var (
|
||||
root []byte
|
||||
start []byte
|
||||
max = int64(-1)
|
||||
err error
|
||||
state []byte
|
||||
storage []byte
|
||||
account []byte
|
||||
start []byte
|
||||
max = int64(-1)
|
||||
err error
|
||||
)
|
||||
if root, err = hexutil.Decode(ctx.Args().Get(0)); err != nil {
|
||||
log.Info("Could not decode the root", "error", err)
|
||||
if state, err = hexutil.Decode(ctx.Args().Get(0)); err != nil {
|
||||
log.Info("Could not decode the state root", "error", err)
|
||||
return err
|
||||
}
|
||||
stRoot := common.BytesToHash(root)
|
||||
if ctx.NArg() >= 2 {
|
||||
if start, err = hexutil.Decode(ctx.Args().Get(1)); err != nil {
|
||||
if account, err = hexutil.Decode(ctx.Args().Get(1)); err != nil {
|
||||
log.Info("Could not decode the account hash", "error", err)
|
||||
return err
|
||||
}
|
||||
if storage, err = hexutil.Decode(ctx.Args().Get(2)); err != nil {
|
||||
log.Info("Could not decode the storage trie root", "error", err)
|
||||
return err
|
||||
}
|
||||
if ctx.NArg() > 3 {
|
||||
if start, err = hexutil.Decode(ctx.Args().Get(3)); err != nil {
|
||||
log.Info("Could not decode the seek position", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if ctx.NArg() >= 3 {
|
||||
if max, err = strconv.ParseInt(ctx.Args().Get(2), 10, 64); err != nil {
|
||||
if ctx.NArg() > 4 {
|
||||
if max, err = strconv.ParseInt(ctx.Args().Get(4), 10, 64); err != nil {
|
||||
log.Info("Could not decode the max count", "error", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
theTrie, err := trie.New(common.Hash{}, stRoot, trie.NewDatabase(db))
|
||||
id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage))
|
||||
theTrie, err := trie.New(id, trie.NewDatabase(db))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -553,16 +551,8 @@ func freezerInspect(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
ancient, err := db.AncientDatadir()
|
||||
if err != nil {
|
||||
log.Info("Failed to retrieve ancient root", "err", err)
|
||||
return err
|
||||
}
|
||||
ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name))
|
||||
stack.Close()
|
||||
return rawdb.InspectFreezerTable(ancient, freezer, table, start, end)
|
||||
}
|
||||
|
||||
@@ -745,88 +735,3 @@ func showMetaData(ctx *cli.Context) error {
|
||||
table.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func freezerMigrate(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, false)
|
||||
defer db.Close()
|
||||
|
||||
// Check first block for legacy receipt format
|
||||
numAncients, err := db.Ancients()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if numAncients < 1 {
|
||||
log.Info("No receipts in freezer to migrate")
|
||||
return nil
|
||||
}
|
||||
|
||||
isFirstLegacy, firstIdx, err := dbHasLegacyReceipts(db, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !isFirstLegacy {
|
||||
log.Info("No legacy receipts to migrate")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Info("Starting migration", "ancients", numAncients, "firstLegacy", firstIdx)
|
||||
start := time.Now()
|
||||
if err := db.MigrateTable("receipts", types.ConvertLegacyStoredReceipts); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := db.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Migration finished", "duration", time.Since(start))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbHasLegacyReceipts checks freezer entries for legacy receipts. It stops at the first
|
||||
// non-empty receipt and checks its format. The index of this first non-empty element is
|
||||
// the second return parameter.
|
||||
func dbHasLegacyReceipts(db ethdb.Database, firstIdx uint64) (bool, uint64, error) {
|
||||
// Check first block for legacy receipt format
|
||||
numAncients, err := db.Ancients()
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
if numAncients < 1 {
|
||||
return false, 0, nil
|
||||
}
|
||||
if firstIdx >= numAncients {
|
||||
return false, firstIdx, nil
|
||||
}
|
||||
var (
|
||||
legacy bool
|
||||
blob []byte
|
||||
emptyRLPList = []byte{192}
|
||||
)
|
||||
// Find first block with non-empty receipt, only if
|
||||
// the index is not already provided.
|
||||
if firstIdx == 0 {
|
||||
for i := uint64(0); i < numAncients; i++ {
|
||||
blob, err = db.Ancient("receipts", i)
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
if len(blob) == 0 {
|
||||
continue
|
||||
}
|
||||
if !bytes.Equal(blob, emptyRLPList) {
|
||||
firstIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Is first non-empty receipt legacy?
|
||||
first, err := db.Ancient("receipts", firstIdx)
|
||||
if err != nil {
|
||||
return false, 0, err
|
||||
}
|
||||
legacy, err = types.IsLegacyStoredReceipts(first)
|
||||
return legacy, firstIdx, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright 2022 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// TestExport does a basic test of "geth export", exporting the test-genesis.
|
||||
func TestExport(t *testing.T) {
|
||||
outfile := fmt.Sprintf("%v/testExport.out", os.TempDir())
|
||||
defer os.Remove(outfile)
|
||||
geth := runGeth(t, "--datadir", initGeth(t), "export", outfile)
|
||||
geth.WaitExit()
|
||||
if have, want := geth.ExitStatus(), 0; have != want {
|
||||
t.Errorf("exit error, have %d want %d", have, want)
|
||||
}
|
||||
have, err := os.ReadFile(outfile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := common.FromHex("0xf9026bf90266a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a08758259b018f7bce3d2be2ddb62f325eaeea0a0c188cf96623eab468a4413e03a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180837a12008080b875000000000000000000000000000000000000000000000000000000000000000002f0d131f1f97aef08aec6e3291b957d9efe71050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000880000000000000000c0c0")
|
||||
if !bytes.Equal(have, want) {
|
||||
t.Fatalf("wrong content exported")
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -70,6 +72,7 @@ var customGenesisTests = []struct {
|
||||
// Tests that initializing Geth with a custom genesis block and chain definitions
|
||||
// work properly.
|
||||
func TestCustomGenesis(t *testing.T) {
|
||||
t.Parallel()
|
||||
for i, tt := range customGenesisTests {
|
||||
// Create a temporary data directory to use and inspect later
|
||||
datadir := t.TempDir()
|
||||
@@ -90,3 +93,101 @@ func TestCustomGenesis(t *testing.T) {
|
||||
geth.ExpectExit()
|
||||
}
|
||||
}
|
||||
|
||||
// TestCustomBackend that the backend selection and detection (leveldb vs pebble) works properly.
|
||||
func TestCustomBackend(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Test pebble, but only on 64-bit platforms
|
||||
if strconv.IntSize != 64 {
|
||||
t.Skip("Custom backends are only available on 64-bit platform")
|
||||
}
|
||||
genesis := `{
|
||||
"alloc" : {},
|
||||
"coinbase" : "0x0000000000000000000000000000000000000000",
|
||||
"difficulty" : "0x20000",
|
||||
"extraData" : "",
|
||||
"gasLimit" : "0x2fefd8",
|
||||
"nonce" : "0x0000000000001338",
|
||||
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
"timestamp" : "0x00",
|
||||
"config" : {}
|
||||
}`
|
||||
type backendTest struct {
|
||||
initArgs []string
|
||||
initExpect string
|
||||
execArgs []string
|
||||
execExpect string
|
||||
}
|
||||
testfunc := func(t *testing.T, tt backendTest) error {
|
||||
// Create a temporary data directory to use and inspect later
|
||||
datadir := t.TempDir()
|
||||
|
||||
// Initialize the data directory with the custom genesis block
|
||||
json := filepath.Join(datadir, "genesis.json")
|
||||
if err := os.WriteFile(json, []byte(genesis), 0600); err != nil {
|
||||
return fmt.Errorf("failed to write genesis file: %v", err)
|
||||
}
|
||||
{ // Init
|
||||
args := append(tt.initArgs, "--datadir", datadir, "init", json)
|
||||
geth := runGeth(t, args...)
|
||||
geth.ExpectRegexp(tt.initExpect)
|
||||
geth.ExpectExit()
|
||||
}
|
||||
{ // Exec + query
|
||||
args := append(tt.execArgs, "--networkid", "1337", "--syncmode=full", "--cache", "16",
|
||||
"--datadir", datadir, "--maxpeers", "0", "--port", "0", "--authrpc.port", "0",
|
||||
"--nodiscover", "--nat", "none", "--ipcdisable",
|
||||
"--exec", "eth.getBlock(0).nonce", "console")
|
||||
geth := runGeth(t, args...)
|
||||
geth.ExpectRegexp(tt.execExpect)
|
||||
geth.ExpectExit()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
for i, tt := range []backendTest{
|
||||
{ // When not specified, it should default to leveldb
|
||||
execArgs: []string{"--db.engine", "leveldb"},
|
||||
execExpect: "0x0000000000001338",
|
||||
},
|
||||
{ // Explicit leveldb
|
||||
initArgs: []string{"--db.engine", "leveldb"},
|
||||
execArgs: []string{"--db.engine", "leveldb"},
|
||||
execExpect: "0x0000000000001338",
|
||||
},
|
||||
{ // Explicit leveldb first, then autodiscover
|
||||
initArgs: []string{"--db.engine", "leveldb"},
|
||||
execExpect: "0x0000000000001338",
|
||||
},
|
||||
{ // Explicit pebble
|
||||
initArgs: []string{"--db.engine", "pebble"},
|
||||
execArgs: []string{"--db.engine", "pebble"},
|
||||
execExpect: "0x0000000000001338",
|
||||
},
|
||||
{ // Explicit pebble, then auto-discover
|
||||
initArgs: []string{"--db.engine", "pebble"},
|
||||
execExpect: "0x0000000000001338",
|
||||
},
|
||||
{ // Can't start pebble on top of leveldb
|
||||
initArgs: []string{"--db.engine", "leveldb"},
|
||||
execArgs: []string{"--db.engine", "pebble"},
|
||||
execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was pebble but found pre-existing leveldb database in specified data directory`,
|
||||
},
|
||||
{ // Can't start leveldb on top of pebble
|
||||
initArgs: []string{"--db.engine", "pebble"},
|
||||
execArgs: []string{"--db.engine", "leveldb"},
|
||||
execExpect: `Fatal: Failed to register the Ethereum service: db.engine choice was leveldb but found pre-existing pebble database in specified data directory`,
|
||||
},
|
||||
{ // Reject invalid backend choice
|
||||
initArgs: []string{"--db.engine", "mssql"},
|
||||
initExpect: `Fatal: Invalid choice for db.engine 'mssql', allowed 'leveldb' or 'pebble'`,
|
||||
// Since the init fails, this will return the (default) mainnet genesis
|
||||
// block nonce
|
||||
execExpect: `0x0000000000000042`,
|
||||
},
|
||||
} {
|
||||
if err := testfunc(t, tt); err != nil {
|
||||
t.Fatalf("test %d-leveldb: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ func startLightServer(t *testing.T) *gethrpc {
|
||||
t.Logf("Importing keys to geth")
|
||||
runGeth(t, "account", "import", "--datadir", datadir, "--password", "./testdata/password.txt", "--lightkdf", "./testdata/key.prv").WaitExit()
|
||||
account := "0x02f0d131f1f97aef08aec6e3291b957d9efe7105"
|
||||
server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4")
|
||||
server := startGethWithIpc(t, "lightserver", "--allow-insecure-unlock", "--datadir", datadir, "--password", "./testdata/password.txt", "--unlock", account, "--miner.etherbase=0x02f0d131f1f97aef08aec6e3291b957d9efe7105", "--mine", "--light.serve=100", "--light.maxpeers=1", "--nodiscover", "--nat=extip:127.0.0.1", "--verbosity=4")
|
||||
return server
|
||||
}
|
||||
|
||||
|
||||
+11
-20
@@ -55,11 +55,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Git SHA1 commit hash of the release (set via linker flags)
|
||||
gitCommit = ""
|
||||
gitDate = ""
|
||||
// The app that holds all commands and flags.
|
||||
app = flags.NewApp(gitCommit, gitDate, "the go-ethereum command line interface")
|
||||
// flags that configure the node
|
||||
nodeFlags = flags.Merge([]cli.Flag{
|
||||
utils.IdentityFlag,
|
||||
@@ -72,8 +67,8 @@ var (
|
||||
utils.NoUSBFlag,
|
||||
utils.USBFlag,
|
||||
utils.SmartCardDaemonPathFlag,
|
||||
utils.OverrideTerminalTotalDifficulty,
|
||||
utils.OverrideTerminalTotalDifficultyPassed,
|
||||
utils.OverrideShanghai,
|
||||
utils.EnablePersonal,
|
||||
utils.EthashCacheDirFlag,
|
||||
utils.EthashCachesInMemoryFlag,
|
||||
utils.EthashCachesOnDiskFlag,
|
||||
@@ -94,6 +89,7 @@ var (
|
||||
utils.TxPoolGlobalQueueFlag,
|
||||
utils.TxPoolLifetimeFlag,
|
||||
utils.SyncModeFlag,
|
||||
utils.SyncTargetFlag,
|
||||
utils.ExitWhenSyncedFlag,
|
||||
utils.GCModeFlag,
|
||||
utils.SnapshotFlag,
|
||||
@@ -129,13 +125,13 @@ var (
|
||||
utils.MiningEnabledFlag,
|
||||
utils.MinerThreadsFlag,
|
||||
utils.MinerNotifyFlag,
|
||||
utils.LegacyMinerGasTargetFlag,
|
||||
utils.MinerGasLimitFlag,
|
||||
utils.MinerGasPriceFlag,
|
||||
utils.MinerEtherbaseFlag,
|
||||
utils.MinerExtraDataFlag,
|
||||
utils.MinerRecommitIntervalFlag,
|
||||
utils.MinerNoVerifyFlag,
|
||||
utils.MinerNewPayloadTimeout,
|
||||
utils.NATFlag,
|
||||
utils.NoDiscoverFlag,
|
||||
utils.DiscoveryV5Flag,
|
||||
@@ -156,7 +152,6 @@ var (
|
||||
utils.GpoMaxGasPriceFlag,
|
||||
utils.GpoIgnoreGasPriceFlag,
|
||||
utils.MinerNotifyFullFlag,
|
||||
utils.IgnoreLegacyReceiptsFlag,
|
||||
configFileFlag,
|
||||
}, utils.NetworkFlags, utils.DatabasePathFlags)
|
||||
|
||||
@@ -208,11 +203,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
var app = flags.NewApp("the go-ethereum command line interface")
|
||||
|
||||
func init() {
|
||||
// Initialize the CLI app and start Geth
|
||||
app.Action = geth
|
||||
app.HideVersion = true // we have a command to print the version
|
||||
app.Copyright = "Copyright 2013-2022 The go-ethereum Authors"
|
||||
app.Copyright = "Copyright 2013-2023 The go-ethereum Authors"
|
||||
app.Commands = []*cli.Command{
|
||||
// See chaincmd.go:
|
||||
initCommand,
|
||||
@@ -244,6 +241,8 @@ func init() {
|
||||
utils.ShowDeprecated,
|
||||
// See snapshot.go
|
||||
snapshotCommand,
|
||||
// See verkle.go
|
||||
verkleCommand,
|
||||
}
|
||||
sort.Sort(cli.CommandsByName(app.Commands))
|
||||
|
||||
@@ -278,9 +277,6 @@ func main() {
|
||||
func prepare(ctx *cli.Context) {
|
||||
// If we're running a known preset, log it for convenience.
|
||||
switch {
|
||||
case ctx.IsSet(utils.RopstenFlag.Name):
|
||||
log.Info("Starting Geth on Ropsten testnet...")
|
||||
|
||||
case ctx.IsSet(utils.RinkebyFlag.Name):
|
||||
log.Info("Starting Geth on Rinkeby testnet...")
|
||||
|
||||
@@ -290,9 +286,6 @@ func prepare(ctx *cli.Context) {
|
||||
case ctx.IsSet(utils.SepoliaFlag.Name):
|
||||
log.Info("Starting Geth on Sepolia testnet...")
|
||||
|
||||
case ctx.IsSet(utils.KilnFlag.Name):
|
||||
log.Info("Starting Geth on Kiln testnet...")
|
||||
|
||||
case ctx.IsSet(utils.DeveloperFlag.Name):
|
||||
log.Info("Starting Geth in ephemeral dev mode...")
|
||||
log.Warn(`You are running Geth in --dev mode. Please note the following:
|
||||
@@ -317,11 +310,9 @@ func prepare(ctx *cli.Context) {
|
||||
// If we're a full node on mainnet without --cache specified, bump default cache allowance
|
||||
if ctx.String(utils.SyncModeFlag.Name) != "light" && !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {
|
||||
// Make sure we're not on any supported preconfigured testnet either
|
||||
if !ctx.IsSet(utils.RopstenFlag.Name) &&
|
||||
!ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||
if !ctx.IsSet(utils.SepoliaFlag.Name) &&
|
||||
!ctx.IsSet(utils.RinkebyFlag.Name) &&
|
||||
!ctx.IsSet(utils.GoerliFlag.Name) &&
|
||||
!ctx.IsSet(utils.KilnFlag.Name) &&
|
||||
!ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||
// Nope, we're really on mainnet. Bump that cache up!
|
||||
log.Info("Bumping default cache on mainnet", "provided", ctx.Int(utils.CacheFlag.Name), "updated", 4096)
|
||||
@@ -341,7 +332,7 @@ func prepare(ctx *cli.Context) {
|
||||
go metrics.CollectProcessMetrics(3 * time.Second)
|
||||
}
|
||||
|
||||
// geth is the main entry point into the system if no special subcommand is ran.
|
||||
// geth is the main entry point into the system if no special subcommand is run.
|
||||
// It creates a default node based on the command line arguments and runs it in
|
||||
// blocking mode, waiting for it to be shut down.
|
||||
func geth(ctx *cli.Context) error {
|
||||
|
||||
+10
-9
@@ -25,6 +25,7 @@ import (
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/internal/version"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -38,9 +39,7 @@ var (
|
||||
VersionCheckVersionFlag = &cli.StringFlag{
|
||||
Name: "check.version",
|
||||
Usage: "Version to check",
|
||||
Value: fmt.Sprintf("Geth/v%v/%v-%v/%v",
|
||||
params.VersionWithCommit(gitCommit, gitDate),
|
||||
runtime.GOOS, runtime.GOARCH, runtime.Version()),
|
||||
Value: version.ClientName(clientIdentifier),
|
||||
}
|
||||
makecacheCommand = &cli.Command{
|
||||
Action: makecache,
|
||||
@@ -67,7 +66,7 @@ Regular users do not need to execute it.
|
||||
`,
|
||||
}
|
||||
versionCommand = &cli.Command{
|
||||
Action: version,
|
||||
Action: printVersion,
|
||||
Name: "version",
|
||||
Usage: "Print version numbers",
|
||||
ArgsUsage: " ",
|
||||
@@ -127,14 +126,16 @@ func makedag(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func version(ctx *cli.Context) error {
|
||||
func printVersion(ctx *cli.Context) error {
|
||||
git, _ := version.VCS()
|
||||
|
||||
fmt.Println(strings.Title(clientIdentifier))
|
||||
fmt.Println("Version:", params.VersionWithMeta)
|
||||
if gitCommit != "" {
|
||||
fmt.Println("Git Commit:", gitCommit)
|
||||
if git.Commit != "" {
|
||||
fmt.Println("Git Commit:", git.Commit)
|
||||
}
|
||||
if gitDate != "" {
|
||||
fmt.Println("Git Commit Date:", gitDate)
|
||||
if git.Date != "" {
|
||||
fmt.Println("Git Commit Date:", git.Date)
|
||||
}
|
||||
fmt.Println("Architecture:", runtime.GOARCH)
|
||||
fmt.Println("Go Version:", runtime.Version())
|
||||
|
||||
+35
-10
@@ -165,12 +165,21 @@ block is used.
|
||||
}
|
||||
)
|
||||
|
||||
// Deprecation: this command should be deprecated once the hash-based
|
||||
// scheme is deprecated.
|
||||
func pruneState(ctx *cli.Context) error {
|
||||
stack, config := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, false)
|
||||
pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.Uint64(utils.BloomFilterSizeFlag.Name))
|
||||
defer chaindb.Close()
|
||||
|
||||
prunerconfig := pruner.Config{
|
||||
Datadir: stack.ResolvePath(""),
|
||||
Cachedir: stack.ResolvePath(config.Eth.TrieCleanCacheJournal),
|
||||
BloomSize: ctx.Uint64(utils.BloomFilterSizeFlag.Name),
|
||||
}
|
||||
pruner, err := pruner.NewPruner(chaindb, prunerconfig)
|
||||
if err != nil {
|
||||
log.Error("Failed to open snapshot tree", "err", err)
|
||||
return err
|
||||
@@ -199,12 +208,20 @@ func verifyState(ctx *cli.Context) error {
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer chaindb.Close()
|
||||
|
||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||
if headBlock == nil {
|
||||
log.Error("Failed to load head block")
|
||||
return errors.New("no head block")
|
||||
}
|
||||
snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false)
|
||||
snapconfig := snapshot.Config{
|
||||
CacheSize: 256,
|
||||
Recovery: false,
|
||||
NoBuild: true,
|
||||
AsyncBuild: false,
|
||||
}
|
||||
snaptree, err := snapshot.New(snapconfig, chaindb, trie.NewDatabase(chaindb), headBlock.Root())
|
||||
if err != nil {
|
||||
log.Error("Failed to open snapshot tree", "err", err)
|
||||
return err
|
||||
@@ -271,7 +288,7 @@ func traverseState(ctx *cli.Context) error {
|
||||
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||
}
|
||||
triedb := trie.NewDatabase(chaindb)
|
||||
t, err := trie.NewStateTrie(common.Hash{}, root, triedb)
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open trie", "root", root, "err", err)
|
||||
return err
|
||||
@@ -292,7 +309,8 @@ func traverseState(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
if acc.Root != emptyRoot {
|
||||
storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.Key), acc.Root, triedb)
|
||||
id := trie.StorageTrieID(root, common.BytesToHash(accIter.Key), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
|
||||
return err
|
||||
@@ -360,7 +378,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
|
||||
}
|
||||
triedb := trie.NewDatabase(chaindb)
|
||||
t, err := trie.NewStateTrie(common.Hash{}, root, triedb)
|
||||
t, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open trie", "root", root, "err", err)
|
||||
return err
|
||||
@@ -383,7 +401,7 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
// Check the present for non-empty hash node(embedded node doesn't
|
||||
// have their own hash).
|
||||
if node != (common.Hash{}) {
|
||||
blob := rawdb.ReadTrieNode(chaindb, node)
|
||||
blob := rawdb.ReadLegacyTrieNode(chaindb, node)
|
||||
if len(blob) == 0 {
|
||||
log.Error("Missing trie node(account)", "hash", node)
|
||||
return errors.New("missing account")
|
||||
@@ -406,7 +424,8 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
return errors.New("invalid account")
|
||||
}
|
||||
if acc.Root != emptyRoot {
|
||||
storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb)
|
||||
id := trie.StorageTrieID(root, common.BytesToHash(accIter.LeafKey()), acc.Root)
|
||||
storageTrie, err := trie.NewStateTrie(id, triedb)
|
||||
if err != nil {
|
||||
log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
|
||||
return errors.New("missing storage trie")
|
||||
@@ -416,10 +435,10 @@ func traverseRawState(ctx *cli.Context) error {
|
||||
nodes += 1
|
||||
node := storageIter.Hash()
|
||||
|
||||
// Check the present for non-empty hash node(embedded node doesn't
|
||||
// Check the presence for non-empty hash node(embedded node doesn't
|
||||
// have their own hash).
|
||||
if node != (common.Hash{}) {
|
||||
blob := rawdb.ReadTrieNode(chaindb, node)
|
||||
blob := rawdb.ReadLegacyTrieNode(chaindb, node)
|
||||
if len(blob) == 0 {
|
||||
log.Error("Missing trie node(storage)", "hash", node)
|
||||
return errors.New("missing storage")
|
||||
@@ -479,7 +498,13 @@ func dumpState(ctx *cli.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, root, false, false, false)
|
||||
snapConfig := snapshot.Config{
|
||||
CacheSize: 256,
|
||||
Recovery: false,
|
||||
NoBuild: true,
|
||||
AsyncBuild: false,
|
||||
}
|
||||
snaptree, err := snapshot.New(snapConfig, db, trie.NewDatabase(db), root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright 2022 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gballet/go-verkle"
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
zero [32]byte
|
||||
|
||||
verkleCommand = &cli.Command{
|
||||
Name: "verkle",
|
||||
Usage: "A set of experimental verkle tree management commands",
|
||||
Description: "",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "verify",
|
||||
Usage: "verify the conversion of a MPT into a verkle tree",
|
||||
ArgsUsage: "<root>",
|
||||
Action: verifyVerkle,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
geth verkle verify <state-root>
|
||||
This command takes a root commitment and attempts to rebuild the tree.
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "dump",
|
||||
Usage: "Dump a verkle tree to a DOT file",
|
||||
ArgsUsage: "<root> <key1> [<key 2> ...]",
|
||||
Action: expandVerkle,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
|
||||
Description: `
|
||||
geth verkle dump <state-root> <key 1> [<key 2> ...]
|
||||
This command will produce a dot file representing the tree, rooted at <root>.
|
||||
in which key1, key2, ... are expanded.
|
||||
`,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// recurse into each child to ensure they can be loaded from the db. The tree isn't rebuilt
|
||||
// (only its nodes are loaded) so there is no need to flush them, the garbage collector should
|
||||
// take care of that for us.
|
||||
func checkChildren(root verkle.VerkleNode, resolver verkle.NodeResolverFn) error {
|
||||
switch node := root.(type) {
|
||||
case *verkle.InternalNode:
|
||||
for i, child := range node.Children() {
|
||||
childC := child.ComputeCommitment().Bytes()
|
||||
|
||||
childS, err := resolver(childC[:])
|
||||
if bytes.Equal(childC[:], zero[:]) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not find child %x in db: %w", childC, err)
|
||||
}
|
||||
// depth is set to 0, the tree isn't rebuilt so it's not a problem
|
||||
childN, err := verkle.ParseNode(childS, 0, childC[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode error child %x in db: %w", child.ComputeCommitment().Bytes(), err)
|
||||
}
|
||||
if err := checkChildren(childN, resolver); err != nil {
|
||||
return fmt.Errorf("%x%w", i, err) // write the path to the erroring node
|
||||
}
|
||||
}
|
||||
case *verkle.LeafNode:
|
||||
// sanity check: ensure at least one value is non-zero
|
||||
|
||||
for i := 0; i < verkle.NodeWidth; i++ {
|
||||
if len(node.Value(i)) != 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Both balance and nonce are 0")
|
||||
case verkle.Empty:
|
||||
// nothing to do
|
||||
default:
|
||||
return fmt.Errorf("unsupported type encountered %v", root)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func verifyVerkle(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||
headBlock := rawdb.ReadHeadBlock(chaindb)
|
||||
if headBlock == nil {
|
||||
log.Error("Failed to load head block")
|
||||
return errors.New("no head block")
|
||||
}
|
||||
if ctx.NArg() > 1 {
|
||||
log.Error("Too many arguments given")
|
||||
return errors.New("too many arguments")
|
||||
}
|
||||
var (
|
||||
rootC common.Hash
|
||||
err error
|
||||
)
|
||||
if ctx.NArg() == 1 {
|
||||
rootC, err = parseRoot(ctx.Args().First())
|
||||
if err != nil {
|
||||
log.Error("Failed to resolve state root", "error", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Rebuilding the tree", "root", rootC)
|
||||
} else {
|
||||
rootC = headBlock.Root()
|
||||
log.Info("Rebuilding the tree", "root", rootC, "number", headBlock.NumberU64())
|
||||
}
|
||||
|
||||
serializedRoot, err := chaindb.Get(rootC[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root, err := verkle.ParseNode(serializedRoot, 0, rootC[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkChildren(root, chaindb.Get); err != nil {
|
||||
log.Error("Could not rebuild the tree from the database", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("Tree was rebuilt from the database")
|
||||
return nil
|
||||
}
|
||||
|
||||
func expandVerkle(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
chaindb := utils.MakeChainDatabase(ctx, stack, true)
|
||||
var (
|
||||
rootC common.Hash
|
||||
keylist [][]byte
|
||||
err error
|
||||
)
|
||||
if ctx.NArg() >= 2 {
|
||||
rootC, err = parseRoot(ctx.Args().First())
|
||||
if err != nil {
|
||||
log.Error("Failed to resolve state root", "error", err)
|
||||
return err
|
||||
}
|
||||
keylist = make([][]byte, 0, ctx.Args().Len()-1)
|
||||
args := ctx.Args().Slice()
|
||||
for i := range args[1:] {
|
||||
key, err := hex.DecodeString(args[i+1])
|
||||
log.Info("decoded key", "arg", args[i+1], "key", key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding key #%d: %w", i+1, err)
|
||||
}
|
||||
keylist = append(keylist, key)
|
||||
}
|
||||
log.Info("Rebuilding the tree", "root", rootC)
|
||||
} else {
|
||||
return fmt.Errorf("usage: %s root key1 [key 2...]", ctx.App.Name)
|
||||
}
|
||||
|
||||
serializedRoot, err := chaindb.Get(rootC[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root, err := verkle.ParseNode(serializedRoot, 0, rootC[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, key := range keylist {
|
||||
log.Info("Reading key", "index", i, "key", keylist[0])
|
||||
root.Get(key, chaindb.Get)
|
||||
}
|
||||
|
||||
if err := os.WriteFile("dump.dot", []byte(verkle.ToDot(root)), 0600); err != nil {
|
||||
log.Error("Failed to dump file", "err", err)
|
||||
} else {
|
||||
log.Info("Tree was dumped to file", "file", "dump.dot")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user