github.com/haliliceylan/bsc@v1.1.10-0.20220501224556-eb78d644ebcb/cmd/geth/snapshot.go (about)

     1  // Copyright 2020 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  	"errors"
    22  	"fmt"
    23  	"os"
    24  	"path/filepath"
    25  	"time"
    26  
    27  	"github.com/prometheus/tsdb/fileutil"
    28  	cli "gopkg.in/urfave/cli.v1"
    29  
    30  	"github.com/ethereum/go-ethereum/cmd/utils"
    31  	"github.com/ethereum/go-ethereum/common"
    32  	"github.com/ethereum/go-ethereum/core/rawdb"
    33  	"github.com/ethereum/go-ethereum/core/state"
    34  	"github.com/ethereum/go-ethereum/core/state/pruner"
    35  	"github.com/ethereum/go-ethereum/core/state/snapshot"
    36  	"github.com/ethereum/go-ethereum/crypto"
    37  	"github.com/ethereum/go-ethereum/ethdb"
    38  	"github.com/ethereum/go-ethereum/log"
    39  	"github.com/ethereum/go-ethereum/node"
    40  	"github.com/ethereum/go-ethereum/rlp"
    41  	"github.com/ethereum/go-ethereum/trie"
    42  )
    43  
    44  var (
    45  	// emptyRoot is the known root hash of an empty trie.
    46  	emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
    47  
    48  	// emptyCode is the known hash of the empty EVM bytecode.
    49  	emptyCode = crypto.Keccak256(nil)
    50  )
    51  
    52  var (
    53  	snapshotCommand = cli.Command{
    54  		Name:        "snapshot",
    55  		Usage:       "A set of commands based on the snapshot",
    56  		Category:    "MISCELLANEOUS COMMANDS",
    57  		Description: "",
    58  		Subcommands: []cli.Command{
    59  			{
    60  				Name:      "prune-state",
    61  				Usage:     "Prune stale ethereum state data based on the snapshot",
    62  				ArgsUsage: "<root>",
    63  				Action:    utils.MigrateFlags(pruneState),
    64  				Category:  "MISCELLANEOUS COMMANDS",
    65  				Flags: []cli.Flag{
    66  					utils.DataDirFlag,
    67  					utils.AncientFlag,
    68  					utils.RopstenFlag,
    69  					utils.RinkebyFlag,
    70  					utils.GoerliFlag,
    71  					utils.CacheTrieJournalFlag,
    72  					utils.BloomFilterSizeFlag,
    73  					utils.TriesInMemoryFlag,
    74  				},
    75  				Description: `
    76  geth snapshot prune-state <state-root>
    77  will prune historical state data with the help of the state snapshot.
    78  All trie nodes and contract codes that do not belong to the specified
    79  version state will be deleted from the database. After pruning, only
    80  two version states are available: genesis and the specific one.
    81  
    82  The default pruning target is the HEAD-127 state.
    83  
    84  WARNING: It's necessary to delete the trie clean cache after the pruning.
    85  If you specify another directory for the trie clean cache via "--cache.trie.journal"
    86  during the use of Geth, please also specify it here for correct deletion. Otherwise
    87  the trie clean cache with default directory will be deleted.
    88  `,
    89  			},
    90  			{
    91  				Name:     "prune-block",
    92  				Usage:    "Prune block data offline",
    93  				Action:   utils.MigrateFlags(pruneBlock),
    94  				Category: "MISCELLANEOUS COMMANDS",
    95  				Flags: []cli.Flag{
    96  					utils.DataDirFlag,
    97  					utils.AncientFlag,
    98  					utils.BlockAmountReserved,
    99  					utils.TriesInMemoryFlag,
   100  					utils.CheckSnapshotWithMPT,
   101  				},
   102  				Description: `
   103  geth offline prune-block for block data in ancientdb.
   104  The amount of blocks expected for remaining after prune can be specified via block-amount-reserved in this command,
   105  will prune and only remain the specified amount of old block data in ancientdb.
   106  the brief workflow is to backup the the number of this specified amount blocks backward in original ancientdb 
   107  into new ancient_backup, then delete the original ancientdb dir and rename the ancient_backup to original one for replacement,
   108  finally assemble the statedb and new ancientDb together.
   109  The purpose of doing it is because the block data will be moved into the ancient store when it
   110  becomes old enough(exceed the Threshold 90000), the disk usage will be very large over time, and is occupied mainly by ancientDb,
   111  so it's very necessary to do block data prune, this feature will handle it.
   112  `,
   113  			},
   114  			{
   115  				Name:      "verify-state",
   116  				Usage:     "Recalculate state hash based on the snapshot for verification",
   117  				ArgsUsage: "<root>",
   118  				Action:    utils.MigrateFlags(verifyState),
   119  				Category:  "MISCELLANEOUS COMMANDS",
   120  				Flags: []cli.Flag{
   121  					utils.DataDirFlag,
   122  					utils.AncientFlag,
   123  					utils.RopstenFlag,
   124  					utils.RinkebyFlag,
   125  					utils.GoerliFlag,
   126  				},
   127  				Description: `
   128  geth snapshot verify-state <state-root>
   129  will traverse the whole accounts and storages set based on the specified
   130  snapshot and recalculate the root hash of state for verification.
   131  In other words, this command does the snapshot to trie conversion.
   132  `,
   133  			},
   134  			{
   135  				Name:      "traverse-state",
   136  				Usage:     "Traverse the state with given root hash for verification",
   137  				ArgsUsage: "<root>",
   138  				Action:    utils.MigrateFlags(traverseState),
   139  				Category:  "MISCELLANEOUS COMMANDS",
   140  				Flags: []cli.Flag{
   141  					utils.DataDirFlag,
   142  					utils.AncientFlag,
   143  					utils.RopstenFlag,
   144  					utils.RinkebyFlag,
   145  					utils.GoerliFlag,
   146  				},
   147  				Description: `
   148  geth snapshot traverse-state <state-root>
   149  will traverse the whole state from the given state root and will abort if any
   150  referenced trie node or contract code is missing. This command can be used for
   151  state integrity verification. The default checking target is the HEAD state.
   152  
   153  It's also usable without snapshot enabled.
   154  `,
   155  			},
   156  			{
   157  				Name:      "traverse-rawstate",
   158  				Usage:     "Traverse the state with given root hash for verification",
   159  				ArgsUsage: "<root>",
   160  				Action:    utils.MigrateFlags(traverseRawState),
   161  				Category:  "MISCELLANEOUS COMMANDS",
   162  				Flags: []cli.Flag{
   163  					utils.DataDirFlag,
   164  					utils.AncientFlag,
   165  					utils.RopstenFlag,
   166  					utils.RinkebyFlag,
   167  					utils.GoerliFlag,
   168  				},
   169  				Description: `
   170  geth snapshot traverse-rawstate <state-root>
   171  will traverse the whole state from the given root and will abort if any referenced
   172  trie node or contract code is missing. This command can be used for state integrity
   173  verification. The default checking target is the HEAD state. It's basically identical
   174  to traverse-state, but the check granularity is smaller. 
   175  
   176  It's also usable without snapshot enabled.
   177  `,
   178  			},
   179  		},
   180  	}
   181  )
   182  
   183  func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
   184  	//The layer of tries trees that keep in memory.
   185  	TriesInMemory := int(ctx.GlobalUint64(utils.TriesInMemoryFlag.Name))
   186  	chaindb := utils.MakeChainDatabase(ctx, stack, false, true)
   187  	defer chaindb.Close()
   188  
   189  	if !ctx.GlobalBool(utils.CheckSnapshotWithMPT.Name) {
   190  		return chaindb, nil
   191  	}
   192  	headBlock := rawdb.ReadHeadBlock(chaindb)
   193  	if headBlock == nil {
   194  		return nil, errors.New("failed to load head block")
   195  	}
   196  	headHeader := headBlock.Header()
   197  	//Make sure the MPT and snapshot matches before pruning, otherwise the node can not start.
   198  	snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, TriesInMemory, headBlock.Root(), false, false, false)
   199  	if err != nil {
   200  		log.Error("snaptree error", "err", err)
   201  		return nil, err // The relevant snapshot(s) might not exist
   202  	}
   203  
   204  	// Use the HEAD-(n-1) as the target root. The reason for picking it is:
   205  	// - in most of the normal cases, the related state is available
   206  	// - the probability of this layer being reorg is very low
   207  
   208  	// Retrieve all snapshot layers from the current HEAD.
   209  	// In theory there are n difflayers + 1 disk layer present,
   210  	// so n diff layers are expected to be returned.
   211  	layers := snaptree.Snapshots(headHeader.Root, TriesInMemory, true)
   212  	if len(layers) != TriesInMemory {
   213  		// Reject if the accumulated diff layers are less than n. It
   214  		// means in most of normal cases, there is no associated state
   215  		// with bottom-most diff layer.
   216  		log.Error("snapshot layers != TriesInMemory", "err", err)
   217  		return nil, fmt.Errorf("snapshot not old enough yet: need %d more blocks", TriesInMemory-len(layers))
   218  	}
   219  	// Use the bottom-most diff layer as the target
   220  	targetRoot := layers[len(layers)-1].Root()
   221  
   222  	// Ensure the root is really present. The weak assumption
   223  	// is the presence of root can indicate the presence of the
   224  	// entire trie.
   225  	if blob := rawdb.ReadTrieNode(chaindb, targetRoot); len(blob) == 0 {
   226  		// The special case is for clique based networks(rinkeby, goerli
   227  		// and some other private networks), it's possible that two
   228  		// consecutive blocks will have same root. In this case snapshot
   229  		// difflayer won't be created. So HEAD-(n-1) may not paired with
   230  		// head-(n-1) layer. Instead the paired layer is higher than the
   231  		// bottom-most diff layer. Try to find the bottom-most snapshot
   232  		// layer with state available.
   233  		//
   234  		// Note HEAD is ignored. Usually there is the associated
   235  		// state available, but we don't want to use the topmost state
   236  		// as the pruning target.
   237  		var found bool
   238  		for i := len(layers) - 2; i >= 1; i-- {
   239  			if blob := rawdb.ReadTrieNode(chaindb, layers[i].Root()); len(blob) != 0 {
   240  				targetRoot = layers[i].Root()
   241  				found = true
   242  				log.Info("Selecting middle-layer as the pruning target", "root", targetRoot, "depth", i)
   243  				break
   244  			}
   245  		}
   246  		if !found {
   247  			if blob := rawdb.ReadTrieNode(chaindb, snaptree.DiskRoot()); len(blob) != 0 {
   248  				targetRoot = snaptree.DiskRoot()
   249  				found = true
   250  				log.Info("Selecting disk-layer as the pruning target", "root", targetRoot)
   251  			}
   252  		}
   253  		if !found {
   254  			if len(layers) > 0 {
   255  				log.Error("no snapshot paired state")
   256  				return nil, errors.New("no snapshot paired state")
   257  			}
   258  			return nil, fmt.Errorf("associated state[%x] is not present", targetRoot)
   259  		}
   260  	} else {
   261  		if len(layers) > 0 {
   262  			log.Info("Selecting bottom-most difflayer as the pruning target", "root", targetRoot, "height", headHeader.Number.Uint64()-uint64(len(layers)-1))
   263  		} else {
   264  			log.Info("Selecting user-specified state as the pruning target", "root", targetRoot)
   265  		}
   266  	}
   267  	return chaindb, nil
   268  }
   269  
   270  func pruneBlock(ctx *cli.Context) error {
   271  	stack, config := makeConfigNode(ctx)
   272  	defer stack.Close()
   273  	blockAmountReserved := ctx.GlobalUint64(utils.BlockAmountReserved.Name)
   274  	chaindb, err := accessDb(ctx, stack)
   275  	if err != nil {
   276  		return err
   277  	}
   278  	var newAncientPath string
   279  	oldAncientPath := ctx.GlobalString(utils.AncientFlag.Name)
   280  	if !filepath.IsAbs(oldAncientPath) {
   281  		// force absolute paths, which often fail due to the splicing of relative paths
   282  		return errors.New("datadir.ancient not abs path")
   283  	}
   284  
   285  	path, _ := filepath.Split(oldAncientPath)
   286  	if path == "" {
   287  		return errors.New("prune failed, did not specify the AncientPath")
   288  	}
   289  	newAncientPath = filepath.Join(path, "ancient_back")
   290  
   291  	blockpruner := pruner.NewBlockPruner(chaindb, stack, oldAncientPath, newAncientPath, blockAmountReserved)
   292  
   293  	lock, exist, err := fileutil.Flock(filepath.Join(oldAncientPath, "PRUNEFLOCK"))
   294  	if err != nil {
   295  		log.Error("file lock error", "err", err)
   296  		return err
   297  	}
   298  	if exist {
   299  		defer lock.Release()
   300  		log.Info("file lock existed, waiting for prune recovery and continue", "err", err)
   301  		if err := blockpruner.RecoverInterruption("chaindata", config.Eth.DatabaseCache, utils.MakeDatabaseHandles(), "", false); err != nil {
   302  			log.Error("Pruning failed", "err", err)
   303  			return err
   304  		}
   305  		log.Info("Block prune successfully")
   306  		return nil
   307  	}
   308  
   309  	if _, err := os.Stat(newAncientPath); err == nil {
   310  		// No file lock found for old ancientDB but new ancientDB exsisted, indicating the geth was interrupted
   311  		// after old ancientDB removal, this happened after backup successfully, so just rename the new ancientDB
   312  		if err := blockpruner.AncientDbReplacer(); err != nil {
   313  			log.Error("Failed to rename new ancient directory")
   314  			return err
   315  		}
   316  		log.Info("Block prune successfully")
   317  		return nil
   318  	}
   319  	name := "chaindata"
   320  	if err := blockpruner.BlockPruneBackUp(name, config.Eth.DatabaseCache, utils.MakeDatabaseHandles(), "", false, false); err != nil {
   321  		log.Error("Failed to back up block", "err", err)
   322  		return err
   323  	}
   324  
   325  	log.Info("backup block successfully")
   326  
   327  	//After backing up successfully, rename the new ancientdb name to the original one, and delete the old ancientdb
   328  	if err := blockpruner.AncientDbReplacer(); err != nil {
   329  		return err
   330  	}
   331  
   332  	lock.Release()
   333  	log.Info("Block prune successfully")
   334  	return nil
   335  }
   336  
   337  func pruneState(ctx *cli.Context) error {
   338  	stack, config := makeConfigNode(ctx)
   339  	defer stack.Close()
   340  
   341  	chaindb := utils.MakeChainDatabase(ctx, stack, false, false)
   342  	pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name), ctx.GlobalUint64(utils.TriesInMemoryFlag.Name))
   343  	if err != nil {
   344  		log.Error("Failed to open snapshot tree", "err", err)
   345  		return err
   346  	}
   347  	if ctx.NArg() > 1 {
   348  		log.Error("Too many arguments given")
   349  		return errors.New("too many arguments")
   350  	}
   351  	var targetRoot common.Hash
   352  	if ctx.NArg() == 1 {
   353  		targetRoot, err = parseRoot(ctx.Args()[0])
   354  		if err != nil {
   355  			log.Error("Failed to resolve state root", "err", err)
   356  			return err
   357  		}
   358  	}
   359  	if err = pruner.Prune(targetRoot); err != nil {
   360  		log.Error("Failed to prune state", "err", err)
   361  		return err
   362  	}
   363  	return nil
   364  }
   365  
   366  func verifyState(ctx *cli.Context) error {
   367  	stack, _ := makeConfigNode(ctx)
   368  	defer stack.Close()
   369  
   370  	chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
   371  	headBlock := rawdb.ReadHeadBlock(chaindb)
   372  	if headBlock == nil {
   373  		log.Error("Failed to load head block")
   374  		return errors.New("no head block")
   375  	}
   376  	snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, 128, headBlock.Root(), false, false, false)
   377  	if err != nil {
   378  		log.Error("Failed to open snapshot tree", "err", err)
   379  		return err
   380  	}
   381  	if ctx.NArg() > 1 {
   382  		log.Error("Too many arguments given")
   383  		return errors.New("too many arguments")
   384  	}
   385  	var root = headBlock.Root()
   386  	if ctx.NArg() == 1 {
   387  		root, err = parseRoot(ctx.Args()[0])
   388  		if err != nil {
   389  			log.Error("Failed to resolve state root", "err", err)
   390  			return err
   391  		}
   392  	}
   393  	if err := snaptree.Verify(root); err != nil {
   394  		log.Error("Failed to verfiy state", "root", root, "err", err)
   395  		return err
   396  	}
   397  	log.Info("Verified the state", "root", root)
   398  	return nil
   399  }
   400  
   401  // traverseState is a helper function used for pruning verification.
   402  // Basically it just iterates the trie, ensure all nodes and associated
   403  // contract codes are present.
   404  func traverseState(ctx *cli.Context) error {
   405  	stack, _ := makeConfigNode(ctx)
   406  	defer stack.Close()
   407  
   408  	chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
   409  	headBlock := rawdb.ReadHeadBlock(chaindb)
   410  	if headBlock == nil {
   411  		log.Error("Failed to load head block")
   412  		return errors.New("no head block")
   413  	}
   414  	if ctx.NArg() > 1 {
   415  		log.Error("Too many arguments given")
   416  		return errors.New("too many arguments")
   417  	}
   418  	var (
   419  		root common.Hash
   420  		err  error
   421  	)
   422  	if ctx.NArg() == 1 {
   423  		root, err = parseRoot(ctx.Args()[0])
   424  		if err != nil {
   425  			log.Error("Failed to resolve state root", "err", err)
   426  			return err
   427  		}
   428  		log.Info("Start traversing the state", "root", root)
   429  	} else {
   430  		root = headBlock.Root()
   431  		log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
   432  	}
   433  	triedb := trie.NewDatabase(chaindb)
   434  	t, err := trie.NewSecure(root, triedb)
   435  	if err != nil {
   436  		log.Error("Failed to open trie", "root", root, "err", err)
   437  		return err
   438  	}
   439  	var (
   440  		accounts   int
   441  		slots      int
   442  		codes      int
   443  		lastReport time.Time
   444  		start      = time.Now()
   445  	)
   446  	accIter := trie.NewIterator(t.NodeIterator(nil))
   447  	for accIter.Next() {
   448  		accounts += 1
   449  		var acc state.Account
   450  		if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
   451  			log.Error("Invalid account encountered during traversal", "err", err)
   452  			return err
   453  		}
   454  		if acc.Root != emptyRoot {
   455  			storageTrie, err := trie.NewSecure(acc.Root, triedb)
   456  			if err != nil {
   457  				log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
   458  				return err
   459  			}
   460  			storageIter := trie.NewIterator(storageTrie.NodeIterator(nil))
   461  			for storageIter.Next() {
   462  				slots += 1
   463  			}
   464  			if storageIter.Err != nil {
   465  				log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
   466  				return storageIter.Err
   467  			}
   468  		}
   469  		if !bytes.Equal(acc.CodeHash, emptyCode) {
   470  			code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
   471  			if len(code) == 0 {
   472  				log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
   473  				return errors.New("missing code")
   474  			}
   475  			codes += 1
   476  		}
   477  		if time.Since(lastReport) > time.Second*8 {
   478  			log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
   479  			lastReport = time.Now()
   480  		}
   481  	}
   482  	if accIter.Err != nil {
   483  		log.Error("Failed to traverse state trie", "root", root, "err", accIter.Err)
   484  		return accIter.Err
   485  	}
   486  	log.Info("State is complete", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
   487  	return nil
   488  }
   489  
   490  // traverseRawState is a helper function used for pruning verification.
   491  // Basically it just iterates the trie, ensure all nodes and associated
   492  // contract codes are present. It's basically identical to traverseState
   493  // but it will check each trie node.
   494  func traverseRawState(ctx *cli.Context) error {
   495  	stack, _ := makeConfigNode(ctx)
   496  	defer stack.Close()
   497  
   498  	chaindb := utils.MakeChainDatabase(ctx, stack, true, false)
   499  	headBlock := rawdb.ReadHeadBlock(chaindb)
   500  	if headBlock == nil {
   501  		log.Error("Failed to load head block")
   502  		return errors.New("no head block")
   503  	}
   504  	if ctx.NArg() > 1 {
   505  		log.Error("Too many arguments given")
   506  		return errors.New("too many arguments")
   507  	}
   508  	var (
   509  		root common.Hash
   510  		err  error
   511  	)
   512  	if ctx.NArg() == 1 {
   513  		root, err = parseRoot(ctx.Args()[0])
   514  		if err != nil {
   515  			log.Error("Failed to resolve state root", "err", err)
   516  			return err
   517  		}
   518  		log.Info("Start traversing the state", "root", root)
   519  	} else {
   520  		root = headBlock.Root()
   521  		log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
   522  	}
   523  	triedb := trie.NewDatabase(chaindb)
   524  	t, err := trie.NewSecure(root, triedb)
   525  	if err != nil {
   526  		log.Error("Failed to open trie", "root", root, "err", err)
   527  		return err
   528  	}
   529  	var (
   530  		nodes      int
   531  		accounts   int
   532  		slots      int
   533  		codes      int
   534  		lastReport time.Time
   535  		start      = time.Now()
   536  	)
   537  	accIter := t.NodeIterator(nil)
   538  	for accIter.Next(true) {
   539  		nodes += 1
   540  		node := accIter.Hash()
   541  
   542  		if node != (common.Hash{}) {
   543  			// Check the present for non-empty hash node(embedded node doesn't
   544  			// have their own hash).
   545  			blob := rawdb.ReadTrieNode(chaindb, node)
   546  			if len(blob) == 0 {
   547  				log.Error("Missing trie node(account)", "hash", node)
   548  				return errors.New("missing account")
   549  			}
   550  		}
   551  		// If it's a leaf node, yes we are touching an account,
   552  		// dig into the storage trie further.
   553  		if accIter.Leaf() {
   554  			accounts += 1
   555  			var acc state.Account
   556  			if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
   557  				log.Error("Invalid account encountered during traversal", "err", err)
   558  				return errors.New("invalid account")
   559  			}
   560  			if acc.Root != emptyRoot {
   561  				storageTrie, err := trie.NewSecure(acc.Root, triedb)
   562  				if err != nil {
   563  					log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
   564  					return errors.New("missing storage trie")
   565  				}
   566  				storageIter := storageTrie.NodeIterator(nil)
   567  				for storageIter.Next(true) {
   568  					nodes += 1
   569  					node := storageIter.Hash()
   570  
   571  					// Check the present for non-empty hash node(embedded node doesn't
   572  					// have their own hash).
   573  					if node != (common.Hash{}) {
   574  						blob := rawdb.ReadTrieNode(chaindb, node)
   575  						if len(blob) == 0 {
   576  							log.Error("Missing trie node(storage)", "hash", node)
   577  							return errors.New("missing storage")
   578  						}
   579  					}
   580  					// Bump the counter if it's leaf node.
   581  					if storageIter.Leaf() {
   582  						slots += 1
   583  					}
   584  				}
   585  				if storageIter.Error() != nil {
   586  					log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
   587  					return storageIter.Error()
   588  				}
   589  			}
   590  			if !bytes.Equal(acc.CodeHash, emptyCode) {
   591  				code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
   592  				if len(code) == 0 {
   593  					log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
   594  					return errors.New("missing code")
   595  				}
   596  				codes += 1
   597  			}
   598  			if time.Since(lastReport) > time.Second*8 {
   599  				log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
   600  				lastReport = time.Now()
   601  			}
   602  		}
   603  	}
   604  	if accIter.Error() != nil {
   605  		log.Error("Failed to traverse state trie", "root", root, "err", accIter.Error())
   606  		return accIter.Error()
   607  	}
   608  	log.Info("State is complete", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
   609  	return nil
   610  }
   611  
   612  func parseRoot(input string) (common.Hash, error) {
   613  	var h common.Hash
   614  	if err := h.UnmarshalText([]byte(input)); err != nil {
   615  		return h, err
   616  	}
   617  	return h, nil
   618  }