blockchain_snapshot_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. // Copyright 2020 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser 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. // The go-ethereum library 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 Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. // Tests that abnormal program termination (i.e.crash) and restart can recovery
  17. // the snapshot properly if the snapshot is enabled.
  18. package core
  19. import (
  20. "bytes"
  21. "fmt"
  22. "io/ioutil"
  23. "os"
  24. "strings"
  25. "testing"
  26. "time"
  27. "github.com/ethereum/go-ethereum/consensus"
  28. "github.com/ethereum/go-ethereum/consensus/ethash"
  29. "github.com/ethereum/go-ethereum/core/rawdb"
  30. "github.com/ethereum/go-ethereum/core/types"
  31. "github.com/ethereum/go-ethereum/core/vm"
  32. "github.com/ethereum/go-ethereum/ethdb"
  33. "github.com/ethereum/go-ethereum/params"
  34. )
  35. // snapshotTestBasic wraps the common testing fields in the snapshot tests.
  36. type snapshotTestBasic struct {
  37. chainBlocks int // Number of blocks to generate for the canonical chain
  38. snapshotBlock uint64 // Block number of the relevant snapshot disk layer
  39. commitBlock uint64 // Block number for which to commit the state to disk
  40. expCanonicalBlocks int // Number of canonical blocks expected to remain in the database (excl. genesis)
  41. expHeadHeader uint64 // Block number of the expected head header
  42. expHeadFastBlock uint64 // Block number of the expected head fast sync block
  43. expHeadBlock uint64 // Block number of the expected head full block
  44. expSnapshotBottom uint64 // The block height corresponding to the snapshot disk layer
  45. // share fields, set in runtime
  46. datadir string
  47. db ethdb.Database
  48. gendb ethdb.Database
  49. engine consensus.Engine
  50. }
  51. func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) {
  52. // Create a temporary persistent database
  53. datadir, err := ioutil.TempDir("", "")
  54. if err != nil {
  55. t.Fatalf("Failed to create temporary datadir: %v", err)
  56. }
  57. os.RemoveAll(datadir)
  58. db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false)
  59. if err != nil {
  60. t.Fatalf("Failed to create persistent database: %v", err)
  61. }
  62. // Initialize a fresh chain
  63. var (
  64. genesis = new(Genesis).MustCommit(db)
  65. engine = ethash.NewFullFaker()
  66. gendb = rawdb.NewMemoryDatabase()
  67. // Snapshot is enabled, the first snapshot is created from the Genesis.
  68. // The snapshot memory allowance is 256MB, it means no snapshot flush
  69. // will happen during the block insertion.
  70. cacheConfig = defaultCacheConfig
  71. )
  72. chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil)
  73. if err != nil {
  74. t.Fatalf("Failed to create chain: %v", err)
  75. }
  76. blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {})
  77. // Insert the blocks with configured settings.
  78. var breakpoints []uint64
  79. if basic.commitBlock > basic.snapshotBlock {
  80. breakpoints = append(breakpoints, basic.snapshotBlock, basic.commitBlock)
  81. } else {
  82. breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
  83. }
  84. var startPoint uint64
  85. for _, point := range breakpoints {
  86. if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
  87. t.Fatalf("Failed to import canonical chain start: %v", err)
  88. }
  89. startPoint = point
  90. if basic.commitBlock > 0 && basic.commitBlock == point {
  91. chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil)
  92. }
  93. if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
  94. // Flushing the entire snap tree into the disk, the
  95. // relavant (a) snapshot root and (b) snapshot generator
  96. // will be persisted atomically.
  97. chain.snaps.Cap(blocks[point-1].Root(), 0)
  98. diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root()
  99. if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
  100. t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
  101. }
  102. }
  103. }
  104. if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
  105. t.Fatalf("Failed to import canonical chain tail: %v", err)
  106. }
  107. // Set runtime fields
  108. basic.datadir = datadir
  109. basic.db = db
  110. basic.gendb = gendb
  111. basic.engine = engine
  112. return chain, blocks
  113. }
  114. func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks []*types.Block) {
  115. // Iterate over all the remaining blocks and ensure there are no gaps
  116. verifyNoGaps(t, chain, true, blocks)
  117. verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
  118. if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
  119. t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
  120. }
  121. if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
  122. t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
  123. }
  124. if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
  125. t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
  126. }
  127. // Check the disk layer, ensure they are matched
  128. block := chain.GetBlockByNumber(basic.expSnapshotBottom)
  129. if block == nil {
  130. t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
  131. } else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
  132. t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
  133. }
  134. // Check the snapshot, ensure it's integrated
  135. if err := chain.snaps.Verify(block.Root()); err != nil {
  136. t.Errorf("The disk layer is not integrated %v", err)
  137. }
  138. }
  139. func (basic *snapshotTestBasic) dump() string {
  140. buffer := new(strings.Builder)
  141. fmt.Fprint(buffer, "Chain:\n G")
  142. for i := 0; i < basic.chainBlocks; i++ {
  143. fmt.Fprintf(buffer, "->C%d", i+1)
  144. }
  145. fmt.Fprint(buffer, " (HEAD)\n\n")
  146. fmt.Fprintf(buffer, "Commit: G")
  147. if basic.commitBlock > 0 {
  148. fmt.Fprintf(buffer, ", C%d", basic.commitBlock)
  149. }
  150. fmt.Fprint(buffer, "\n")
  151. fmt.Fprintf(buffer, "Snapshot: G")
  152. if basic.snapshotBlock > 0 {
  153. fmt.Fprintf(buffer, ", C%d", basic.snapshotBlock)
  154. }
  155. fmt.Fprint(buffer, "\n")
  156. //if crash {
  157. // fmt.Fprintf(buffer, "\nCRASH\n\n")
  158. //} else {
  159. // fmt.Fprintf(buffer, "\nSetHead(%d)\n\n", basic.setHead)
  160. //}
  161. fmt.Fprintf(buffer, "------------------------------\n\n")
  162. fmt.Fprint(buffer, "Expected in leveldb:\n G")
  163. for i := 0; i < basic.expCanonicalBlocks; i++ {
  164. fmt.Fprintf(buffer, "->C%d", i+1)
  165. }
  166. fmt.Fprintf(buffer, "\n\n")
  167. fmt.Fprintf(buffer, "Expected head header : C%d\n", basic.expHeadHeader)
  168. fmt.Fprintf(buffer, "Expected head fast block: C%d\n", basic.expHeadFastBlock)
  169. if basic.expHeadBlock == 0 {
  170. fmt.Fprintf(buffer, "Expected head block : G\n")
  171. } else {
  172. fmt.Fprintf(buffer, "Expected head block : C%d\n", basic.expHeadBlock)
  173. }
  174. if basic.expSnapshotBottom == 0 {
  175. fmt.Fprintf(buffer, "Expected snapshot disk : G\n")
  176. } else {
  177. fmt.Fprintf(buffer, "Expected snapshot disk : C%d\n", basic.expSnapshotBottom)
  178. }
  179. return buffer.String()
  180. }
  181. func (basic *snapshotTestBasic) teardown() {
  182. basic.db.Close()
  183. basic.gendb.Close()
  184. os.RemoveAll(basic.datadir)
  185. }
  186. // snapshotTest is a test case type for normal snapshot recovery.
  187. // It can be used for testing that restart Geth normally.
  188. type snapshotTest struct {
  189. snapshotTestBasic
  190. }
  191. func (snaptest *snapshotTest) test(t *testing.T) {
  192. // It's hard to follow the test case, visualize the input
  193. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  194. // fmt.Println(tt.dump())
  195. chain, blocks := snaptest.prepare(t)
  196. // Restart the chain normally
  197. chain.Stop()
  198. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  199. if err != nil {
  200. t.Fatalf("Failed to recreate chain: %v", err)
  201. }
  202. defer newchain.Stop()
  203. snaptest.verify(t, newchain, blocks)
  204. }
  205. // crashSnapshotTest is a test case type for innormal snapshot recovery.
  206. // It can be used for testing that restart Geth after the crash.
  207. type crashSnapshotTest struct {
  208. snapshotTestBasic
  209. }
  210. func (snaptest *crashSnapshotTest) test(t *testing.T) {
  211. // It's hard to follow the test case, visualize the input
  212. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  213. // fmt.Println(tt.dump())
  214. chain, blocks := snaptest.prepare(t)
  215. // Pull the plug on the database, simulating a hard crash
  216. db := chain.db
  217. db.Close()
  218. // Start a new blockchain back up and see where the repair leads us
  219. newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false)
  220. if err != nil {
  221. t.Fatalf("Failed to reopen persistent database: %v", err)
  222. }
  223. defer newdb.Close()
  224. // The interesting thing is: instead of starting the blockchain after
  225. // the crash, we do restart twice here: one after the crash and one
  226. // after the normal stop. It's used to ensure the broken snapshot
  227. // can be detected all the time.
  228. newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  229. if err != nil {
  230. t.Fatalf("Failed to recreate chain: %v", err)
  231. }
  232. newchain.Stop()
  233. newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  234. if err != nil {
  235. t.Fatalf("Failed to recreate chain: %v", err)
  236. }
  237. defer newchain.Stop()
  238. snaptest.verify(t, newchain, blocks)
  239. }
  240. // gappedSnapshotTest is a test type used to test this scenario:
  241. // - have a complete snapshot
  242. // - restart without enabling the snapshot
  243. // - insert a few blocks
  244. // - restart with enabling the snapshot again
  245. type gappedSnapshotTest struct {
  246. snapshotTestBasic
  247. gapped int // Number of blocks to insert without enabling snapshot
  248. }
  249. func (snaptest *gappedSnapshotTest) test(t *testing.T) {
  250. // It's hard to follow the test case, visualize the input
  251. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  252. // fmt.Println(tt.dump())
  253. chain, blocks := snaptest.prepare(t)
  254. // Insert blocks without enabling snapshot if gapping is required.
  255. chain.Stop()
  256. gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {})
  257. // Insert a few more blocks without enabling snapshot
  258. var cacheConfig = &CacheConfig{
  259. TrieCleanLimit: 256,
  260. TrieDirtyLimit: 256,
  261. TrieTimeLimit: 5 * time.Minute,
  262. SnapshotLimit: 0,
  263. }
  264. newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  265. if err != nil {
  266. t.Fatalf("Failed to recreate chain: %v", err)
  267. }
  268. newchain.InsertChain(gappedBlocks)
  269. newchain.Stop()
  270. // Restart the chain with enabling the snapshot
  271. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  272. if err != nil {
  273. t.Fatalf("Failed to recreate chain: %v", err)
  274. }
  275. defer newchain.Stop()
  276. snaptest.verify(t, newchain, blocks)
  277. }
  278. // setHeadSnapshotTest is the test type used to test this scenario:
  279. // - have a complete snapshot
  280. // - set the head to a lower point
  281. // - restart
  282. type setHeadSnapshotTest struct {
  283. snapshotTestBasic
  284. setHead uint64 // Block number to set head back to
  285. }
  286. func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
  287. // It's hard to follow the test case, visualize the input
  288. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  289. // fmt.Println(tt.dump())
  290. chain, blocks := snaptest.prepare(t)
  291. // Rewind the chain if setHead operation is required.
  292. chain.SetHead(snaptest.setHead)
  293. chain.Stop()
  294. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  295. if err != nil {
  296. t.Fatalf("Failed to recreate chain: %v", err)
  297. }
  298. defer newchain.Stop()
  299. snaptest.verify(t, newchain, blocks)
  300. }
  301. // restartCrashSnapshotTest is the test type used to test this scenario:
  302. // - have a complete snapshot
  303. // - restart chain
  304. // - insert more blocks with enabling the snapshot
  305. // - commit the snapshot
  306. // - crash
  307. // - restart again
  308. type restartCrashSnapshotTest struct {
  309. snapshotTestBasic
  310. newBlocks int
  311. }
  312. func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
  313. // It's hard to follow the test case, visualize the input
  314. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  315. // fmt.Println(tt.dump())
  316. chain, blocks := snaptest.prepare(t)
  317. // Firstly, stop the chain properly, with all snapshot journal
  318. // and state committed.
  319. chain.Stop()
  320. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  321. if err != nil {
  322. t.Fatalf("Failed to recreate chain: %v", err)
  323. }
  324. newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
  325. newchain.InsertChain(newBlocks)
  326. // Commit the entire snapshot into the disk if requested. Note only
  327. // (a) snapshot root and (b) snapshot generator will be committed,
  328. // the diff journal is not.
  329. newchain.Snapshots().Cap(newBlocks[len(newBlocks)-1].Root(), 0)
  330. // Simulate the blockchain crash
  331. // Don't call chain.Stop here, so that no snapshot
  332. // journal and latest state will be committed
  333. // Restart the chain after the crash
  334. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  335. if err != nil {
  336. t.Fatalf("Failed to recreate chain: %v", err)
  337. }
  338. defer newchain.Stop()
  339. snaptest.verify(t, newchain, blocks)
  340. }
  341. // wipeCrashSnapshotTest is the test type used to test this scenario:
  342. // - have a complete snapshot
  343. // - restart, insert more blocks without enabling the snapshot
  344. // - restart again with enabling the snapshot
  345. // - crash
  346. type wipeCrashSnapshotTest struct {
  347. snapshotTestBasic
  348. newBlocks int
  349. }
  350. func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
  351. // It's hard to follow the test case, visualize the input
  352. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  353. // fmt.Println(tt.dump())
  354. chain, blocks := snaptest.prepare(t)
  355. // Firstly, stop the chain properly, with all snapshot journal
  356. // and state committed.
  357. chain.Stop()
  358. config := &CacheConfig{
  359. TrieCleanLimit: 256,
  360. TrieDirtyLimit: 256,
  361. TrieTimeLimit: 5 * time.Minute,
  362. SnapshotLimit: 0,
  363. }
  364. newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  365. if err != nil {
  366. t.Fatalf("Failed to recreate chain: %v", err)
  367. }
  368. newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
  369. newchain.InsertChain(newBlocks)
  370. newchain.Stop()
  371. // Restart the chain, the wiper should starts working
  372. config = &CacheConfig{
  373. TrieCleanLimit: 256,
  374. TrieDirtyLimit: 256,
  375. TrieTimeLimit: 5 * time.Minute,
  376. SnapshotLimit: 256,
  377. SnapshotWait: false, // Don't wait rebuild
  378. }
  379. newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  380. if err != nil {
  381. t.Fatalf("Failed to recreate chain: %v", err)
  382. }
  383. // Simulate the blockchain crash.
  384. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil)
  385. if err != nil {
  386. t.Fatalf("Failed to recreate chain: %v", err)
  387. }
  388. snaptest.verify(t, newchain, blocks)
  389. }
  390. // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot
  391. // journal will be persisted correctly. In this case no snapshot recovery is
  392. // required.
  393. func TestRestartWithNewSnapshot(t *testing.T) {
  394. // Chain:
  395. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  396. //
  397. // Commit: G
  398. // Snapshot: G
  399. //
  400. // SetHead(0)
  401. //
  402. // ------------------------------
  403. //
  404. // Expected in leveldb:
  405. // G->C1->C2->C3->C4->C5->C6->C7->C8
  406. //
  407. // Expected head header : C8
  408. // Expected head fast block: C8
  409. // Expected head block : C8
  410. // Expected snapshot disk : G
  411. test := &snapshotTest{
  412. snapshotTestBasic{
  413. chainBlocks: 8,
  414. snapshotBlock: 0,
  415. commitBlock: 0,
  416. expCanonicalBlocks: 8,
  417. expHeadHeader: 8,
  418. expHeadFastBlock: 8,
  419. expHeadBlock: 8,
  420. expSnapshotBottom: 0, // Initial disk layer built from genesis
  421. },
  422. }
  423. test.test(t)
  424. test.teardown()
  425. }
  426. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  427. // chain head should be rewound to the point with available state. And also the
  428. // new head should must be lower than disk layer. But there is no committed point
  429. // so the chain should be rewound to genesis and the disk layer should be left
  430. // for recovery.
  431. func TestNoCommitCrashWithNewSnapshot(t *testing.T) {
  432. // Chain:
  433. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  434. //
  435. // Commit: G
  436. // Snapshot: G, C4
  437. //
  438. // CRASH
  439. //
  440. // ------------------------------
  441. //
  442. // Expected in leveldb:
  443. // G->C1->C2->C3->C4->C5->C6->C7->C8
  444. //
  445. // Expected head header : C8
  446. // Expected head fast block: C8
  447. // Expected head block : G
  448. // Expected snapshot disk : C4
  449. test := &crashSnapshotTest{
  450. snapshotTestBasic{
  451. chainBlocks: 8,
  452. snapshotBlock: 4,
  453. commitBlock: 0,
  454. expCanonicalBlocks: 8,
  455. expHeadHeader: 8,
  456. expHeadFastBlock: 8,
  457. expHeadBlock: 0,
  458. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  459. },
  460. }
  461. test.test(t)
  462. test.teardown()
  463. }
  464. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  465. // chain head should be rewound to the point with available state. And also the
  466. // new head should must be lower than disk layer. But there is only a low committed
  467. // point so the chain should be rewound to committed point and the disk layer
  468. // should be left for recovery.
  469. func TestLowCommitCrashWithNewSnapshot(t *testing.T) {
  470. // Chain:
  471. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  472. //
  473. // Commit: G, C2
  474. // Snapshot: G, C4
  475. //
  476. // CRASH
  477. //
  478. // ------------------------------
  479. //
  480. // Expected in leveldb:
  481. // G->C1->C2->C3->C4->C5->C6->C7->C8
  482. //
  483. // Expected head header : C8
  484. // Expected head fast block: C8
  485. // Expected head block : C2
  486. // Expected snapshot disk : C4
  487. test := &crashSnapshotTest{
  488. snapshotTestBasic{
  489. chainBlocks: 8,
  490. snapshotBlock: 4,
  491. commitBlock: 2,
  492. expCanonicalBlocks: 8,
  493. expHeadHeader: 8,
  494. expHeadFastBlock: 8,
  495. expHeadBlock: 2,
  496. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  497. },
  498. }
  499. test.test(t)
  500. test.teardown()
  501. }
  502. // Tests a Geth was crashed and restarts with a broken snapshot. In this case
  503. // the chain head should be rewound to the point with available state. And also
  504. // the new head should must be lower than disk layer. But there is only a high
  505. // committed point so the chain should be rewound to genesis and the disk layer
  506. // should be left for recovery.
  507. func TestHighCommitCrashWithNewSnapshot(t *testing.T) {
  508. // Chain:
  509. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  510. //
  511. // Commit: G, C6
  512. // Snapshot: G, C4
  513. //
  514. // CRASH
  515. //
  516. // ------------------------------
  517. //
  518. // Expected in leveldb:
  519. // G->C1->C2->C3->C4->C5->C6->C7->C8
  520. //
  521. // Expected head header : C8
  522. // Expected head fast block: C8
  523. // Expected head block : G
  524. // Expected snapshot disk : C4
  525. test := &crashSnapshotTest{
  526. snapshotTestBasic{
  527. chainBlocks: 8,
  528. snapshotBlock: 4,
  529. commitBlock: 6,
  530. expCanonicalBlocks: 8,
  531. expHeadHeader: 8,
  532. expHeadFastBlock: 8,
  533. expHeadBlock: 0,
  534. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  535. },
  536. }
  537. test.test(t)
  538. test.teardown()
  539. }
  540. // Tests a Geth was running with snapshot enabled. Then restarts without
  541. // enabling snapshot and after that re-enable the snapshot again. In this
  542. // case the snapshot should be rebuilt with latest chain head.
  543. func TestGappedNewSnapshot(t *testing.T) {
  544. // Chain:
  545. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  546. //
  547. // Commit: G
  548. // Snapshot: G
  549. //
  550. // SetHead(0)
  551. //
  552. // ------------------------------
  553. //
  554. // Expected in leveldb:
  555. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  556. //
  557. // Expected head header : C10
  558. // Expected head fast block: C10
  559. // Expected head block : C10
  560. // Expected snapshot disk : C10
  561. test := &gappedSnapshotTest{
  562. snapshotTestBasic: snapshotTestBasic{
  563. chainBlocks: 8,
  564. snapshotBlock: 0,
  565. commitBlock: 0,
  566. expCanonicalBlocks: 10,
  567. expHeadHeader: 10,
  568. expHeadFastBlock: 10,
  569. expHeadBlock: 10,
  570. expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
  571. },
  572. gapped: 2,
  573. }
  574. test.test(t)
  575. test.teardown()
  576. }
  577. // Tests the Geth was running with snapshot enabled and resetHead is applied.
  578. // In this case the head is rewound to the target(with state available). After
  579. // that the chain is restarted and the original disk layer is kept.
  580. func TestSetHeadWithNewSnapshot(t *testing.T) {
  581. // Chain:
  582. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  583. //
  584. // Commit: G
  585. // Snapshot: G
  586. //
  587. // SetHead(4)
  588. //
  589. // ------------------------------
  590. //
  591. // Expected in leveldb:
  592. // G->C1->C2->C3->C4
  593. //
  594. // Expected head header : C4
  595. // Expected head fast block: C4
  596. // Expected head block : C4
  597. // Expected snapshot disk : G
  598. test := &setHeadSnapshotTest{
  599. snapshotTestBasic: snapshotTestBasic{
  600. chainBlocks: 8,
  601. snapshotBlock: 0,
  602. commitBlock: 0,
  603. expCanonicalBlocks: 4,
  604. expHeadHeader: 4,
  605. expHeadFastBlock: 4,
  606. expHeadBlock: 4,
  607. expSnapshotBottom: 0, // The initial disk layer is built from the genesis
  608. },
  609. setHead: 4,
  610. }
  611. test.test(t)
  612. test.teardown()
  613. }
  614. // Tests the Geth was running with a complete snapshot and then imports a few
  615. // more new blocks on top without enabling the snapshot. After the restart,
  616. // crash happens. Check everything is ok after the restart.
  617. func TestRecoverSnapshotFromWipingCrash(t *testing.T) {
  618. // Chain:
  619. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  620. //
  621. // Commit: G
  622. // Snapshot: G
  623. //
  624. // SetHead(0)
  625. //
  626. // ------------------------------
  627. //
  628. // Expected in leveldb:
  629. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  630. //
  631. // Expected head header : C10
  632. // Expected head fast block: C10
  633. // Expected head block : C8
  634. // Expected snapshot disk : C10
  635. test := &wipeCrashSnapshotTest{
  636. snapshotTestBasic: snapshotTestBasic{
  637. chainBlocks: 8,
  638. snapshotBlock: 4,
  639. commitBlock: 0,
  640. expCanonicalBlocks: 10,
  641. expHeadHeader: 10,
  642. expHeadFastBlock: 10,
  643. expHeadBlock: 10,
  644. expSnapshotBottom: 10,
  645. },
  646. newBlocks: 2,
  647. }
  648. test.test(t)
  649. test.teardown()
  650. }