blockchain_snapshot_test.go 21 KB

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