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