github.com/ethereum/go-ethereum@v1.16.1/cmd/geth/dbcmd.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"os"
    23  	"os/signal"
    24  	"path/filepath"
    25  	"slices"
    26  	"strconv"
    27  	"strings"
    28  	"syscall"
    29  	"time"
    30  
    31  	"github.com/ethereum/go-ethereum/cmd/utils"
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/ethereum/go-ethereum/common/hexutil"
    34  	"github.com/ethereum/go-ethereum/console/prompt"
    35  	"github.com/ethereum/go-ethereum/core/rawdb"
    36  	"github.com/ethereum/go-ethereum/core/state/snapshot"
    37  	"github.com/ethereum/go-ethereum/core/types"
    38  	"github.com/ethereum/go-ethereum/crypto"
    39  	"github.com/ethereum/go-ethereum/ethdb"
    40  	"github.com/ethereum/go-ethereum/log"
    41  	"github.com/ethereum/go-ethereum/rlp"
    42  	"github.com/ethereum/go-ethereum/trie"
    43  	"github.com/ethereum/go-ethereum/triedb"
    44  	"github.com/olekukonko/tablewriter"
    45  	"github.com/urfave/cli/v2"
    46  )
    47  
    48  var (
    49  	removeStateDataFlag = &cli.BoolFlag{
    50  		Name:  "remove.state",
    51  		Usage: "If set, selects the state data for removal",
    52  	}
    53  	removeChainDataFlag = &cli.BoolFlag{
    54  		Name:  "remove.chain",
    55  		Usage: "If set, selects the state data for removal",
    56  	}
    57  
    58  	removedbCommand = &cli.Command{
    59  		Action:    removeDB,
    60  		Name:      "removedb",
    61  		Usage:     "Remove blockchain and state databases",
    62  		ArgsUsage: "",
    63  		Flags: slices.Concat(utils.DatabaseFlags,
    64  			[]cli.Flag{removeStateDataFlag, removeChainDataFlag}),
    65  		Description: `
    66  Remove blockchain and state databases`,
    67  	}
    68  	dbCommand = &cli.Command{
    69  		Name:      "db",
    70  		Usage:     "Low level database operations",
    71  		ArgsUsage: "",
    72  		Subcommands: []*cli.Command{
    73  			dbInspectCmd,
    74  			dbStatCmd,
    75  			dbCompactCmd,
    76  			dbGetCmd,
    77  			dbDeleteCmd,
    78  			dbPutCmd,
    79  			dbGetSlotsCmd,
    80  			dbDumpFreezerIndex,
    81  			dbImportCmd,
    82  			dbExportCmd,
    83  			dbMetadataCmd,
    84  			dbCheckStateContentCmd,
    85  			dbInspectHistoryCmd,
    86  		},
    87  	}
    88  	dbInspectCmd = &cli.Command{
    89  		Action:      inspect,
    90  		Name:        "inspect",
    91  		ArgsUsage:   "<prefix> <start>",
    92  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
    93  		Usage:       "Inspect the storage size for each type of data in the database",
    94  		Description: `This commands iterates the entire database. If the optional 'prefix' and 'start' arguments are provided, then the iteration is limited to the given subset of data.`,
    95  	}
    96  	dbCheckStateContentCmd = &cli.Command{
    97  		Action:    checkStateContent,
    98  		Name:      "check-state-content",
    99  		ArgsUsage: "<start (optional)>",
   100  		Flags:     slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   101  		Usage:     "Verify that state data is cryptographically correct",
   102  		Description: `This command iterates the entire database for 32-byte keys, looking for rlp-encoded trie nodes.
   103  For each trie node encountered, it checks that the key corresponds to the keccak256(value). If this is not true, this indicates
   104  a data corruption.`,
   105  	}
   106  	dbStatCmd = &cli.Command{
   107  		Action: dbStats,
   108  		Name:   "stats",
   109  		Usage:  "Print leveldb statistics",
   110  		Flags:  slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   111  	}
   112  	dbCompactCmd = &cli.Command{
   113  		Action: dbCompact,
   114  		Name:   "compact",
   115  		Usage:  "Compact leveldb database. WARNING: May take a very long time",
   116  		Flags: slices.Concat([]cli.Flag{
   117  			utils.CacheFlag,
   118  			utils.CacheDatabaseFlag,
   119  		}, utils.NetworkFlags, utils.DatabaseFlags),
   120  		Description: `This command performs a database compaction.
   121  WARNING: This operation may take a very long time to finish, and may cause database
   122  corruption if it is aborted during execution'!`,
   123  	}
   124  	dbGetCmd = &cli.Command{
   125  		Action:      dbGet,
   126  		Name:        "get",
   127  		Usage:       "Show the value of a database key",
   128  		ArgsUsage:   "<hex-encoded key>",
   129  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   130  		Description: "This command looks up the specified database key from the database.",
   131  	}
   132  	dbDeleteCmd = &cli.Command{
   133  		Action:    dbDelete,
   134  		Name:      "delete",
   135  		Usage:     "Delete a database key (WARNING: may corrupt your database)",
   136  		ArgsUsage: "<hex-encoded key>",
   137  		Flags:     slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   138  		Description: `This command deletes the specified database key from the database.
   139  WARNING: This is a low-level operation which may cause database corruption!`,
   140  	}
   141  	dbPutCmd = &cli.Command{
   142  		Action:    dbPut,
   143  		Name:      "put",
   144  		Usage:     "Set the value of a database key (WARNING: may corrupt your database)",
   145  		ArgsUsage: "<hex-encoded key> <hex-encoded value>",
   146  		Flags:     slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   147  		Description: `This command sets a given database key to the given value.
   148  WARNING: This is a low-level operation which may cause database corruption!`,
   149  	}
   150  	dbGetSlotsCmd = &cli.Command{
   151  		Action:      dbDumpTrie,
   152  		Name:        "dumptrie",
   153  		Usage:       "Show the storage key/values of a given storage trie",
   154  		ArgsUsage:   "<hex-encoded state root> <hex-encoded account hash> <hex-encoded storage trie root> <hex-encoded start (optional)> <int max elements (optional)>",
   155  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   156  		Description: "This command looks up the specified database key from the database.",
   157  	}
   158  	dbDumpFreezerIndex = &cli.Command{
   159  		Action:      freezerInspect,
   160  		Name:        "freezer-index",
   161  		Usage:       "Dump out the index of a specific freezer table",
   162  		ArgsUsage:   "<freezer-type> <table-type> <start (int)> <end (int)>",
   163  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   164  		Description: "This command displays information about the freezer index.",
   165  	}
   166  	dbImportCmd = &cli.Command{
   167  		Action:      importLDBdata,
   168  		Name:        "import",
   169  		Usage:       "Imports leveldb-data from an exported RLP dump.",
   170  		ArgsUsage:   "<dumpfile> <start (optional)",
   171  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   172  		Description: "The import command imports the specific chain data from an RLP encoded stream.",
   173  	}
   174  	dbExportCmd = &cli.Command{
   175  		Action:      exportChaindata,
   176  		Name:        "export",
   177  		Usage:       "Exports the chain data into an RLP dump. If the <dumpfile> has .gz suffix, gzip compression will be used.",
   178  		ArgsUsage:   "<type> <dumpfile>",
   179  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   180  		Description: "Exports the specified chain data to an RLP encoded stream, optionally gzip-compressed.",
   181  	}
   182  	dbMetadataCmd = &cli.Command{
   183  		Action:      showMetaData,
   184  		Name:        "metadata",
   185  		Usage:       "Shows metadata about the chain status.",
   186  		Flags:       slices.Concat(utils.NetworkFlags, utils.DatabaseFlags),
   187  		Description: "Shows metadata about the chain status.",
   188  	}
   189  	dbInspectHistoryCmd = &cli.Command{
   190  		Action:    inspectHistory,
   191  		Name:      "inspect-history",
   192  		Usage:     "Inspect the state history within block range",
   193  		ArgsUsage: "<address> [OPTIONAL <storage-slot>]",
   194  		Flags: slices.Concat([]cli.Flag{
   195  			&cli.Uint64Flag{
   196  				Name:  "start",
   197  				Usage: "block number of the range start, zero means earliest history",
   198  			},
   199  			&cli.Uint64Flag{
   200  				Name:  "end",
   201  				Usage: "block number of the range end(included), zero means latest history",
   202  			},
   203  			&cli.BoolFlag{
   204  				Name:  "raw",
   205  				Usage: "display the decoded raw state value (otherwise shows rlp-encoded value)",
   206  			},
   207  		}, utils.NetworkFlags, utils.DatabaseFlags),
   208  		Description: "This command queries the history of the account or storage slot within the specified block range",
   209  	}
   210  )
   211  
   212  func removeDB(ctx *cli.Context) error {
   213  	stack, config := makeConfigNode(ctx)
   214  
   215  	// Resolve folder paths.
   216  	var (
   217  		rootDir    = stack.ResolvePath("chaindata")
   218  		ancientDir = config.Eth.DatabaseFreezer
   219  	)
   220  	switch {
   221  	case ancientDir == "":
   222  		ancientDir = filepath.Join(stack.ResolvePath("chaindata"), "ancient")
   223  	case !filepath.IsAbs(ancientDir):
   224  		ancientDir = config.Node.ResolvePath(ancientDir)
   225  	}
   226  	// Delete state data
   227  	statePaths := []string{
   228  		rootDir,
   229  		filepath.Join(ancientDir, rawdb.MerkleStateFreezerName),
   230  		filepath.Join(ancientDir, rawdb.VerkleStateFreezerName),
   231  	}
   232  	confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
   233  
   234  	// Delete ancient chain
   235  	chainPaths := []string{filepath.Join(
   236  		ancientDir,
   237  		rawdb.ChainFreezerName,
   238  	)}
   239  	confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name)
   240  	return nil
   241  }
   242  
   243  // removeFolder deletes all files (not folders) inside the directory 'dir' (but
   244  // not files in subfolders).
   245  func removeFolder(dir string) {
   246  	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
   247  		// If we're at the top level folder, recurse into
   248  		if path == dir {
   249  			return nil
   250  		}
   251  		// Delete all the files, but not subfolders
   252  		if !info.IsDir() {
   253  			os.Remove(path)
   254  			return nil
   255  		}
   256  		return filepath.SkipDir
   257  	})
   258  }
   259  
   260  // confirmAndRemoveDB prompts the user for a last confirmation and removes the
   261  // list of folders if accepted.
   262  func confirmAndRemoveDB(paths []string, kind string, ctx *cli.Context, removeFlagName string) {
   263  	var (
   264  		confirm bool
   265  		err     error
   266  	)
   267  	msg := fmt.Sprintf("Location(s) of '%s': \n", kind)
   268  	for _, path := range paths {
   269  		msg += fmt.Sprintf("\t- %s\n", path)
   270  	}
   271  	fmt.Println(msg)
   272  	if ctx.IsSet(removeFlagName) {
   273  		confirm = ctx.Bool(removeFlagName)
   274  		if confirm {
   275  			fmt.Printf("Remove '%s'? [y/n] y\n", kind)
   276  		} else {
   277  			fmt.Printf("Remove '%s'? [y/n] n\n", kind)
   278  		}
   279  	} else {
   280  		confirm, err = prompt.Stdin.PromptConfirm(fmt.Sprintf("Remove '%s'?", kind))
   281  	}
   282  	switch {
   283  	case err != nil:
   284  		utils.Fatalf("%v", err)
   285  	case !confirm:
   286  		log.Info("Database deletion skipped", "kind", kind, "paths", paths)
   287  	default:
   288  		var (
   289  			deleted []string
   290  			start   = time.Now()
   291  		)
   292  		for _, path := range paths {
   293  			if common.FileExist(path) {
   294  				removeFolder(path)
   295  				deleted = append(deleted, path)
   296  			} else {
   297  				log.Info("Folder is not existent", "path", path)
   298  			}
   299  		}
   300  		log.Info("Database successfully deleted", "kind", kind, "paths", deleted, "elapsed", common.PrettyDuration(time.Since(start)))
   301  	}
   302  }
   303  
   304  func inspect(ctx *cli.Context) error {
   305  	var (
   306  		prefix []byte
   307  		start  []byte
   308  	)
   309  	if ctx.NArg() > 2 {
   310  		return fmt.Errorf("max 2 arguments: %v", ctx.Command.ArgsUsage)
   311  	}
   312  	if ctx.NArg() >= 1 {
   313  		if d, err := hexutil.Decode(ctx.Args().Get(0)); err != nil {
   314  			return fmt.Errorf("failed to hex-decode 'prefix': %v", err)
   315  		} else {
   316  			prefix = d
   317  		}
   318  	}
   319  	if ctx.NArg() >= 2 {
   320  		if d, err := hexutil.Decode(ctx.Args().Get(1)); err != nil {
   321  			return fmt.Errorf("failed to hex-decode 'start': %v", err)
   322  		} else {
   323  			start = d
   324  		}
   325  	}
   326  	stack, _ := makeConfigNode(ctx)
   327  	defer stack.Close()
   328  
   329  	db := utils.MakeChainDatabase(ctx, stack, true)
   330  	defer db.Close()
   331  
   332  	return rawdb.InspectDatabase(db, prefix, start)
   333  }
   334  
   335  func checkStateContent(ctx *cli.Context) error {
   336  	var (
   337  		prefix []byte
   338  		start  []byte
   339  	)
   340  	if ctx.NArg() > 1 {
   341  		return fmt.Errorf("max 1 argument: %v", ctx.Command.ArgsUsage)
   342  	}
   343  	if ctx.NArg() > 0 {
   344  		if d, err := hexutil.Decode(ctx.Args().First()); err != nil {
   345  			return fmt.Errorf("failed to hex-decode 'start': %v", err)
   346  		} else {
   347  			start = d
   348  		}
   349  	}
   350  	stack, _ := makeConfigNode(ctx)
   351  	defer stack.Close()
   352  
   353  	db := utils.MakeChainDatabase(ctx, stack, true)
   354  	defer db.Close()
   355  	var (
   356  		it        = rawdb.NewKeyLengthIterator(db.NewIterator(prefix, start), 32)
   357  		hasher    = crypto.NewKeccakState()
   358  		got       = make([]byte, 32)
   359  		errs      int
   360  		count     int
   361  		startTime = time.Now()
   362  		lastLog   = time.Now()
   363  	)
   364  	for it.Next() {
   365  		count++
   366  		k := it.Key()
   367  		v := it.Value()
   368  		hasher.Reset()
   369  		hasher.Write(v)
   370  		hasher.Read(got)
   371  		if !bytes.Equal(k, got) {
   372  			errs++
   373  			fmt.Printf("Error at %#x\n", k)
   374  			fmt.Printf("  Hash:  %#x\n", got)
   375  			fmt.Printf("  Data:  %#x\n", v)
   376  		}
   377  		if time.Since(lastLog) > 8*time.Second {
   378  			log.Info("Iterating the database", "at", fmt.Sprintf("%#x", k), "elapsed", common.PrettyDuration(time.Since(startTime)))
   379  			lastLog = time.Now()
   380  		}
   381  	}
   382  	if err := it.Error(); err != nil {
   383  		return err
   384  	}
   385  	log.Info("Iterated the state content", "errors", errs, "items", count)
   386  	return nil
   387  }
   388  
   389  func showDBStats(db ethdb.KeyValueStater) {
   390  	stats, err := db.Stat()
   391  	if err != nil {
   392  		log.Warn("Failed to read database stats", "error", err)
   393  		return
   394  	}
   395  	fmt.Println(stats)
   396  }
   397  
   398  func dbStats(ctx *cli.Context) error {
   399  	stack, _ := makeConfigNode(ctx)
   400  	defer stack.Close()
   401  
   402  	db := utils.MakeChainDatabase(ctx, stack, true)
   403  	defer db.Close()
   404  
   405  	showDBStats(db)
   406  	return nil
   407  }
   408  
   409  func dbCompact(ctx *cli.Context) error {
   410  	stack, _ := makeConfigNode(ctx)
   411  	defer stack.Close()
   412  
   413  	db := utils.MakeChainDatabase(ctx, stack, false)
   414  	defer db.Close()
   415  
   416  	log.Info("Stats before compaction")
   417  	showDBStats(db)
   418  
   419  	log.Info("Triggering compaction")
   420  	if err := db.Compact(nil, nil); err != nil {
   421  		log.Info("Compact err", "error", err)
   422  		return err
   423  	}
   424  	log.Info("Stats after compaction")
   425  	showDBStats(db)
   426  	return nil
   427  }
   428  
   429  // dbGet shows the value of a given database key
   430  func dbGet(ctx *cli.Context) error {
   431  	if ctx.NArg() != 1 {
   432  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   433  	}
   434  	stack, _ := makeConfigNode(ctx)
   435  	defer stack.Close()
   436  
   437  	db := utils.MakeChainDatabase(ctx, stack, true)
   438  	defer db.Close()
   439  
   440  	key, err := common.ParseHexOrString(ctx.Args().Get(0))
   441  	if err != nil {
   442  		log.Info("Could not decode the key", "error", err)
   443  		return err
   444  	}
   445  
   446  	data, err := db.Get(key)
   447  	if err != nil {
   448  		log.Info("Get operation failed", "key", fmt.Sprintf("%#x", key), "error", err)
   449  		return err
   450  	}
   451  	fmt.Printf("key %#x: %#x\n", key, data)
   452  	return nil
   453  }
   454  
   455  // dbDelete deletes a key from the database
   456  func dbDelete(ctx *cli.Context) error {
   457  	if ctx.NArg() != 1 {
   458  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   459  	}
   460  	stack, _ := makeConfigNode(ctx)
   461  	defer stack.Close()
   462  
   463  	db := utils.MakeChainDatabase(ctx, stack, false)
   464  	defer db.Close()
   465  
   466  	key, err := common.ParseHexOrString(ctx.Args().Get(0))
   467  	if err != nil {
   468  		log.Info("Could not decode the key", "error", err)
   469  		return err
   470  	}
   471  	data, err := db.Get(key)
   472  	if err == nil {
   473  		fmt.Printf("Previous value: %#x\n", data)
   474  	}
   475  	if err = db.Delete(key); err != nil {
   476  		log.Info("Delete operation returned an error", "key", fmt.Sprintf("%#x", key), "error", err)
   477  		return err
   478  	}
   479  	return nil
   480  }
   481  
   482  // dbPut overwrite a value in the database
   483  func dbPut(ctx *cli.Context) error {
   484  	if ctx.NArg() != 2 {
   485  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   486  	}
   487  	stack, _ := makeConfigNode(ctx)
   488  	defer stack.Close()
   489  
   490  	db := utils.MakeChainDatabase(ctx, stack, false)
   491  	defer db.Close()
   492  
   493  	var (
   494  		key   []byte
   495  		value []byte
   496  		data  []byte
   497  		err   error
   498  	)
   499  	key, err = common.ParseHexOrString(ctx.Args().Get(0))
   500  	if err != nil {
   501  		log.Info("Could not decode the key", "error", err)
   502  		return err
   503  	}
   504  	value, err = hexutil.Decode(ctx.Args().Get(1))
   505  	if err != nil {
   506  		log.Info("Could not decode the value", "error", err)
   507  		return err
   508  	}
   509  	data, err = db.Get(key)
   510  	if err == nil {
   511  		fmt.Printf("Previous value: %#x\n", data)
   512  	}
   513  	return db.Put(key, value)
   514  }
   515  
   516  // dbDumpTrie shows the key-value slots of a given storage trie
   517  func dbDumpTrie(ctx *cli.Context) error {
   518  	if ctx.NArg() < 3 {
   519  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   520  	}
   521  	stack, _ := makeConfigNode(ctx)
   522  	defer stack.Close()
   523  
   524  	db := utils.MakeChainDatabase(ctx, stack, true)
   525  	defer db.Close()
   526  
   527  	triedb := utils.MakeTrieDatabase(ctx, db, false, true, false)
   528  	defer triedb.Close()
   529  
   530  	var (
   531  		state   []byte
   532  		storage []byte
   533  		account []byte
   534  		start   []byte
   535  		max     = int64(-1)
   536  		err     error
   537  	)
   538  	if state, err = hexutil.Decode(ctx.Args().Get(0)); err != nil {
   539  		log.Info("Could not decode the state root", "error", err)
   540  		return err
   541  	}
   542  	if account, err = hexutil.Decode(ctx.Args().Get(1)); err != nil {
   543  		log.Info("Could not decode the account hash", "error", err)
   544  		return err
   545  	}
   546  	if storage, err = hexutil.Decode(ctx.Args().Get(2)); err != nil {
   547  		log.Info("Could not decode the storage trie root", "error", err)
   548  		return err
   549  	}
   550  	if ctx.NArg() > 3 {
   551  		if start, err = hexutil.Decode(ctx.Args().Get(3)); err != nil {
   552  			log.Info("Could not decode the seek position", "error", err)
   553  			return err
   554  		}
   555  	}
   556  	if ctx.NArg() > 4 {
   557  		if max, err = strconv.ParseInt(ctx.Args().Get(4), 10, 64); err != nil {
   558  			log.Info("Could not decode the max count", "error", err)
   559  			return err
   560  		}
   561  	}
   562  	id := trie.StorageTrieID(common.BytesToHash(state), common.BytesToHash(account), common.BytesToHash(storage))
   563  	theTrie, err := trie.New(id, triedb)
   564  	if err != nil {
   565  		return err
   566  	}
   567  	trieIt, err := theTrie.NodeIterator(start)
   568  	if err != nil {
   569  		return err
   570  	}
   571  	var count int64
   572  	it := trie.NewIterator(trieIt)
   573  	for it.Next() {
   574  		if max > 0 && count == max {
   575  			fmt.Printf("Exiting after %d values\n", count)
   576  			break
   577  		}
   578  		fmt.Printf("  %d. key %#x: %#x\n", count, it.Key, it.Value)
   579  		count++
   580  	}
   581  	return it.Err
   582  }
   583  
   584  func freezerInspect(ctx *cli.Context) error {
   585  	if ctx.NArg() < 4 {
   586  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   587  	}
   588  	var (
   589  		freezer = ctx.Args().Get(0)
   590  		table   = ctx.Args().Get(1)
   591  	)
   592  	start, err := strconv.ParseInt(ctx.Args().Get(2), 10, 64)
   593  	if err != nil {
   594  		log.Info("Could not read start-param", "err", err)
   595  		return err
   596  	}
   597  	end, err := strconv.ParseInt(ctx.Args().Get(3), 10, 64)
   598  	if err != nil {
   599  		log.Info("Could not read count param", "err", err)
   600  		return err
   601  	}
   602  	stack, _ := makeConfigNode(ctx)
   603  	ancient := stack.ResolveAncient("chaindata", ctx.String(utils.AncientFlag.Name))
   604  	stack.Close()
   605  	return rawdb.InspectFreezerTable(ancient, freezer, table, start, end)
   606  }
   607  
   608  func importLDBdata(ctx *cli.Context) error {
   609  	start := 0
   610  	switch ctx.NArg() {
   611  	case 1:
   612  		break
   613  	case 2:
   614  		s, err := strconv.Atoi(ctx.Args().Get(1))
   615  		if err != nil {
   616  			return fmt.Errorf("second arg must be an integer: %v", err)
   617  		}
   618  		start = s
   619  	default:
   620  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   621  	}
   622  	var (
   623  		fName     = ctx.Args().Get(0)
   624  		stack, _  = makeConfigNode(ctx)
   625  		interrupt = make(chan os.Signal, 1)
   626  		stop      = make(chan struct{})
   627  	)
   628  	defer stack.Close()
   629  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   630  	defer signal.Stop(interrupt)
   631  	defer close(interrupt)
   632  	go func() {
   633  		if _, ok := <-interrupt; ok {
   634  			log.Info("Interrupted during ldb import, stopping at next batch")
   635  		}
   636  		close(stop)
   637  	}()
   638  	db := utils.MakeChainDatabase(ctx, stack, false)
   639  	defer db.Close()
   640  	return utils.ImportLDBData(db, fName, int64(start), stop)
   641  }
   642  
   643  type preimageIterator struct {
   644  	iter ethdb.Iterator
   645  }
   646  
   647  func (iter *preimageIterator) Next() (byte, []byte, []byte, bool) {
   648  	for iter.iter.Next() {
   649  		key := iter.iter.Key()
   650  		if bytes.HasPrefix(key, rawdb.PreimagePrefix) && len(key) == (len(rawdb.PreimagePrefix)+common.HashLength) {
   651  			return utils.OpBatchAdd, key, iter.iter.Value(), true
   652  		}
   653  	}
   654  	return 0, nil, nil, false
   655  }
   656  
   657  func (iter *preimageIterator) Release() {
   658  	iter.iter.Release()
   659  }
   660  
   661  type snapshotIterator struct {
   662  	init    bool
   663  	account ethdb.Iterator
   664  	storage ethdb.Iterator
   665  }
   666  
   667  func (iter *snapshotIterator) Next() (byte, []byte, []byte, bool) {
   668  	if !iter.init {
   669  		iter.init = true
   670  		return utils.OpBatchDel, rawdb.SnapshotRootKey, nil, true
   671  	}
   672  	for iter.account.Next() {
   673  		key := iter.account.Key()
   674  		if bytes.HasPrefix(key, rawdb.SnapshotAccountPrefix) && len(key) == (len(rawdb.SnapshotAccountPrefix)+common.HashLength) {
   675  			return utils.OpBatchAdd, key, iter.account.Value(), true
   676  		}
   677  	}
   678  	for iter.storage.Next() {
   679  		key := iter.storage.Key()
   680  		if bytes.HasPrefix(key, rawdb.SnapshotStoragePrefix) && len(key) == (len(rawdb.SnapshotStoragePrefix)+2*common.HashLength) {
   681  			return utils.OpBatchAdd, key, iter.storage.Value(), true
   682  		}
   683  	}
   684  	return 0, nil, nil, false
   685  }
   686  
   687  func (iter *snapshotIterator) Release() {
   688  	iter.account.Release()
   689  	iter.storage.Release()
   690  }
   691  
   692  // chainExporters defines the export scheme for all exportable chain data.
   693  var chainExporters = map[string]func(db ethdb.Database) utils.ChainDataIterator{
   694  	"preimage": func(db ethdb.Database) utils.ChainDataIterator {
   695  		iter := db.NewIterator(rawdb.PreimagePrefix, nil)
   696  		return &preimageIterator{iter: iter}
   697  	},
   698  	"snapshot": func(db ethdb.Database) utils.ChainDataIterator {
   699  		account := db.NewIterator(rawdb.SnapshotAccountPrefix, nil)
   700  		storage := db.NewIterator(rawdb.SnapshotStoragePrefix, nil)
   701  		return &snapshotIterator{account: account, storage: storage}
   702  	},
   703  }
   704  
   705  func exportChaindata(ctx *cli.Context) error {
   706  	if ctx.NArg() < 2 {
   707  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   708  	}
   709  	// Parse the required chain data type, make sure it's supported.
   710  	kind := ctx.Args().Get(0)
   711  	kind = strings.ToLower(strings.Trim(kind, " "))
   712  	exporter, ok := chainExporters[kind]
   713  	if !ok {
   714  		var kinds []string
   715  		for kind := range chainExporters {
   716  			kinds = append(kinds, kind)
   717  		}
   718  		return fmt.Errorf("invalid data type %s, supported types: %s", kind, strings.Join(kinds, ", "))
   719  	}
   720  	var (
   721  		stack, _  = makeConfigNode(ctx)
   722  		interrupt = make(chan os.Signal, 1)
   723  		stop      = make(chan struct{})
   724  	)
   725  	defer stack.Close()
   726  	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
   727  	defer signal.Stop(interrupt)
   728  	defer close(interrupt)
   729  	go func() {
   730  		if _, ok := <-interrupt; ok {
   731  			log.Info("Interrupted during db export, stopping at next batch")
   732  		}
   733  		close(stop)
   734  	}()
   735  	db := utils.MakeChainDatabase(ctx, stack, true)
   736  	defer db.Close()
   737  	return utils.ExportChaindata(ctx.Args().Get(1), kind, exporter(db), stop)
   738  }
   739  
   740  func showMetaData(ctx *cli.Context) error {
   741  	stack, _ := makeConfigNode(ctx)
   742  	defer stack.Close()
   743  	db := utils.MakeChainDatabase(ctx, stack, true)
   744  	defer db.Close()
   745  
   746  	ancients, err := db.Ancients()
   747  	if err != nil {
   748  		fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
   749  	}
   750  	data := rawdb.ReadChainMetadata(db)
   751  	data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
   752  	data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
   753  	if b := rawdb.ReadHeadBlock(db); b != nil {
   754  		data = append(data, []string{"headBlock.Hash", fmt.Sprintf("%v", b.Hash())})
   755  		data = append(data, []string{"headBlock.Root", fmt.Sprintf("%v", b.Root())})
   756  		data = append(data, []string{"headBlock.Number", fmt.Sprintf("%d (%#x)", b.Number(), b.Number())})
   757  	}
   758  	if h := rawdb.ReadHeadHeader(db); h != nil {
   759  		data = append(data, []string{"headHeader.Hash", fmt.Sprintf("%v", h.Hash())})
   760  		data = append(data, []string{"headHeader.Root", fmt.Sprintf("%v", h.Root)})
   761  		data = append(data, []string{"headHeader.Number", fmt.Sprintf("%d (%#x)", h.Number, h.Number)})
   762  	}
   763  	table := tablewriter.NewWriter(os.Stdout)
   764  	table.SetHeader([]string{"Field", "Value"})
   765  	table.AppendBulk(data)
   766  	table.Render()
   767  	return nil
   768  }
   769  
   770  func inspectAccount(db *triedb.Database, start uint64, end uint64, address common.Address, raw bool) error {
   771  	stats, err := db.AccountHistory(address, start, end)
   772  	if err != nil {
   773  		return err
   774  	}
   775  	fmt.Printf("Account history:\n\taddress: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), stats.Start, stats.End)
   776  
   777  	from := stats.Start
   778  	for i := 0; i < len(stats.Blocks); i++ {
   779  		var content string
   780  		if len(stats.Origins[i]) == 0 {
   781  			content = "<empty>"
   782  		} else {
   783  			if !raw {
   784  				content = fmt.Sprintf("%#x", stats.Origins[i])
   785  			} else {
   786  				account := new(types.SlimAccount)
   787  				if err := rlp.DecodeBytes(stats.Origins[i], account); err != nil {
   788  					panic(err)
   789  				}
   790  				code := "<nil>"
   791  				if len(account.CodeHash) > 0 {
   792  					code = fmt.Sprintf("%#x", account.CodeHash)
   793  				}
   794  				root := "<nil>"
   795  				if len(account.Root) > 0 {
   796  					root = fmt.Sprintf("%#x", account.Root)
   797  				}
   798  				content = fmt.Sprintf("nonce: %d, balance: %d, codeHash: %s, root: %s", account.Nonce, account.Balance, code, root)
   799  			}
   800  		}
   801  		fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
   802  		from = stats.Blocks[i]
   803  	}
   804  	return nil
   805  }
   806  
   807  func inspectStorage(db *triedb.Database, start uint64, end uint64, address common.Address, slot common.Hash, raw bool) error {
   808  	// The hash of storage slot key is utilized in the history
   809  	// rather than the raw slot key, make the conversion.
   810  	stats, err := db.StorageHistory(address, slot, start, end)
   811  	if err != nil {
   812  		return err
   813  	}
   814  	fmt.Printf("Storage history:\n\taddress: %s\n\tslot: %s\n\tblockrange: [#%d-#%d]\n", address.Hex(), slot.Hex(), stats.Start, stats.End)
   815  
   816  	from := stats.Start
   817  	for i := 0; i < len(stats.Blocks); i++ {
   818  		var content string
   819  		if len(stats.Origins[i]) == 0 {
   820  			content = "<empty>"
   821  		} else {
   822  			if !raw {
   823  				content = fmt.Sprintf("%#x", stats.Origins[i])
   824  			} else {
   825  				_, data, _, err := rlp.Split(stats.Origins[i])
   826  				if err != nil {
   827  					fmt.Printf("Failed to decode storage slot, %v", err)
   828  					return err
   829  				}
   830  				content = fmt.Sprintf("%#x", data)
   831  			}
   832  		}
   833  		fmt.Printf("#%d - #%d: %s\n", from, stats.Blocks[i], content)
   834  		from = stats.Blocks[i]
   835  	}
   836  	return nil
   837  }
   838  
   839  func inspectHistory(ctx *cli.Context) error {
   840  	if ctx.NArg() == 0 || ctx.NArg() > 2 {
   841  		return fmt.Errorf("required arguments: %v", ctx.Command.ArgsUsage)
   842  	}
   843  	var (
   844  		address common.Address
   845  		slot    common.Hash
   846  	)
   847  	if err := address.UnmarshalText([]byte(ctx.Args().Get(0))); err != nil {
   848  		return err
   849  	}
   850  	if ctx.NArg() > 1 {
   851  		if err := slot.UnmarshalText([]byte(ctx.Args().Get(1))); err != nil {
   852  			return err
   853  		}
   854  	}
   855  	// Load the databases.
   856  	stack, _ := makeConfigNode(ctx)
   857  	defer stack.Close()
   858  
   859  	db := utils.MakeChainDatabase(ctx, stack, true)
   860  	defer db.Close()
   861  
   862  	triedb := utils.MakeTrieDatabase(ctx, db, false, false, false)
   863  	defer triedb.Close()
   864  
   865  	var (
   866  		err   error
   867  		start uint64 // the id of first history object to query
   868  		end   uint64 // the id (included) of last history object to query
   869  	)
   870  	// State histories are identified by state ID rather than block number.
   871  	// To address this, load the corresponding block header and perform the
   872  	// conversion by this function.
   873  	blockToID := func(blockNumber uint64) (uint64, error) {
   874  		header := rawdb.ReadHeader(db, rawdb.ReadCanonicalHash(db, blockNumber), blockNumber)
   875  		if header == nil {
   876  			return 0, fmt.Errorf("block #%d is not existent", blockNumber)
   877  		}
   878  		id := rawdb.ReadStateID(db, header.Root)
   879  		if id == nil {
   880  			first, last, err := triedb.HistoryRange()
   881  			if err == nil {
   882  				return 0, fmt.Errorf("history of block #%d is not existent, available history range: [#%d-#%d]", blockNumber, first, last)
   883  			}
   884  			return 0, fmt.Errorf("history of block #%d is not existent", blockNumber)
   885  		}
   886  		return *id, nil
   887  	}
   888  	// Parse the starting block number for inspection.
   889  	startNumber := ctx.Uint64("start")
   890  	if startNumber != 0 {
   891  		start, err = blockToID(startNumber)
   892  		if err != nil {
   893  			return err
   894  		}
   895  	}
   896  	// Parse the ending block number for inspection.
   897  	endBlock := ctx.Uint64("end")
   898  	if endBlock != 0 {
   899  		end, err = blockToID(endBlock)
   900  		if err != nil {
   901  			return err
   902  		}
   903  	}
   904  	// Inspect the state history.
   905  	if slot == (common.Hash{}) {
   906  		return inspectAccount(triedb, start, end, address, ctx.Bool("raw"))
   907  	}
   908  	return inspectStorage(triedb, start, end, address, slot, ctx.Bool("raw"))
   909  }