snapshot.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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. package main
  17. import (
  18. "bytes"
  19. "encoding/json"
  20. "errors"
  21. "os"
  22. "time"
  23. "github.com/ethereum/go-ethereum/cmd/utils"
  24. "github.com/ethereum/go-ethereum/common"
  25. "github.com/ethereum/go-ethereum/core/rawdb"
  26. "github.com/ethereum/go-ethereum/core/state"
  27. "github.com/ethereum/go-ethereum/core/state/pruner"
  28. "github.com/ethereum/go-ethereum/core/state/snapshot"
  29. "github.com/ethereum/go-ethereum/core/types"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. "github.com/ethereum/go-ethereum/internal/flags"
  32. "github.com/ethereum/go-ethereum/log"
  33. "github.com/ethereum/go-ethereum/rlp"
  34. "github.com/ethereum/go-ethereum/trie"
  35. cli "github.com/urfave/cli/v2"
  36. )
  37. var (
  38. // emptyRoot is the known root hash of an empty trie.
  39. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
  40. // emptyCode is the known hash of the empty EVM bytecode.
  41. emptyCode = crypto.Keccak256(nil)
  42. )
  43. var (
  44. snapshotCommand = &cli.Command{
  45. Name: "snapshot",
  46. Usage: "A set of commands based on the snapshot",
  47. Description: "",
  48. Subcommands: []*cli.Command{
  49. {
  50. Name: "prune-state",
  51. Usage: "Prune stale ethereum state data based on the snapshot",
  52. ArgsUsage: "<root>",
  53. Action: pruneState,
  54. Flags: flags.Merge([]cli.Flag{
  55. utils.CacheTrieJournalFlag,
  56. utils.BloomFilterSizeFlag,
  57. }, utils.NetworkFlags, utils.DatabasePathFlags),
  58. Description: `
  59. geth snapshot prune-state <state-root>
  60. will prune historical state data with the help of the state snapshot.
  61. All trie nodes and contract codes that do not belong to the specified
  62. version state will be deleted from the database. After pruning, only
  63. two version states are available: genesis and the specific one.
  64. The default pruning target is the HEAD-127 state.
  65. WARNING: It's necessary to delete the trie clean cache after the pruning.
  66. If you specify another directory for the trie clean cache via "--cache.trie.journal"
  67. during the use of Geth, please also specify it here for correct deletion. Otherwise
  68. the trie clean cache with default directory will be deleted.
  69. `,
  70. },
  71. {
  72. Name: "verify-state",
  73. Usage: "Recalculate state hash based on the snapshot for verification",
  74. ArgsUsage: "<root>",
  75. Action: verifyState,
  76. Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
  77. Description: `
  78. geth snapshot verify-state <state-root>
  79. will traverse the whole accounts and storages set based on the specified
  80. snapshot and recalculate the root hash of state for verification.
  81. In other words, this command does the snapshot to trie conversion.
  82. `,
  83. },
  84. {
  85. Name: "check-dangling-storage",
  86. Usage: "Check that there is no 'dangling' snap storage",
  87. ArgsUsage: "<root>",
  88. Action: checkDanglingStorage,
  89. Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
  90. Description: `
  91. geth snapshot check-dangling-storage <state-root> traverses the snap storage
  92. data, and verifies that all snapshot storage data has a corresponding account.
  93. `,
  94. },
  95. {
  96. Name: "inspect-account",
  97. Usage: "Check all snapshot layers for the a specific account",
  98. ArgsUsage: "<address | hash>",
  99. Action: checkAccount,
  100. Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
  101. Description: `
  102. geth snapshot inspect-account <address | hash> checks all snapshot layers and prints out
  103. information about the specified address.
  104. `,
  105. },
  106. {
  107. Name: "traverse-state",
  108. Usage: "Traverse the state with given root hash and perform quick verification",
  109. ArgsUsage: "<root>",
  110. Action: traverseState,
  111. Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
  112. Description: `
  113. geth snapshot traverse-state <state-root>
  114. will traverse the whole state from the given state root and will abort if any
  115. referenced trie node or contract code is missing. This command can be used for
  116. state integrity verification. The default checking target is the HEAD state.
  117. It's also usable without snapshot enabled.
  118. `,
  119. },
  120. {
  121. Name: "traverse-rawstate",
  122. Usage: "Traverse the state with given root hash and perform detailed verification",
  123. ArgsUsage: "<root>",
  124. Action: traverseRawState,
  125. Flags: flags.Merge(utils.NetworkFlags, utils.DatabasePathFlags),
  126. Description: `
  127. geth snapshot traverse-rawstate <state-root>
  128. will traverse the whole state from the given root and will abort if any referenced
  129. trie node or contract code is missing. This command can be used for state integrity
  130. verification. The default checking target is the HEAD state. It's basically identical
  131. to traverse-state, but the check granularity is smaller.
  132. It's also usable without snapshot enabled.
  133. `,
  134. },
  135. {
  136. Name: "dump",
  137. Usage: "Dump a specific block from storage (same as 'geth dump' but using snapshots)",
  138. ArgsUsage: "[? <blockHash> | <blockNum>]",
  139. Action: dumpState,
  140. Flags: flags.Merge([]cli.Flag{
  141. utils.ExcludeCodeFlag,
  142. utils.ExcludeStorageFlag,
  143. utils.StartKeyFlag,
  144. utils.DumpLimitFlag,
  145. }, utils.NetworkFlags, utils.DatabasePathFlags),
  146. Description: `
  147. This command is semantically equivalent to 'geth dump', but uses the snapshots
  148. as the backend data source, making this command a lot faster.
  149. The argument is interpreted as block number or hash. If none is provided, the latest
  150. block is used.
  151. `,
  152. },
  153. },
  154. }
  155. )
  156. func pruneState(ctx *cli.Context) error {
  157. stack, config := makeConfigNode(ctx)
  158. defer stack.Close()
  159. chaindb := utils.MakeChainDatabase(ctx, stack, false)
  160. pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.Uint64(utils.BloomFilterSizeFlag.Name))
  161. if err != nil {
  162. log.Error("Failed to open snapshot tree", "err", err)
  163. return err
  164. }
  165. if ctx.NArg() > 1 {
  166. log.Error("Too many arguments given")
  167. return errors.New("too many arguments")
  168. }
  169. var targetRoot common.Hash
  170. if ctx.NArg() == 1 {
  171. targetRoot, err = parseRoot(ctx.Args().First())
  172. if err != nil {
  173. log.Error("Failed to resolve state root", "err", err)
  174. return err
  175. }
  176. }
  177. if err = pruner.Prune(targetRoot); err != nil {
  178. log.Error("Failed to prune state", "err", err)
  179. return err
  180. }
  181. return nil
  182. }
  183. func verifyState(ctx *cli.Context) error {
  184. stack, _ := makeConfigNode(ctx)
  185. defer stack.Close()
  186. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  187. headBlock := rawdb.ReadHeadBlock(chaindb)
  188. if headBlock == nil {
  189. log.Error("Failed to load head block")
  190. return errors.New("no head block")
  191. }
  192. snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false)
  193. if err != nil {
  194. log.Error("Failed to open snapshot tree", "err", err)
  195. return err
  196. }
  197. if ctx.NArg() > 1 {
  198. log.Error("Too many arguments given")
  199. return errors.New("too many arguments")
  200. }
  201. var root = headBlock.Root()
  202. if ctx.NArg() == 1 {
  203. root, err = parseRoot(ctx.Args().First())
  204. if err != nil {
  205. log.Error("Failed to resolve state root", "err", err)
  206. return err
  207. }
  208. }
  209. if err := snaptree.Verify(root); err != nil {
  210. log.Error("Failed to verify state", "root", root, "err", err)
  211. return err
  212. }
  213. log.Info("Verified the state", "root", root)
  214. return snapshot.CheckDanglingStorage(chaindb)
  215. }
  216. // checkDanglingStorage iterates the snap storage data, and verifies that all
  217. // storage also has corresponding account data.
  218. func checkDanglingStorage(ctx *cli.Context) error {
  219. stack, _ := makeConfigNode(ctx)
  220. defer stack.Close()
  221. return snapshot.CheckDanglingStorage(utils.MakeChainDatabase(ctx, stack, true))
  222. }
  223. // traverseState is a helper function used for pruning verification.
  224. // Basically it just iterates the trie, ensure all nodes and associated
  225. // contract codes are present.
  226. func traverseState(ctx *cli.Context) error {
  227. stack, _ := makeConfigNode(ctx)
  228. defer stack.Close()
  229. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  230. headBlock := rawdb.ReadHeadBlock(chaindb)
  231. if headBlock == nil {
  232. log.Error("Failed to load head block")
  233. return errors.New("no head block")
  234. }
  235. if ctx.NArg() > 1 {
  236. log.Error("Too many arguments given")
  237. return errors.New("too many arguments")
  238. }
  239. var (
  240. root common.Hash
  241. err error
  242. )
  243. if ctx.NArg() == 1 {
  244. root, err = parseRoot(ctx.Args().First())
  245. if err != nil {
  246. log.Error("Failed to resolve state root", "err", err)
  247. return err
  248. }
  249. log.Info("Start traversing the state", "root", root)
  250. } else {
  251. root = headBlock.Root()
  252. log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
  253. }
  254. triedb := trie.NewDatabase(chaindb)
  255. t, err := trie.NewStateTrie(common.Hash{}, root, triedb)
  256. if err != nil {
  257. log.Error("Failed to open trie", "root", root, "err", err)
  258. return err
  259. }
  260. var (
  261. accounts int
  262. slots int
  263. codes int
  264. lastReport time.Time
  265. start = time.Now()
  266. )
  267. accIter := trie.NewIterator(t.NodeIterator(nil))
  268. for accIter.Next() {
  269. accounts += 1
  270. var acc types.StateAccount
  271. if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
  272. log.Error("Invalid account encountered during traversal", "err", err)
  273. return err
  274. }
  275. if acc.Root != emptyRoot {
  276. storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.Key), acc.Root, triedb)
  277. if err != nil {
  278. log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
  279. return err
  280. }
  281. storageIter := trie.NewIterator(storageTrie.NodeIterator(nil))
  282. for storageIter.Next() {
  283. slots += 1
  284. }
  285. if storageIter.Err != nil {
  286. log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
  287. return storageIter.Err
  288. }
  289. }
  290. if !bytes.Equal(acc.CodeHash, emptyCode) {
  291. if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
  292. log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
  293. return errors.New("missing code")
  294. }
  295. codes += 1
  296. }
  297. if time.Since(lastReport) > time.Second*8 {
  298. log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  299. lastReport = time.Now()
  300. }
  301. }
  302. if accIter.Err != nil {
  303. log.Error("Failed to traverse state trie", "root", root, "err", accIter.Err)
  304. return accIter.Err
  305. }
  306. log.Info("State is complete", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  307. return nil
  308. }
  309. // traverseRawState is a helper function used for pruning verification.
  310. // Basically it just iterates the trie, ensure all nodes and associated
  311. // contract codes are present. It's basically identical to traverseState
  312. // but it will check each trie node.
  313. func traverseRawState(ctx *cli.Context) error {
  314. stack, _ := makeConfigNode(ctx)
  315. defer stack.Close()
  316. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  317. headBlock := rawdb.ReadHeadBlock(chaindb)
  318. if headBlock == nil {
  319. log.Error("Failed to load head block")
  320. return errors.New("no head block")
  321. }
  322. if ctx.NArg() > 1 {
  323. log.Error("Too many arguments given")
  324. return errors.New("too many arguments")
  325. }
  326. var (
  327. root common.Hash
  328. err error
  329. )
  330. if ctx.NArg() == 1 {
  331. root, err = parseRoot(ctx.Args().First())
  332. if err != nil {
  333. log.Error("Failed to resolve state root", "err", err)
  334. return err
  335. }
  336. log.Info("Start traversing the state", "root", root)
  337. } else {
  338. root = headBlock.Root()
  339. log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
  340. }
  341. triedb := trie.NewDatabase(chaindb)
  342. t, err := trie.NewStateTrie(common.Hash{}, root, triedb)
  343. if err != nil {
  344. log.Error("Failed to open trie", "root", root, "err", err)
  345. return err
  346. }
  347. var (
  348. nodes int
  349. accounts int
  350. slots int
  351. codes int
  352. lastReport time.Time
  353. start = time.Now()
  354. hasher = crypto.NewKeccakState()
  355. got = make([]byte, 32)
  356. )
  357. accIter := t.NodeIterator(nil)
  358. for accIter.Next(true) {
  359. nodes += 1
  360. node := accIter.Hash()
  361. // Check the present for non-empty hash node(embedded node doesn't
  362. // have their own hash).
  363. if node != (common.Hash{}) {
  364. blob := rawdb.ReadTrieNode(chaindb, node)
  365. if len(blob) == 0 {
  366. log.Error("Missing trie node(account)", "hash", node)
  367. return errors.New("missing account")
  368. }
  369. hasher.Reset()
  370. hasher.Write(blob)
  371. hasher.Read(got)
  372. if !bytes.Equal(got, node.Bytes()) {
  373. log.Error("Invalid trie node(account)", "hash", node.Hex(), "value", blob)
  374. return errors.New("invalid account node")
  375. }
  376. }
  377. // If it's a leaf node, yes we are touching an account,
  378. // dig into the storage trie further.
  379. if accIter.Leaf() {
  380. accounts += 1
  381. var acc types.StateAccount
  382. if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
  383. log.Error("Invalid account encountered during traversal", "err", err)
  384. return errors.New("invalid account")
  385. }
  386. if acc.Root != emptyRoot {
  387. storageTrie, err := trie.NewStateTrie(common.BytesToHash(accIter.LeafKey()), acc.Root, triedb)
  388. if err != nil {
  389. log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
  390. return errors.New("missing storage trie")
  391. }
  392. storageIter := storageTrie.NodeIterator(nil)
  393. for storageIter.Next(true) {
  394. nodes += 1
  395. node := storageIter.Hash()
  396. // Check the present for non-empty hash node(embedded node doesn't
  397. // have their own hash).
  398. if node != (common.Hash{}) {
  399. blob := rawdb.ReadTrieNode(chaindb, node)
  400. if len(blob) == 0 {
  401. log.Error("Missing trie node(storage)", "hash", node)
  402. return errors.New("missing storage")
  403. }
  404. hasher.Reset()
  405. hasher.Write(blob)
  406. hasher.Read(got)
  407. if !bytes.Equal(got, node.Bytes()) {
  408. log.Error("Invalid trie node(storage)", "hash", node.Hex(), "value", blob)
  409. return errors.New("invalid storage node")
  410. }
  411. }
  412. // Bump the counter if it's leaf node.
  413. if storageIter.Leaf() {
  414. slots += 1
  415. }
  416. }
  417. if storageIter.Error() != nil {
  418. log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
  419. return storageIter.Error()
  420. }
  421. }
  422. if !bytes.Equal(acc.CodeHash, emptyCode) {
  423. if !rawdb.HasCode(chaindb, common.BytesToHash(acc.CodeHash)) {
  424. log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
  425. return errors.New("missing code")
  426. }
  427. codes += 1
  428. }
  429. if time.Since(lastReport) > time.Second*8 {
  430. log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  431. lastReport = time.Now()
  432. }
  433. }
  434. }
  435. if accIter.Error() != nil {
  436. log.Error("Failed to traverse state trie", "root", root, "err", accIter.Error())
  437. return accIter.Error()
  438. }
  439. log.Info("State is complete", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  440. return nil
  441. }
  442. func parseRoot(input string) (common.Hash, error) {
  443. var h common.Hash
  444. if err := h.UnmarshalText([]byte(input)); err != nil {
  445. return h, err
  446. }
  447. return h, nil
  448. }
  449. func dumpState(ctx *cli.Context) error {
  450. stack, _ := makeConfigNode(ctx)
  451. defer stack.Close()
  452. conf, db, root, err := parseDumpConfig(ctx, stack)
  453. if err != nil {
  454. return err
  455. }
  456. snaptree, err := snapshot.New(db, trie.NewDatabase(db), 256, root, false, false, false)
  457. if err != nil {
  458. return err
  459. }
  460. accIt, err := snaptree.AccountIterator(root, common.BytesToHash(conf.Start))
  461. if err != nil {
  462. return err
  463. }
  464. defer accIt.Release()
  465. log.Info("Snapshot dumping started", "root", root)
  466. var (
  467. start = time.Now()
  468. logged = time.Now()
  469. accounts uint64
  470. )
  471. enc := json.NewEncoder(os.Stdout)
  472. enc.Encode(struct {
  473. Root common.Hash `json:"root"`
  474. }{root})
  475. for accIt.Next() {
  476. account, err := snapshot.FullAccount(accIt.Account())
  477. if err != nil {
  478. return err
  479. }
  480. da := &state.DumpAccount{
  481. Balance: account.Balance.String(),
  482. Nonce: account.Nonce,
  483. Root: account.Root,
  484. CodeHash: account.CodeHash,
  485. SecureKey: accIt.Hash().Bytes(),
  486. }
  487. if !conf.SkipCode && !bytes.Equal(account.CodeHash, emptyCode) {
  488. da.Code = rawdb.ReadCode(db, common.BytesToHash(account.CodeHash))
  489. }
  490. if !conf.SkipStorage {
  491. da.Storage = make(map[common.Hash]string)
  492. stIt, err := snaptree.StorageIterator(root, accIt.Hash(), common.Hash{})
  493. if err != nil {
  494. return err
  495. }
  496. for stIt.Next() {
  497. da.Storage[stIt.Hash()] = common.Bytes2Hex(stIt.Slot())
  498. }
  499. }
  500. enc.Encode(da)
  501. accounts++
  502. if time.Since(logged) > 8*time.Second {
  503. log.Info("Snapshot dumping in progress", "at", accIt.Hash(), "accounts", accounts,
  504. "elapsed", common.PrettyDuration(time.Since(start)))
  505. logged = time.Now()
  506. }
  507. if conf.Max > 0 && accounts >= conf.Max {
  508. break
  509. }
  510. }
  511. log.Info("Snapshot dumping complete", "accounts", accounts,
  512. "elapsed", common.PrettyDuration(time.Since(start)))
  513. return nil
  514. }
  515. // checkAccount iterates the snap data layers, and looks up the given account
  516. // across all layers.
  517. func checkAccount(ctx *cli.Context) error {
  518. if ctx.NArg() != 1 {
  519. return errors.New("need <address|hash> arg")
  520. }
  521. var (
  522. hash common.Hash
  523. addr common.Address
  524. )
  525. switch arg := ctx.Args().First(); len(arg) {
  526. case 40, 42:
  527. addr = common.HexToAddress(arg)
  528. hash = crypto.Keccak256Hash(addr.Bytes())
  529. case 64, 66:
  530. hash = common.HexToHash(arg)
  531. default:
  532. return errors.New("malformed address or hash")
  533. }
  534. stack, _ := makeConfigNode(ctx)
  535. defer stack.Close()
  536. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  537. defer chaindb.Close()
  538. start := time.Now()
  539. log.Info("Checking difflayer journal", "address", addr, "hash", hash)
  540. if err := snapshot.CheckJournalAccount(chaindb, hash); err != nil {
  541. return err
  542. }
  543. log.Info("Checked the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start)))
  544. return nil
  545. }