snapshot.go 21 KB

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