blockchain_snapshot_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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)
  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)
  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)
  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)
  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. TriesInMemory: 128,
  263. SnapshotLimit: 0,
  264. }
  265. newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  266. if err != nil {
  267. t.Fatalf("Failed to recreate chain: %v", err)
  268. }
  269. newchain.InsertChain(gappedBlocks)
  270. newchain.Stop()
  271. // Restart the chain with enabling the snapshot
  272. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  273. if err != nil {
  274. t.Fatalf("Failed to recreate chain: %v", err)
  275. }
  276. defer newchain.Stop()
  277. snaptest.verify(t, newchain, blocks)
  278. }
  279. // setHeadSnapshotTest is the test type used to test this scenario:
  280. // - have a complete snapshot
  281. // - set the head to a lower point
  282. // - restart
  283. type setHeadSnapshotTest struct {
  284. snapshotTestBasic
  285. setHead uint64 // Block number to set head back to
  286. }
  287. func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
  288. // It's hard to follow the test case, visualize the input
  289. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  290. // fmt.Println(tt.dump())
  291. chain, blocks := snaptest.prepare(t)
  292. // Rewind the chain if setHead operation is required.
  293. chain.SetHead(snaptest.setHead)
  294. chain.Stop()
  295. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  296. if err != nil {
  297. t.Fatalf("Failed to recreate chain: %v", err)
  298. }
  299. defer newchain.Stop()
  300. snaptest.verify(t, newchain, blocks)
  301. }
  302. // restartCrashSnapshotTest is the test type used to test this scenario:
  303. // - have a complete snapshot
  304. // - restart chain
  305. // - insert more blocks with enabling the snapshot
  306. // - commit the snapshot
  307. // - crash
  308. // - restart again
  309. type restartCrashSnapshotTest struct {
  310. snapshotTestBasic
  311. newBlocks int
  312. }
  313. func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
  314. // It's hard to follow the test case, visualize the input
  315. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  316. // fmt.Println(tt.dump())
  317. chain, blocks := snaptest.prepare(t)
  318. // Firstly, stop the chain properly, with all snapshot journal
  319. // and state committed.
  320. chain.Stop()
  321. newchain, err := NewBlockChain(snaptest.db, nil, 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. // Commit the entire snapshot into the disk if requested. Note only
  328. // (a) snapshot root and (b) snapshot generator will be committed,
  329. // the diff journal is not.
  330. newchain.Snapshots().Cap(newBlocks[len(newBlocks)-1].Root(), 0)
  331. // Simulate the blockchain crash
  332. // Don't call chain.Stop here, so that no snapshot
  333. // journal and latest state will be committed
  334. // Restart the chain after the crash
  335. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  336. if err != nil {
  337. t.Fatalf("Failed to recreate chain: %v", err)
  338. }
  339. defer newchain.Stop()
  340. snaptest.verify(t, newchain, blocks)
  341. }
  342. // wipeCrashSnapshotTest is the test type used to test this scenario:
  343. // - have a complete snapshot
  344. // - restart, insert more blocks without enabling the snapshot
  345. // - restart again with enabling the snapshot
  346. // - crash
  347. type wipeCrashSnapshotTest struct {
  348. snapshotTestBasic
  349. newBlocks int
  350. }
  351. func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
  352. // It's hard to follow the test case, visualize the input
  353. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  354. // fmt.Println(tt.dump())
  355. chain, blocks := snaptest.prepare(t)
  356. // Firstly, stop the chain properly, with all snapshot journal
  357. // and state committed.
  358. chain.Stop()
  359. config := &CacheConfig{
  360. TrieCleanLimit: 256,
  361. TrieDirtyLimit: 256,
  362. TrieTimeLimit: 5 * time.Minute,
  363. SnapshotLimit: 0,
  364. TriesInMemory: 128,
  365. }
  366. newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  367. if err != nil {
  368. t.Fatalf("Failed to recreate chain: %v", err)
  369. }
  370. newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
  371. newchain.InsertChain(newBlocks)
  372. newchain.Stop()
  373. // Restart the chain, the wiper should starts working
  374. config = &CacheConfig{
  375. TrieCleanLimit: 256,
  376. TrieDirtyLimit: 256,
  377. TrieTimeLimit: 5 * time.Minute,
  378. SnapshotLimit: 256,
  379. SnapshotWait: false, // Don't wait rebuild
  380. TriesInMemory: 128,
  381. }
  382. newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  383. if err != nil {
  384. t.Fatalf("Failed to recreate chain: %v", err)
  385. }
  386. // Simulate the blockchain crash.
  387. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  388. if err != nil {
  389. t.Fatalf("Failed to recreate chain: %v", err)
  390. }
  391. snaptest.verify(t, newchain, blocks)
  392. }
  393. // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot
  394. // journal will be persisted correctly. In this case no snapshot recovery is
  395. // required.
  396. func TestRestartWithNewSnapshot(t *testing.T) {
  397. // Chain:
  398. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  399. //
  400. // Commit: G
  401. // Snapshot: G
  402. //
  403. // SetHead(0)
  404. //
  405. // ------------------------------
  406. //
  407. // Expected in leveldb:
  408. // G->C1->C2->C3->C4->C5->C6->C7->C8
  409. //
  410. // Expected head header : C8
  411. // Expected head fast block: C8
  412. // Expected head block : C8
  413. // Expected snapshot disk : G
  414. test := &snapshotTest{
  415. snapshotTestBasic{
  416. chainBlocks: 8,
  417. snapshotBlock: 0,
  418. commitBlock: 0,
  419. expCanonicalBlocks: 8,
  420. expHeadHeader: 8,
  421. expHeadFastBlock: 8,
  422. expHeadBlock: 8,
  423. expSnapshotBottom: 0, // Initial disk layer built from genesis
  424. },
  425. }
  426. test.test(t)
  427. test.teardown()
  428. }
  429. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  430. // chain head should be rewound to the point with available state. And also the
  431. // new head should must be lower than disk layer. But there is no committed point
  432. // so the chain should be rewound to genesis and the disk layer should be left
  433. // for recovery.
  434. func TestNoCommitCrashWithNewSnapshot(t *testing.T) {
  435. // Chain:
  436. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  437. //
  438. // Commit: G
  439. // Snapshot: G, C4
  440. //
  441. // CRASH
  442. //
  443. // ------------------------------
  444. //
  445. // Expected in leveldb:
  446. // G->C1->C2->C3->C4->C5->C6->C7->C8
  447. //
  448. // Expected head header : C8
  449. // Expected head fast block: C8
  450. // Expected head block : G
  451. // Expected snapshot disk : C4
  452. test := &crashSnapshotTest{
  453. snapshotTestBasic{
  454. chainBlocks: 8,
  455. snapshotBlock: 4,
  456. commitBlock: 0,
  457. expCanonicalBlocks: 8,
  458. expHeadHeader: 8,
  459. expHeadFastBlock: 8,
  460. expHeadBlock: 0,
  461. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  462. },
  463. }
  464. test.test(t)
  465. test.teardown()
  466. }
  467. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  468. // chain head should be rewound to the point with available state. And also the
  469. // new head should must be lower than disk layer. But there is only a low committed
  470. // point so the chain should be rewound to committed point and the disk layer
  471. // should be left for recovery.
  472. func TestLowCommitCrashWithNewSnapshot(t *testing.T) {
  473. // Chain:
  474. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  475. //
  476. // Commit: G, C2
  477. // Snapshot: G, C4
  478. //
  479. // CRASH
  480. //
  481. // ------------------------------
  482. //
  483. // Expected in leveldb:
  484. // G->C1->C2->C3->C4->C5->C6->C7->C8
  485. //
  486. // Expected head header : C8
  487. // Expected head fast block: C8
  488. // Expected head block : C2
  489. // Expected snapshot disk : C4
  490. test := &crashSnapshotTest{
  491. snapshotTestBasic{
  492. chainBlocks: 8,
  493. snapshotBlock: 4,
  494. commitBlock: 2,
  495. expCanonicalBlocks: 8,
  496. expHeadHeader: 8,
  497. expHeadFastBlock: 8,
  498. expHeadBlock: 2,
  499. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  500. },
  501. }
  502. test.test(t)
  503. test.teardown()
  504. }
  505. // Tests a Geth was crashed and restarts with a broken snapshot. In this case
  506. // the chain head should be rewound to the point with available state. And also
  507. // the new head should must be lower than disk layer. But there is only a high
  508. // committed point so the chain should be rewound to genesis and the disk layer
  509. // should be left for recovery.
  510. func TestHighCommitCrashWithNewSnapshot(t *testing.T) {
  511. // Chain:
  512. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  513. //
  514. // Commit: G, C6
  515. // Snapshot: G, C4
  516. //
  517. // CRASH
  518. //
  519. // ------------------------------
  520. //
  521. // Expected in leveldb:
  522. // G->C1->C2->C3->C4->C5->C6->C7->C8
  523. //
  524. // Expected head header : C8
  525. // Expected head fast block: C8
  526. // Expected head block : G
  527. // Expected snapshot disk : C4
  528. test := &crashSnapshotTest{
  529. snapshotTestBasic{
  530. chainBlocks: 8,
  531. snapshotBlock: 4,
  532. commitBlock: 6,
  533. expCanonicalBlocks: 8,
  534. expHeadHeader: 8,
  535. expHeadFastBlock: 8,
  536. expHeadBlock: 0,
  537. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  538. },
  539. }
  540. test.test(t)
  541. test.teardown()
  542. }
  543. // Tests a Geth was running with snapshot enabled. Then restarts without
  544. // enabling snapshot and after that re-enable the snapshot again. In this
  545. // case the snapshot should be rebuilt with latest chain head.
  546. func TestGappedNewSnapshot(t *testing.T) {
  547. // Chain:
  548. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  549. //
  550. // Commit: G
  551. // Snapshot: G
  552. //
  553. // SetHead(0)
  554. //
  555. // ------------------------------
  556. //
  557. // Expected in leveldb:
  558. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  559. //
  560. // Expected head header : C10
  561. // Expected head fast block: C10
  562. // Expected head block : C10
  563. // Expected snapshot disk : C10
  564. test := &gappedSnapshotTest{
  565. snapshotTestBasic: snapshotTestBasic{
  566. chainBlocks: 8,
  567. snapshotBlock: 0,
  568. commitBlock: 0,
  569. expCanonicalBlocks: 10,
  570. expHeadHeader: 10,
  571. expHeadFastBlock: 10,
  572. expHeadBlock: 10,
  573. expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
  574. },
  575. gapped: 2,
  576. }
  577. test.test(t)
  578. test.teardown()
  579. }
  580. // Tests the Geth was running with snapshot enabled and resetHead is applied.
  581. // In this case the head is rewound to the target(with state available). After
  582. // that the chain is restarted and the original disk layer is kept.
  583. func TestSetHeadWithNewSnapshot(t *testing.T) {
  584. // Chain:
  585. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  586. //
  587. // Commit: G
  588. // Snapshot: G
  589. //
  590. // SetHead(4)
  591. //
  592. // ------------------------------
  593. //
  594. // Expected in leveldb:
  595. // G->C1->C2->C3->C4
  596. //
  597. // Expected head header : C4
  598. // Expected head fast block: C4
  599. // Expected head block : C4
  600. // Expected snapshot disk : G
  601. test := &setHeadSnapshotTest{
  602. snapshotTestBasic: snapshotTestBasic{
  603. chainBlocks: 8,
  604. snapshotBlock: 0,
  605. commitBlock: 0,
  606. expCanonicalBlocks: 4,
  607. expHeadHeader: 4,
  608. expHeadFastBlock: 4,
  609. expHeadBlock: 4,
  610. expSnapshotBottom: 0, // The initial disk layer is built from the genesis
  611. },
  612. setHead: 4,
  613. }
  614. test.test(t)
  615. test.teardown()
  616. }
  617. // Tests the Geth was running with a complete snapshot and then imports a few
  618. // more new blocks on top without enabling the snapshot. After the restart,
  619. // crash happens. Check everything is ok after the restart.
  620. func TestRecoverSnapshotFromWipingCrash(t *testing.T) {
  621. // Chain:
  622. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  623. //
  624. // Commit: G
  625. // Snapshot: G
  626. //
  627. // SetHead(0)
  628. //
  629. // ------------------------------
  630. //
  631. // Expected in leveldb:
  632. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  633. //
  634. // Expected head header : C10
  635. // Expected head fast block: C10
  636. // Expected head block : C8
  637. // Expected snapshot disk : C10
  638. test := &wipeCrashSnapshotTest{
  639. snapshotTestBasic: snapshotTestBasic{
  640. chainBlocks: 8,
  641. snapshotBlock: 4,
  642. commitBlock: 0,
  643. expCanonicalBlocks: 10,
  644. expHeadHeader: 10,
  645. expHeadFastBlock: 10,
  646. expHeadBlock: 10,
  647. expSnapshotBottom: 10,
  648. },
  649. newBlocks: 2,
  650. }
  651. test.test(t)
  652. test.teardown()
  653. }