snapshot.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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. "time"
  21. "github.com/ethereum/go-ethereum/cmd/utils"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/core/rawdb"
  24. "github.com/ethereum/go-ethereum/core/state"
  25. "github.com/ethereum/go-ethereum/core/state/pruner"
  26. "github.com/ethereum/go-ethereum/core/state/snapshot"
  27. "github.com/ethereum/go-ethereum/crypto"
  28. "github.com/ethereum/go-ethereum/log"
  29. "github.com/ethereum/go-ethereum/rlp"
  30. "github.com/ethereum/go-ethereum/trie"
  31. cli "gopkg.in/urfave/cli.v1"
  32. )
  33. var (
  34. // emptyRoot is the known root hash of an empty trie.
  35. emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
  36. // emptyCode is the known hash of the empty EVM bytecode.
  37. emptyCode = crypto.Keccak256(nil)
  38. )
  39. var (
  40. snapshotCommand = cli.Command{
  41. Name: "snapshot",
  42. Usage: "A set of commands based on the snapshot",
  43. Category: "MISCELLANEOUS COMMANDS",
  44. Description: "",
  45. Subcommands: []cli.Command{
  46. {
  47. Name: "prune-state",
  48. Usage: "Prune stale ethereum state data based on the snapshot",
  49. ArgsUsage: "<root>",
  50. Action: utils.MigrateFlags(pruneState),
  51. Category: "MISCELLANEOUS COMMANDS",
  52. Flags: []cli.Flag{
  53. utils.DataDirFlag,
  54. utils.AncientFlag,
  55. utils.RopstenFlag,
  56. utils.RinkebyFlag,
  57. utils.GoerliFlag,
  58. utils.CacheTrieJournalFlag,
  59. utils.BloomFilterSizeFlag,
  60. },
  61. Description: `
  62. geth snapshot prune-state <state-root>
  63. will prune historical state data with the help of the state snapshot.
  64. All trie nodes and contract codes that do not belong to the specified
  65. version state will be deleted from the database. After pruning, only
  66. two version states are available: genesis and the specific one.
  67. The default pruning target is the HEAD-127 state.
  68. WARNING: It's necessary to delete the trie clean cache after the pruning.
  69. If you specify another directory for the trie clean cache via "--cache.trie.journal"
  70. during the use of Geth, please also specify it here for correct deletion. Otherwise
  71. the trie clean cache with default directory will be deleted.
  72. `,
  73. },
  74. {
  75. Name: "verify-state",
  76. Usage: "Recalculate state hash based on the snapshot for verification",
  77. ArgsUsage: "<root>",
  78. Action: utils.MigrateFlags(verifyState),
  79. Category: "MISCELLANEOUS COMMANDS",
  80. Flags: []cli.Flag{
  81. utils.DataDirFlag,
  82. utils.AncientFlag,
  83. utils.RopstenFlag,
  84. utils.RinkebyFlag,
  85. utils.GoerliFlag,
  86. },
  87. Description: `
  88. geth snapshot verify-state <state-root>
  89. will traverse the whole accounts and storages set based on the specified
  90. snapshot and recalculate the root hash of state for verification.
  91. In other words, this command does the snapshot to trie conversion.
  92. `,
  93. },
  94. {
  95. Name: "traverse-state",
  96. Usage: "Traverse the state with given root hash for verification",
  97. ArgsUsage: "<root>",
  98. Action: utils.MigrateFlags(traverseState),
  99. Category: "MISCELLANEOUS COMMANDS",
  100. Flags: []cli.Flag{
  101. utils.DataDirFlag,
  102. utils.AncientFlag,
  103. utils.RopstenFlag,
  104. utils.RinkebyFlag,
  105. utils.GoerliFlag,
  106. },
  107. Description: `
  108. geth snapshot traverse-state <state-root>
  109. will traverse the whole state from the given state root and will abort if any
  110. referenced trie node or contract code is missing. This command can be used for
  111. state integrity verification. The default checking target is the HEAD state.
  112. It's also usable without snapshot enabled.
  113. `,
  114. },
  115. {
  116. Name: "traverse-rawstate",
  117. Usage: "Traverse the state with given root hash for verification",
  118. ArgsUsage: "<root>",
  119. Action: utils.MigrateFlags(traverseRawState),
  120. Category: "MISCELLANEOUS COMMANDS",
  121. Flags: []cli.Flag{
  122. utils.DataDirFlag,
  123. utils.AncientFlag,
  124. utils.RopstenFlag,
  125. utils.RinkebyFlag,
  126. utils.GoerliFlag,
  127. },
  128. Description: `
  129. geth snapshot traverse-rawstate <state-root>
  130. will traverse the whole state from the given root and will abort if any referenced
  131. trie node or contract code is missing. This command can be used for state integrity
  132. verification. The default checking target is the HEAD state. It's basically identical
  133. to traverse-state, but the check granularity is smaller.
  134. It's also usable without snapshot enabled.
  135. `,
  136. },
  137. },
  138. }
  139. )
  140. func pruneState(ctx *cli.Context) error {
  141. stack, config := makeConfigNode(ctx)
  142. defer stack.Close()
  143. chaindb := utils.MakeChainDatabase(ctx, stack, false)
  144. // Quorum
  145. if config.Eth.Genesis.Config.IsQuorum {
  146. log.Error("Can not prune state when using GoQuorum as this has an impact on private state")
  147. return errors.New("prune-state is not available when IsQuorum is enabled")
  148. }
  149. pruner, err := pruner.NewPruner(chaindb, stack.ResolvePath(""), stack.ResolvePath(config.Eth.TrieCleanCacheJournal), ctx.GlobalUint64(utils.BloomFilterSizeFlag.Name))
  150. if err != nil {
  151. log.Error("Failed to open snapshot tree", "err", err)
  152. return err
  153. }
  154. if ctx.NArg() > 1 {
  155. log.Error("Too many arguments given")
  156. return errors.New("too many arguments")
  157. }
  158. var targetRoot common.Hash
  159. if ctx.NArg() == 1 {
  160. targetRoot, err = parseRoot(ctx.Args()[0])
  161. if err != nil {
  162. log.Error("Failed to resolve state root", "err", err)
  163. return err
  164. }
  165. }
  166. if err = pruner.Prune(targetRoot); err != nil {
  167. log.Error("Failed to prune state", "err", err)
  168. return err
  169. }
  170. return nil
  171. }
  172. func verifyState(ctx *cli.Context) error {
  173. stack, _ := makeConfigNode(ctx)
  174. defer stack.Close()
  175. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  176. headBlock := rawdb.ReadHeadBlock(chaindb)
  177. if headBlock == nil {
  178. log.Error("Failed to load head block")
  179. return errors.New("no head block")
  180. }
  181. snaptree, err := snapshot.New(chaindb, trie.NewDatabase(chaindb), 256, headBlock.Root(), false, false, false)
  182. if err != nil {
  183. log.Error("Failed to open snapshot tree", "err", err)
  184. return err
  185. }
  186. if ctx.NArg() > 1 {
  187. log.Error("Too many arguments given")
  188. return errors.New("too many arguments")
  189. }
  190. var root = headBlock.Root()
  191. if ctx.NArg() == 1 {
  192. root, err = parseRoot(ctx.Args()[0])
  193. if err != nil {
  194. log.Error("Failed to resolve state root", "err", err)
  195. return err
  196. }
  197. }
  198. if err := snaptree.Verify(root); err != nil {
  199. log.Error("Failed to verify state", "root", root, "err", err)
  200. return err
  201. }
  202. log.Info("Verified the state", "root", root)
  203. return nil
  204. }
  205. // traverseState is a helper function used for pruning verification.
  206. // Basically it just iterates the trie, ensure all nodes and associated
  207. // contract codes are present.
  208. func traverseState(ctx *cli.Context) error {
  209. stack, _ := makeConfigNode(ctx)
  210. defer stack.Close()
  211. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  212. headBlock := rawdb.ReadHeadBlock(chaindb)
  213. if headBlock == nil {
  214. log.Error("Failed to load head block")
  215. return errors.New("no head block")
  216. }
  217. if ctx.NArg() > 1 {
  218. log.Error("Too many arguments given")
  219. return errors.New("too many arguments")
  220. }
  221. var (
  222. root common.Hash
  223. err error
  224. )
  225. if ctx.NArg() == 1 {
  226. root, err = parseRoot(ctx.Args()[0])
  227. if err != nil {
  228. log.Error("Failed to resolve state root", "err", err)
  229. return err
  230. }
  231. log.Info("Start traversing the state", "root", root)
  232. } else {
  233. root = headBlock.Root()
  234. log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
  235. }
  236. triedb := trie.NewDatabase(chaindb)
  237. t, err := trie.NewSecure(root, triedb)
  238. if err != nil {
  239. log.Error("Failed to open trie", "root", root, "err", err)
  240. return err
  241. }
  242. var (
  243. accounts int
  244. slots int
  245. codes int
  246. lastReport time.Time
  247. start = time.Now()
  248. )
  249. accIter := trie.NewIterator(t.NodeIterator(nil))
  250. for accIter.Next() {
  251. accounts += 1
  252. var acc state.Account
  253. if err := rlp.DecodeBytes(accIter.Value, &acc); err != nil {
  254. log.Error("Invalid account encountered during traversal", "err", err)
  255. return err
  256. }
  257. if acc.Root != emptyRoot {
  258. storageTrie, err := trie.NewSecure(acc.Root, triedb)
  259. if err != nil {
  260. log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
  261. return err
  262. }
  263. storageIter := trie.NewIterator(storageTrie.NodeIterator(nil))
  264. for storageIter.Next() {
  265. slots += 1
  266. }
  267. if storageIter.Err != nil {
  268. log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Err)
  269. return storageIter.Err
  270. }
  271. }
  272. if !bytes.Equal(acc.CodeHash, emptyCode) {
  273. code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
  274. if len(code) == 0 {
  275. log.Error("Code is missing", "hash", common.BytesToHash(acc.CodeHash))
  276. return errors.New("missing code")
  277. }
  278. codes += 1
  279. }
  280. if time.Since(lastReport) > time.Second*8 {
  281. log.Info("Traversing state", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  282. lastReport = time.Now()
  283. }
  284. }
  285. if accIter.Err != nil {
  286. log.Error("Failed to traverse state trie", "root", root, "err", accIter.Err)
  287. return accIter.Err
  288. }
  289. log.Info("State is complete", "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  290. return nil
  291. }
  292. // traverseRawState is a helper function used for pruning verification.
  293. // Basically it just iterates the trie, ensure all nodes and associated
  294. // contract codes are present. It's basically identical to traverseState
  295. // but it will check each trie node.
  296. func traverseRawState(ctx *cli.Context) error {
  297. stack, _ := makeConfigNode(ctx)
  298. defer stack.Close()
  299. chaindb := utils.MakeChainDatabase(ctx, stack, true)
  300. headBlock := rawdb.ReadHeadBlock(chaindb)
  301. if headBlock == nil {
  302. log.Error("Failed to load head block")
  303. return errors.New("no head block")
  304. }
  305. if ctx.NArg() > 1 {
  306. log.Error("Too many arguments given")
  307. return errors.New("too many arguments")
  308. }
  309. var (
  310. root common.Hash
  311. err error
  312. )
  313. if ctx.NArg() == 1 {
  314. root, err = parseRoot(ctx.Args()[0])
  315. if err != nil {
  316. log.Error("Failed to resolve state root", "err", err)
  317. return err
  318. }
  319. log.Info("Start traversing the state", "root", root)
  320. } else {
  321. root = headBlock.Root()
  322. log.Info("Start traversing the state", "root", root, "number", headBlock.NumberU64())
  323. }
  324. triedb := trie.NewDatabase(chaindb)
  325. t, err := trie.NewSecure(root, triedb)
  326. if err != nil {
  327. log.Error("Failed to open trie", "root", root, "err", err)
  328. return err
  329. }
  330. var (
  331. nodes int
  332. accounts int
  333. slots int
  334. codes int
  335. lastReport time.Time
  336. start = time.Now()
  337. )
  338. accIter := t.NodeIterator(nil)
  339. for accIter.Next(true) {
  340. nodes += 1
  341. node := accIter.Hash()
  342. if node != (common.Hash{}) {
  343. // Check the present for non-empty hash node(embedded node doesn't
  344. // have their own hash).
  345. blob := rawdb.ReadTrieNode(chaindb, node)
  346. if len(blob) == 0 {
  347. log.Error("Missing trie node(account)", "hash", node)
  348. return errors.New("missing account")
  349. }
  350. }
  351. // If it's a leaf node, yes we are touching an account,
  352. // dig into the storage trie further.
  353. if accIter.Leaf() {
  354. accounts += 1
  355. var acc state.Account
  356. if err := rlp.DecodeBytes(accIter.LeafBlob(), &acc); err != nil {
  357. log.Error("Invalid account encountered during traversal", "err", err)
  358. return errors.New("invalid account")
  359. }
  360. if acc.Root != emptyRoot {
  361. storageTrie, err := trie.NewSecure(acc.Root, triedb)
  362. if err != nil {
  363. log.Error("Failed to open storage trie", "root", acc.Root, "err", err)
  364. return errors.New("missing storage trie")
  365. }
  366. storageIter := storageTrie.NodeIterator(nil)
  367. for storageIter.Next(true) {
  368. nodes += 1
  369. node := storageIter.Hash()
  370. // Check the present for non-empty hash node(embedded node doesn't
  371. // have their own hash).
  372. if node != (common.Hash{}) {
  373. blob := rawdb.ReadTrieNode(chaindb, node)
  374. if len(blob) == 0 {
  375. log.Error("Missing trie node(storage)", "hash", node)
  376. return errors.New("missing storage")
  377. }
  378. }
  379. // Bump the counter if it's leaf node.
  380. if storageIter.Leaf() {
  381. slots += 1
  382. }
  383. }
  384. if storageIter.Error() != nil {
  385. log.Error("Failed to traverse storage trie", "root", acc.Root, "err", storageIter.Error())
  386. return storageIter.Error()
  387. }
  388. }
  389. if !bytes.Equal(acc.CodeHash, emptyCode) {
  390. code := rawdb.ReadCode(chaindb, common.BytesToHash(acc.CodeHash))
  391. if len(code) == 0 {
  392. log.Error("Code is missing", "account", common.BytesToHash(accIter.LeafKey()))
  393. return errors.New("missing code")
  394. }
  395. codes += 1
  396. }
  397. if time.Since(lastReport) > time.Second*8 {
  398. log.Info("Traversing state", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  399. lastReport = time.Now()
  400. }
  401. }
  402. }
  403. if accIter.Error() != nil {
  404. log.Error("Failed to traverse state trie", "root", root, "err", accIter.Error())
  405. return accIter.Error()
  406. }
  407. log.Info("State is complete", "nodes", nodes, "accounts", accounts, "slots", slots, "codes", codes, "elapsed", common.PrettyDuration(time.Since(start)))
  408. return nil
  409. }
  410. func parseRoot(input string) (common.Hash, error) {
  411. var h common.Hash
  412. if err := h.UnmarshalText([]byte(input)); err != nil {
  413. return h, err
  414. }
  415. return h, nil
  416. }