diff --git a/cmd/XDC/chaincmd.go b/cmd/XDC/chaincmd.go
index d6fb97b913..4a5d115572 100644
--- a/cmd/XDC/chaincmd.go
+++ b/cmd/XDC/chaincmd.go
@@ -27,7 +27,6 @@ import (
"github.com/XinFinOrg/XDPoSChain/cmd/utils"
"github.com/XinFinOrg/XDPoSChain/common"
- "github.com/XinFinOrg/XDPoSChain/console"
"github.com/XinFinOrg/XDPoSChain/core"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
@@ -132,19 +131,6 @@ if already existing.`,
},
Description: `
The export-preimages command export hash preimages to an RLP encoded stream`,
- }
- removedbCommand = &cli.Command{
- Action: removeDB,
- Name: "removedb",
- Usage: "Remove blockchain and state databases",
- ArgsUsage: " ",
- Flags: []cli.Flag{
- utils.DataDirFlag,
- utils.XDCXDataDirFlag,
- utils.LightModeFlag,
- },
- Description: `
-Remove blockchain and state databases`,
}
dumpCommand = &cli.Command{
Action: dump,
@@ -224,8 +210,8 @@ func importChain(ctx *cli.Context) error {
// Start metrics export if enabled
utils.SetupMetrics(&cfg.Metrics)
- chain, chainDb := utils.MakeChain(ctx, stack, false)
- defer chainDb.Close()
+ chain, db := utils.MakeChain(ctx, stack, false)
+ defer db.Close()
// Start periodically gathering memory profiles
var peakMemAlloc, peakMemSys uint64
@@ -245,13 +231,17 @@ func importChain(ctx *cli.Context) error {
// Import the chain
start := time.Now()
+ var importErr error
+
if ctx.Args().Len() == 1 {
if err := utils.ImportChain(chain, ctx.Args().First()); err != nil {
+ importErr = err
log.Error("Import error", "err", err)
}
} else {
for _, arg := range ctx.Args().Slice() {
if err := utils.ImportChain(chain, arg); err != nil {
+ importErr = err
log.Error("Import error", "file", arg, "err", err)
}
}
@@ -260,19 +250,7 @@ func importChain(ctx *cli.Context) error {
fmt.Printf("Import done in %v.\n\n", time.Since(start))
// Output pre-compaction stats mostly to see the import trashing
- db := chainDb
-
- stats, err := db.Get([]byte("leveldb.stats"))
- if err != nil {
- utils.Fatalf("Failed to read database stats: %v", err)
- }
- fmt.Println(stats)
-
- ioStats, err := db.Get([]byte("leveldb.iostats"))
- if err != nil {
- utils.Fatalf("Failed to read database iostats: %v", err)
- }
- fmt.Println(ioStats)
+ showLeveldbStats(db)
// Print the memory statistics used by the importing
mem := new(runtime.MemStats)
@@ -283,31 +261,20 @@ func importChain(ctx *cli.Context) error {
fmt.Printf("Allocations: %.3f million\n", float64(mem.Mallocs)/1000000)
fmt.Printf("GC pause: %v\n\n", time.Duration(mem.PauseTotalNs))
- if ctx.IsSet(utils.NoCompactionFlag.Name) {
+ if ctx.Bool(utils.NoCompactionFlag.Name) {
return nil
}
// Compact the entire database to more accurately measure disk io and print the stats
start = time.Now()
fmt.Println("Compacting entire database...")
- if err = db.Compact(nil, nil); err != nil {
+ if err := db.Compact(nil, nil); err != nil {
utils.Fatalf("Compaction failed: %v", err)
}
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
- stats, err = db.Get([]byte("leveldb.stats"))
- if err != nil {
- utils.Fatalf("Failed to read database stats: %v", err)
- }
- fmt.Println(stats)
-
- ioStats, err = db.Get([]byte("leveldb.iostats"))
- if err != nil {
- utils.Fatalf("Failed to read database iostats: %v", err)
- }
- fmt.Println(ioStats)
-
- return nil
+ showLeveldbStats(db)
+ return importErr
}
func exportChain(ctx *cli.Context) error {
@@ -385,35 +352,6 @@ func exportPreimages(ctx *cli.Context) error {
return nil
}
-func removeDB(ctx *cli.Context) error {
- stack, _ := makeConfigNode(ctx)
-
- for _, name := range []string{"chaindata", "lightchaindata"} {
- // Ensure the database exists in the first place
- logger := log.New("database", name)
-
- dbdir := stack.ResolvePath(name)
- if !common.FileExist(dbdir) {
- logger.Info("Database doesn't exist, skipping", "path", dbdir)
- continue
- }
- // Confirm removal and execute
- fmt.Println(dbdir)
- confirm, err := console.Stdin.PromptConfirm("Remove this database?")
- switch {
- case err != nil:
- utils.Fatalf("%v", err)
- case !confirm:
- logger.Warn("Database deletion aborted")
- default:
- start := time.Now()
- os.RemoveAll(dbdir)
- logger.Info("Database successfully deleted", "elapsed", common.PrettyDuration(time.Since(start)))
- }
- }
- return nil
-}
-
func dump(ctx *cli.Context) error {
stack, _ := makeFullNode(ctx)
defer stack.Close()
diff --git a/cmd/XDC/dbcmd.go b/cmd/XDC/dbcmd.go
new file mode 100644
index 0000000000..dddd91e7ea
--- /dev/null
+++ b/cmd/XDC/dbcmd.go
@@ -0,0 +1,259 @@
+// Copyright 2020 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 .
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/XinFinOrg/XDPoSChain/cmd/utils"
+ "github.com/XinFinOrg/XDPoSChain/common"
+ "github.com/XinFinOrg/XDPoSChain/common/hexutil"
+ "github.com/XinFinOrg/XDPoSChain/console"
+ "github.com/XinFinOrg/XDPoSChain/ethdb"
+ "github.com/XinFinOrg/XDPoSChain/log"
+ "github.com/urfave/cli/v2"
+)
+
+var (
+ removedbCommand = &cli.Command{
+ Action: removeDB,
+ Name: "removedb",
+ Usage: "Remove blockchain and state databases",
+ ArgsUsage: " ",
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.XDCXDataDirFlag,
+ utils.LightModeFlag,
+ },
+ Description: `
+Remove blockchain and state databases`,
+ }
+ dbCommand = &cli.Command{
+ Name: "db",
+ Usage: "Low level database operations",
+ ArgsUsage: "",
+ Subcommands: []*cli.Command{
+ dbStatCmd,
+ dbCompactCmd,
+ dbGetCmd,
+ dbDeleteCmd,
+ dbPutCmd,
+ },
+ }
+ dbStatCmd = &cli.Command{
+ Action: dbStats,
+ Name: "stats",
+ Usage: "Print leveldb statistics",
+ }
+ dbCompactCmd = &cli.Command{
+ Action: dbCompact,
+ Name: "compact",
+ Usage: "Compact leveldb database. WARNING: May take a very long time",
+ Description: `This command performs a database compaction.
+WARNING: This operation may take a very long time to finish, and may cause database
+corruption if it is aborted during execution'!`,
+ }
+ dbGetCmd = &cli.Command{
+ Action: dbGet,
+ Name: "get",
+ Usage: "Show the value of a database key",
+ ArgsUsage: "",
+ Description: "This command looks up the specified database key from the database.",
+ }
+ dbDeleteCmd = &cli.Command{
+ Action: dbDelete,
+ Name: "delete",
+ Usage: "Delete a database key (WARNING: may corrupt your database)",
+ ArgsUsage: "",
+ Description: `This command deletes the specified database key from the database.
+WARNING: This is a low-level operation which may cause database corruption!`,
+ }
+ dbPutCmd = &cli.Command{
+ Action: dbPut,
+ Name: "put",
+ Usage: "Set the value of a database key (WARNING: may corrupt your database)",
+ ArgsUsage: " ",
+ Description: `This command sets a given database key to the given value.
+WARNING: This is a low-level operation which may cause database corruption!`,
+ }
+)
+
+func removeDB(ctx *cli.Context) error {
+ stack, _ := makeConfigNode(ctx)
+ for _, name := range []string{"chaindata", "lightchaindata"} {
+ // Ensure the database exists in the first place
+ logger := log.New("database", name)
+
+ dbdir := stack.ResolvePath(name)
+ if !common.FileExist(dbdir) {
+ logger.Info("Database doesn't exist, skipping", "path", dbdir)
+ continue
+ }
+ confirmAndRemoveDB(dbdir, name)
+ }
+ return nil
+}
+
+// confirmAndRemoveDB prompts the user for a last confirmation and removes the
+// folder if accepted.
+func confirmAndRemoveDB(database string, kind string) {
+ confirm, err := console.Stdin.PromptConfirm(fmt.Sprintf("Remove %s (%s)?", kind, database))
+ switch {
+ case err != nil:
+ utils.Fatalf("%v", err)
+ case !confirm:
+ log.Warn("Database deletion aborted", "path", database)
+ default:
+ start := time.Now()
+ os.RemoveAll(database)
+ log.Info("Database successfully deleted", "path", database, "elapsed", common.PrettyDuration(time.Since(start)))
+ }
+}
+
+func showLeveldbStats(db ethdb.Stater) {
+ if stats, err := db.Stat("leveldb.stats"); err != nil {
+ log.Warn("Failed to read database stats", "error", err)
+ } else {
+ fmt.Println(stats)
+ }
+ if ioStats, err := db.Stat("leveldb.iostats"); err != nil {
+ log.Warn("Failed to read database iostats", "error", err)
+ } else {
+ fmt.Println(ioStats)
+ }
+}
+
+func dbStats(ctx *cli.Context) error {
+ stack, _ := makeConfigNode(ctx)
+ defer stack.Close()
+
+ db := utils.MakeChainDatabase(ctx, stack, true)
+ defer db.Close()
+
+ showLeveldbStats(db)
+ return nil
+}
+
+func dbCompact(ctx *cli.Context) error {
+ stack, _ := makeConfigNode(ctx)
+ defer stack.Close()
+
+ db := utils.MakeChainDatabase(ctx, stack, false)
+ defer db.Close()
+
+ log.Info("Stats before compaction")
+ showLeveldbStats(db)
+
+ log.Info("Triggering compaction")
+ if err := db.Compact(nil, nil); err != nil {
+ log.Info("Compact err", "error", err)
+ return err
+ }
+
+ log.Info("Stats after compaction")
+ showLeveldbStats(db)
+ return nil
+}
+
+// dbGet shows the value of a given database key
+func dbGet(ctx *cli.Context) error {
+ if ctx.NArg() != 1 {
+ return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
+ }
+ stack, _ := makeConfigNode(ctx)
+ defer stack.Close()
+
+ db := utils.MakeChainDatabase(ctx, stack, true)
+ defer db.Close()
+
+ key, err := common.ParseHexOrString(ctx.Args().Get(0))
+ if err != nil {
+ log.Info("Could not decode the key", "error", err)
+ return err
+ }
+
+ data, err := db.Get(key)
+ if err != nil {
+ log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err)
+ return err
+ }
+ fmt.Printf("key %#x:\n\t%#x\n", key, data)
+ return nil
+}
+
+// dbDelete deletes a key from the database
+func dbDelete(ctx *cli.Context) error {
+ if ctx.NArg() != 1 {
+ return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
+ }
+ stack, _ := makeConfigNode(ctx)
+ defer stack.Close()
+
+ db := utils.MakeChainDatabase(ctx, stack, false)
+ defer db.Close()
+
+ key, err := common.ParseHexOrString(ctx.Args().Get(0))
+ if err != nil {
+ log.Info("Could not decode the key", "error", err)
+ return err
+ }
+ data, err := db.Get(key)
+ if err == nil {
+ fmt.Printf("Previous value: %#x\n", data)
+ }
+ if err = db.Delete(key); err != nil {
+ log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err)
+ return err
+ }
+ return nil
+}
+
+// dbPut overwrite a value in the database
+func dbPut(ctx *cli.Context) error {
+ if ctx.NArg() != 2 {
+ return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
+ }
+ stack, _ := makeConfigNode(ctx)
+ defer stack.Close()
+
+ db := utils.MakeChainDatabase(ctx, stack, false)
+ defer db.Close()
+
+ var (
+ key []byte
+ value []byte
+ data []byte
+ err error
+ )
+ key, err = common.ParseHexOrString(ctx.Args().Get(0))
+ if err != nil {
+ log.Info("Could not decode the key", "error", err)
+ return err
+ }
+ value, err = hexutil.Decode(ctx.Args().Get(1))
+ if err != nil {
+ log.Info("Could not decode the value", "error", err)
+ return err
+ }
+ data, err = db.Get(key)
+ if err == nil {
+ fmt.Printf("Previous value:\n%#x\n", data)
+ }
+ return db.Put(key, value)
+}
diff --git a/cmd/XDC/main.go b/cmd/XDC/main.go
index f3b9bdba13..21d8ee777a 100644
--- a/cmd/XDC/main.go
+++ b/cmd/XDC/main.go
@@ -188,6 +188,8 @@ func init() {
initCommand,
importCommand,
exportCommand,
+ importPreimagesCommand,
+ exportPreimagesCommand,
removedbCommand,
dumpCommand,
// See accountcmd.go:
@@ -198,9 +200,16 @@ func init() {
attachCommand,
javascriptCommand,
// See misccmd.go:
+ makecacheCommand,
+ makedagCommand,
versionCommand,
+ licenseCommand,
// See config.go
dumpConfigCommand,
+ // see dbcmd.go
+ dbCommand,
+ // See cmd/utils/flags_legacy.go
+ utils.ShowDeprecated,
}
sort.Sort(cli.CommandsByName(app.Commands))