blockchain_snapshot_test.go 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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/state/snapshot"
  31. "github.com/ethereum/go-ethereum/core/types"
  32. "github.com/ethereum/go-ethereum/core/vm"
  33. "github.com/ethereum/go-ethereum/ethdb"
  34. "github.com/ethereum/go-ethereum/params"
  35. )
  36. // snapshotTestBasic wraps the common testing fields in the snapshot tests.
  37. type snapshotTestBasic struct {
  38. legacy bool // Wether write the snapshot journal in legacy format
  39. chainBlocks int // Number of blocks to generate for the canonical chain
  40. snapshotBlock uint64 // Block number of the relevant snapshot disk layer
  41. commitBlock uint64 // Block number for which to commit the state to disk
  42. expCanonicalBlocks int // Number of canonical blocks expected to remain in the database (excl. genesis)
  43. expHeadHeader uint64 // Block number of the expected head header
  44. expHeadFastBlock uint64 // Block number of the expected head fast sync block
  45. expHeadBlock uint64 // Block number of the expected head full block
  46. expSnapshotBottom uint64 // The block height corresponding to the snapshot disk layer
  47. // share fields, set in runtime
  48. datadir string
  49. db ethdb.Database
  50. gendb ethdb.Database
  51. engine consensus.Engine
  52. }
  53. func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) {
  54. // Create a temporary persistent database
  55. datadir, err := ioutil.TempDir("", "")
  56. if err != nil {
  57. t.Fatalf("Failed to create temporary datadir: %v", err)
  58. }
  59. os.RemoveAll(datadir)
  60. db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "")
  61. if err != nil {
  62. t.Fatalf("Failed to create persistent database: %v", err)
  63. }
  64. // Initialize a fresh chain
  65. var (
  66. genesis = new(Genesis).MustCommit(db)
  67. engine = ethash.NewFullFaker()
  68. gendb = rawdb.NewMemoryDatabase()
  69. // Snapshot is enabled, the first snapshot is created from the Genesis.
  70. // The snapshot memory allowance is 256MB, it means no snapshot flush
  71. // will happen during the block insertion.
  72. cacheConfig = defaultCacheConfig
  73. )
  74. chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil)
  75. if err != nil {
  76. t.Fatalf("Failed to create chain: %v", err)
  77. }
  78. blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {})
  79. // Insert the blocks with configured settings.
  80. var breakpoints []uint64
  81. if basic.commitBlock > basic.snapshotBlock {
  82. breakpoints = append(breakpoints, basic.snapshotBlock, basic.commitBlock)
  83. } else {
  84. breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock)
  85. }
  86. var startPoint uint64
  87. for _, point := range breakpoints {
  88. if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil {
  89. t.Fatalf("Failed to import canonical chain start: %v", err)
  90. }
  91. startPoint = point
  92. if basic.commitBlock > 0 && basic.commitBlock == point {
  93. chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil)
  94. }
  95. if basic.snapshotBlock > 0 && basic.snapshotBlock == point {
  96. if basic.legacy {
  97. // Here we commit the snapshot disk root to simulate
  98. // committing the legacy snapshot.
  99. rawdb.WriteSnapshotRoot(db, blocks[point-1].Root())
  100. } else {
  101. // Flushing the entire snap tree into the disk, the
  102. // relavant (a) snapshot root and (b) snapshot generator
  103. // will be persisted atomically.
  104. chain.snaps.Cap(blocks[point-1].Root(), 0)
  105. diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root()
  106. if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) {
  107. t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot)
  108. }
  109. }
  110. }
  111. }
  112. if _, err := chain.InsertChain(blocks[startPoint:]); err != nil {
  113. t.Fatalf("Failed to import canonical chain tail: %v", err)
  114. }
  115. // Set runtime fields
  116. basic.datadir = datadir
  117. basic.db = db
  118. basic.gendb = gendb
  119. basic.engine = engine
  120. // Ugly hack, notify the chain to flush the journal in legacy format
  121. // if it's requested.
  122. if basic.legacy {
  123. chain.writeLegacyJournal = true
  124. }
  125. return chain, blocks
  126. }
  127. func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks []*types.Block) {
  128. // Iterate over all the remaining blocks and ensure there are no gaps
  129. verifyNoGaps(t, chain, true, blocks)
  130. verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks)
  131. if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader {
  132. t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader)
  133. }
  134. if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock {
  135. t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock)
  136. }
  137. if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock {
  138. t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock)
  139. }
  140. // Check the disk layer, ensure they are matched
  141. block := chain.GetBlockByNumber(basic.expSnapshotBottom)
  142. if block == nil {
  143. t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom)
  144. } else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) {
  145. t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot())
  146. }
  147. // Check the snapshot, ensure it's integrated
  148. if err := snapshot.VerifyState(chain.snaps, block.Root()); err != nil {
  149. t.Errorf("The disk layer is not integrated %v", err)
  150. }
  151. }
  152. func (basic *snapshotTestBasic) dump() string {
  153. buffer := new(strings.Builder)
  154. fmt.Fprint(buffer, "Chain:\n G")
  155. for i := 0; i < basic.chainBlocks; i++ {
  156. fmt.Fprintf(buffer, "->C%d", i+1)
  157. }
  158. fmt.Fprint(buffer, " (HEAD)\n\n")
  159. fmt.Fprintf(buffer, "Commit: G")
  160. if basic.commitBlock > 0 {
  161. fmt.Fprintf(buffer, ", C%d", basic.commitBlock)
  162. }
  163. fmt.Fprint(buffer, "\n")
  164. fmt.Fprintf(buffer, "Snapshot: G")
  165. if basic.snapshotBlock > 0 {
  166. fmt.Fprintf(buffer, ", C%d", basic.snapshotBlock)
  167. }
  168. fmt.Fprint(buffer, "\n")
  169. //if crash {
  170. // fmt.Fprintf(buffer, "\nCRASH\n\n")
  171. //} else {
  172. // fmt.Fprintf(buffer, "\nSetHead(%d)\n\n", basic.setHead)
  173. //}
  174. fmt.Fprintf(buffer, "------------------------------\n\n")
  175. fmt.Fprint(buffer, "Expected in leveldb:\n G")
  176. for i := 0; i < basic.expCanonicalBlocks; i++ {
  177. fmt.Fprintf(buffer, "->C%d", i+1)
  178. }
  179. fmt.Fprintf(buffer, "\n\n")
  180. fmt.Fprintf(buffer, "Expected head header : C%d\n", basic.expHeadHeader)
  181. fmt.Fprintf(buffer, "Expected head fast block: C%d\n", basic.expHeadFastBlock)
  182. if basic.expHeadBlock == 0 {
  183. fmt.Fprintf(buffer, "Expected head block : G\n")
  184. } else {
  185. fmt.Fprintf(buffer, "Expected head block : C%d\n", basic.expHeadBlock)
  186. }
  187. if basic.expSnapshotBottom == 0 {
  188. fmt.Fprintf(buffer, "Expected snapshot disk : G\n")
  189. } else {
  190. fmt.Fprintf(buffer, "Expected snapshot disk : C%d\n", basic.expSnapshotBottom)
  191. }
  192. return buffer.String()
  193. }
  194. func (basic *snapshotTestBasic) teardown() {
  195. basic.db.Close()
  196. basic.gendb.Close()
  197. os.RemoveAll(basic.datadir)
  198. }
  199. // snapshotTest is a test case type for normal snapshot recovery.
  200. // It can be used for testing that restart Geth normally.
  201. type snapshotTest struct {
  202. snapshotTestBasic
  203. }
  204. func (snaptest *snapshotTest) test(t *testing.T) {
  205. // It's hard to follow the test case, visualize the input
  206. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  207. // fmt.Println(tt.dump())
  208. chain, blocks := snaptest.prepare(t)
  209. // Restart the chain normally
  210. chain.Stop()
  211. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  212. if err != nil {
  213. t.Fatalf("Failed to recreate chain: %v", err)
  214. }
  215. defer newchain.Stop()
  216. snaptest.verify(t, newchain, blocks)
  217. }
  218. // crashSnapshotTest is a test case type for innormal snapshot recovery.
  219. // It can be used for testing that restart Geth after the crash.
  220. type crashSnapshotTest struct {
  221. snapshotTestBasic
  222. }
  223. func (snaptest *crashSnapshotTest) test(t *testing.T) {
  224. // It's hard to follow the test case, visualize the input
  225. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  226. // fmt.Println(tt.dump())
  227. chain, blocks := snaptest.prepare(t)
  228. // Pull the plug on the database, simulating a hard crash
  229. db := chain.db
  230. db.Close()
  231. // Start a new blockchain back up and see where the repair leads us
  232. newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "")
  233. if err != nil {
  234. t.Fatalf("Failed to reopen persistent database: %v", err)
  235. }
  236. defer newdb.Close()
  237. // The interesting thing is: instead of starting the blockchain after
  238. // the crash, we do restart twice here: one after the crash and one
  239. // after the normal stop. It's used to ensure the broken snapshot
  240. // can be detected all the time.
  241. newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  242. if err != nil {
  243. t.Fatalf("Failed to recreate chain: %v", err)
  244. }
  245. newchain.Stop()
  246. newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  247. if err != nil {
  248. t.Fatalf("Failed to recreate chain: %v", err)
  249. }
  250. defer newchain.Stop()
  251. snaptest.verify(t, newchain, blocks)
  252. }
  253. // gappedSnapshotTest is a test type used to test this scenario:
  254. // - have a complete snapshot
  255. // - restart without enabling the snapshot
  256. // - insert a few blocks
  257. // - restart with enabling the snapshot again
  258. type gappedSnapshotTest struct {
  259. snapshotTestBasic
  260. gapped int // Number of blocks to insert without enabling snapshot
  261. }
  262. func (snaptest *gappedSnapshotTest) test(t *testing.T) {
  263. // It's hard to follow the test case, visualize the input
  264. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  265. // fmt.Println(tt.dump())
  266. chain, blocks := snaptest.prepare(t)
  267. // Insert blocks without enabling snapshot if gapping is required.
  268. chain.Stop()
  269. gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {})
  270. // Insert a few more blocks without enabling snapshot
  271. var cacheConfig = &CacheConfig{
  272. TrieCleanLimit: 256,
  273. TrieDirtyLimit: 256,
  274. TrieTimeLimit: 5 * time.Minute,
  275. SnapshotLimit: 0,
  276. }
  277. newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  278. if err != nil {
  279. t.Fatalf("Failed to recreate chain: %v", err)
  280. }
  281. newchain.InsertChain(gappedBlocks)
  282. newchain.Stop()
  283. // Restart the chain with enabling the snapshot
  284. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  285. if err != nil {
  286. t.Fatalf("Failed to recreate chain: %v", err)
  287. }
  288. defer newchain.Stop()
  289. snaptest.verify(t, newchain, blocks)
  290. }
  291. // setHeadSnapshotTest is the test type used to test this scenario:
  292. // - have a complete snapshot
  293. // - set the head to a lower point
  294. // - restart
  295. type setHeadSnapshotTest struct {
  296. snapshotTestBasic
  297. setHead uint64 // Block number to set head back to
  298. }
  299. func (snaptest *setHeadSnapshotTest) test(t *testing.T) {
  300. // It's hard to follow the test case, visualize the input
  301. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  302. // fmt.Println(tt.dump())
  303. chain, blocks := snaptest.prepare(t)
  304. // Rewind the chain if setHead operation is required.
  305. chain.SetHead(snaptest.setHead)
  306. chain.Stop()
  307. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  308. if err != nil {
  309. t.Fatalf("Failed to recreate chain: %v", err)
  310. }
  311. defer newchain.Stop()
  312. snaptest.verify(t, newchain, blocks)
  313. }
  314. // restartCrashSnapshotTest is the test type used to test this scenario:
  315. // - have a complete snapshot
  316. // - restart chain
  317. // - insert more blocks with enabling the snapshot
  318. // - commit the snapshot
  319. // - crash
  320. // - restart again
  321. type restartCrashSnapshotTest struct {
  322. snapshotTestBasic
  323. newBlocks int
  324. }
  325. func (snaptest *restartCrashSnapshotTest) test(t *testing.T) {
  326. // It's hard to follow the test case, visualize the input
  327. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  328. // fmt.Println(tt.dump())
  329. chain, blocks := snaptest.prepare(t)
  330. // Firstly, stop the chain properly, with all snapshot journal
  331. // and state committed.
  332. chain.Stop()
  333. newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  334. if err != nil {
  335. t.Fatalf("Failed to recreate chain: %v", err)
  336. }
  337. newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
  338. newchain.InsertChain(newBlocks)
  339. // Commit the entire snapshot into the disk if requested. Note only
  340. // (a) snapshot root and (b) snapshot generator will be committed,
  341. // the diff journal is not.
  342. newchain.Snapshots().Cap(newBlocks[len(newBlocks)-1].Root(), 0)
  343. // Simulate the blockchain crash
  344. // Don't call chain.Stop here, so that no snapshot
  345. // journal and latest state will be committed
  346. // Restart the chain after the crash
  347. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  348. if err != nil {
  349. t.Fatalf("Failed to recreate chain: %v", err)
  350. }
  351. defer newchain.Stop()
  352. snaptest.verify(t, newchain, blocks)
  353. }
  354. // wipeCrashSnapshotTest is the test type used to test this scenario:
  355. // - have a complete snapshot
  356. // - restart, insert more blocks without enabling the snapshot
  357. // - restart again with enabling the snapshot
  358. // - crash
  359. type wipeCrashSnapshotTest struct {
  360. snapshotTestBasic
  361. newBlocks int
  362. }
  363. func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) {
  364. // It's hard to follow the test case, visualize the input
  365. // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
  366. // fmt.Println(tt.dump())
  367. chain, blocks := snaptest.prepare(t)
  368. // Firstly, stop the chain properly, with all snapshot journal
  369. // and state committed.
  370. chain.Stop()
  371. config := &CacheConfig{
  372. TrieCleanLimit: 256,
  373. TrieDirtyLimit: 256,
  374. TrieTimeLimit: 5 * time.Minute,
  375. SnapshotLimit: 0,
  376. }
  377. newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  378. if err != nil {
  379. t.Fatalf("Failed to recreate chain: %v", err)
  380. }
  381. newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {})
  382. newchain.InsertChain(newBlocks)
  383. newchain.Stop()
  384. // Restart the chain, the wiper should starts working
  385. config = &CacheConfig{
  386. TrieCleanLimit: 256,
  387. TrieDirtyLimit: 256,
  388. TrieTimeLimit: 5 * time.Minute,
  389. SnapshotLimit: 256,
  390. SnapshotWait: false, // Don't wait rebuild
  391. }
  392. newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  393. if err != nil {
  394. t.Fatalf("Failed to recreate chain: %v", err)
  395. }
  396. // Simulate the blockchain crash.
  397. newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil)
  398. if err != nil {
  399. t.Fatalf("Failed to recreate chain: %v", err)
  400. }
  401. snaptest.verify(t, newchain, blocks)
  402. }
  403. // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot
  404. // journal will be persisted correctly. In this case no snapshot recovery is
  405. // required.
  406. func TestRestartWithNewSnapshot(t *testing.T) {
  407. // Chain:
  408. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  409. //
  410. // Commit: G
  411. // Snapshot: G
  412. //
  413. // SetHead(0)
  414. //
  415. // ------------------------------
  416. //
  417. // Expected in leveldb:
  418. // G->C1->C2->C3->C4->C5->C6->C7->C8
  419. //
  420. // Expected head header : C8
  421. // Expected head fast block: C8
  422. // Expected head block : C8
  423. // Expected snapshot disk : G
  424. test := &snapshotTest{
  425. snapshotTestBasic{
  426. legacy: false,
  427. chainBlocks: 8,
  428. snapshotBlock: 0,
  429. commitBlock: 0,
  430. expCanonicalBlocks: 8,
  431. expHeadHeader: 8,
  432. expHeadFastBlock: 8,
  433. expHeadBlock: 8,
  434. expSnapshotBottom: 0, // Initial disk layer built from genesis
  435. },
  436. }
  437. test.test(t)
  438. test.teardown()
  439. }
  440. // Tests a Geth restart with valid but "legacy" snapshot. Before the shutdown,
  441. // all snapshot journal will be persisted correctly. In this case no snapshot
  442. // recovery is required.
  443. func TestRestartWithLegacySnapshot(t *testing.T) {
  444. // Chain:
  445. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  446. //
  447. // Commit: G
  448. // Snapshot: G
  449. //
  450. // SetHead(0)
  451. //
  452. // ------------------------------
  453. //
  454. // Expected in leveldb:
  455. // G->C1->C2->C3->C4->C5->C6->C7->C8
  456. //
  457. // Expected head header : C8
  458. // Expected head fast block: C8
  459. // Expected head block : C8
  460. // Expected snapshot disk : G
  461. t.Skip("Legacy format testing is not supported")
  462. test := &snapshotTest{
  463. snapshotTestBasic{
  464. legacy: true,
  465. chainBlocks: 8,
  466. snapshotBlock: 0,
  467. commitBlock: 0,
  468. expCanonicalBlocks: 8,
  469. expHeadHeader: 8,
  470. expHeadFastBlock: 8,
  471. expHeadBlock: 8,
  472. expSnapshotBottom: 0, // Initial disk layer built from genesis
  473. },
  474. }
  475. test.test(t)
  476. test.teardown()
  477. }
  478. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  479. // chain head should be rewound to the point with available state. And also the
  480. // new head should must be lower than disk layer. But there is no committed point
  481. // so the chain should be rewound to genesis and the disk layer should be left
  482. // for recovery.
  483. func TestNoCommitCrashWithNewSnapshot(t *testing.T) {
  484. // Chain:
  485. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  486. //
  487. // Commit: G
  488. // Snapshot: G, C4
  489. //
  490. // CRASH
  491. //
  492. // ------------------------------
  493. //
  494. // Expected in leveldb:
  495. // G->C1->C2->C3->C4->C5->C6->C7->C8
  496. //
  497. // Expected head header : C8
  498. // Expected head fast block: C8
  499. // Expected head block : G
  500. // Expected snapshot disk : C4
  501. test := &crashSnapshotTest{
  502. snapshotTestBasic{
  503. legacy: false,
  504. chainBlocks: 8,
  505. snapshotBlock: 4,
  506. commitBlock: 0,
  507. expCanonicalBlocks: 8,
  508. expHeadHeader: 8,
  509. expHeadFastBlock: 8,
  510. expHeadBlock: 0,
  511. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  512. },
  513. }
  514. test.test(t)
  515. test.teardown()
  516. }
  517. // Tests a Geth was crashed and restarts with a broken snapshot. In this case the
  518. // chain head should be rewound to the point with available state. And also the
  519. // new head should must be lower than disk layer. But there is only a low committed
  520. // point so the chain should be rewound to committed point and the disk layer
  521. // should be left for recovery.
  522. func TestLowCommitCrashWithNewSnapshot(t *testing.T) {
  523. // Chain:
  524. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  525. //
  526. // Commit: G, C2
  527. // Snapshot: G, C4
  528. //
  529. // CRASH
  530. //
  531. // ------------------------------
  532. //
  533. // Expected in leveldb:
  534. // G->C1->C2->C3->C4->C5->C6->C7->C8
  535. //
  536. // Expected head header : C8
  537. // Expected head fast block: C8
  538. // Expected head block : C2
  539. // Expected snapshot disk : C4
  540. test := &crashSnapshotTest{
  541. snapshotTestBasic{
  542. legacy: false,
  543. chainBlocks: 8,
  544. snapshotBlock: 4,
  545. commitBlock: 2,
  546. expCanonicalBlocks: 8,
  547. expHeadHeader: 8,
  548. expHeadFastBlock: 8,
  549. expHeadBlock: 2,
  550. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  551. },
  552. }
  553. test.test(t)
  554. test.teardown()
  555. }
  556. // Tests a Geth was crashed and restarts with a broken snapshot. In this case
  557. // the chain head should be rewound to the point with available state. And also
  558. // the new head should must be lower than disk layer. But there is only a high
  559. // committed point so the chain should be rewound to genesis and the disk layer
  560. // should be left for recovery.
  561. func TestHighCommitCrashWithNewSnapshot(t *testing.T) {
  562. // Chain:
  563. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  564. //
  565. // Commit: G, C6
  566. // Snapshot: G, C4
  567. //
  568. // CRASH
  569. //
  570. // ------------------------------
  571. //
  572. // Expected in leveldb:
  573. // G->C1->C2->C3->C4->C5->C6->C7->C8
  574. //
  575. // Expected head header : C8
  576. // Expected head fast block: C8
  577. // Expected head block : G
  578. // Expected snapshot disk : C4
  579. test := &crashSnapshotTest{
  580. snapshotTestBasic{
  581. legacy: false,
  582. chainBlocks: 8,
  583. snapshotBlock: 4,
  584. commitBlock: 6,
  585. expCanonicalBlocks: 8,
  586. expHeadHeader: 8,
  587. expHeadFastBlock: 8,
  588. expHeadBlock: 0,
  589. expSnapshotBottom: 4, // Last committed disk layer, wait recovery
  590. },
  591. }
  592. test.test(t)
  593. test.teardown()
  594. }
  595. // Tests a Geth was crashed and restarts with a broken and "legacy format"
  596. // snapshot. In this case the entire legacy snapshot should be discared
  597. // and rebuild from the new chain head. The new head here refers to the
  598. // genesis because there is no committed point.
  599. func TestNoCommitCrashWithLegacySnapshot(t *testing.T) {
  600. // Chain:
  601. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  602. //
  603. // Commit: G
  604. // Snapshot: G, C4
  605. //
  606. // CRASH
  607. //
  608. // ------------------------------
  609. //
  610. // Expected in leveldb:
  611. // G->C1->C2->C3->C4->C5->C6->C7->C8
  612. //
  613. // Expected head header : C8
  614. // Expected head fast block: C8
  615. // Expected head block : G
  616. // Expected snapshot disk : G
  617. t.Skip("Legacy format testing is not supported")
  618. test := &crashSnapshotTest{
  619. snapshotTestBasic{
  620. legacy: true,
  621. chainBlocks: 8,
  622. snapshotBlock: 4,
  623. commitBlock: 0,
  624. expCanonicalBlocks: 8,
  625. expHeadHeader: 8,
  626. expHeadFastBlock: 8,
  627. expHeadBlock: 0,
  628. expSnapshotBottom: 0, // Rebuilt snapshot from the latest HEAD(genesis)
  629. },
  630. }
  631. test.test(t)
  632. test.teardown()
  633. }
  634. // Tests a Geth was crashed and restarts with a broken and "legacy format"
  635. // snapshot. In this case the entire legacy snapshot should be discared
  636. // and rebuild from the new chain head. The new head here refers to the
  637. // block-2 because it's committed into the disk.
  638. func TestLowCommitCrashWithLegacySnapshot(t *testing.T) {
  639. // Chain:
  640. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  641. //
  642. // Commit: G, C2
  643. // Snapshot: G, C4
  644. //
  645. // CRASH
  646. //
  647. // ------------------------------
  648. //
  649. // Expected in leveldb:
  650. // G->C1->C2->C3->C4->C5->C6->C7->C8
  651. //
  652. // Expected head header : C8
  653. // Expected head fast block: C8
  654. // Expected head block : C2
  655. // Expected snapshot disk : C2
  656. t.Skip("Legacy format testing is not supported")
  657. test := &crashSnapshotTest{
  658. snapshotTestBasic{
  659. legacy: true,
  660. chainBlocks: 8,
  661. snapshotBlock: 4,
  662. commitBlock: 2,
  663. expCanonicalBlocks: 8,
  664. expHeadHeader: 8,
  665. expHeadFastBlock: 8,
  666. expHeadBlock: 2,
  667. expSnapshotBottom: 2, // Rebuilt snapshot from the latest HEAD
  668. },
  669. }
  670. test.test(t)
  671. test.teardown()
  672. }
  673. // Tests a Geth was crashed and restarts with a broken and "legacy format"
  674. // snapshot. In this case the entire legacy snapshot should be discared
  675. // and rebuild from the new chain head.
  676. //
  677. // The new head here refers to the the genesis, the reason is:
  678. // - the state of block-6 is committed into the disk
  679. // - the legacy disk layer of block-4 is committed into the disk
  680. // - the head is rewound the genesis in order to find an available
  681. // state lower than disk layer
  682. func TestHighCommitCrashWithLegacySnapshot(t *testing.T) {
  683. // Chain:
  684. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  685. //
  686. // Commit: G, C6
  687. // Snapshot: G, C4
  688. //
  689. // CRASH
  690. //
  691. // ------------------------------
  692. //
  693. // Expected in leveldb:
  694. // G->C1->C2->C3->C4->C5->C6->C7->C8
  695. //
  696. // Expected head header : C8
  697. // Expected head fast block: C8
  698. // Expected head block : G
  699. // Expected snapshot disk : G
  700. t.Skip("Legacy format testing is not supported")
  701. test := &crashSnapshotTest{
  702. snapshotTestBasic{
  703. legacy: true,
  704. chainBlocks: 8,
  705. snapshotBlock: 4,
  706. commitBlock: 6,
  707. expCanonicalBlocks: 8,
  708. expHeadHeader: 8,
  709. expHeadFastBlock: 8,
  710. expHeadBlock: 0,
  711. expSnapshotBottom: 0, // Rebuilt snapshot from the latest HEAD(genesis)
  712. },
  713. }
  714. test.test(t)
  715. test.teardown()
  716. }
  717. // Tests a Geth was running with snapshot enabled. Then restarts without
  718. // enabling snapshot and after that re-enable the snapshot again. In this
  719. // case the snapshot should be rebuilt with latest chain head.
  720. func TestGappedNewSnapshot(t *testing.T) {
  721. // Chain:
  722. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  723. //
  724. // Commit: G
  725. // Snapshot: G
  726. //
  727. // SetHead(0)
  728. //
  729. // ------------------------------
  730. //
  731. // Expected in leveldb:
  732. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  733. //
  734. // Expected head header : C10
  735. // Expected head fast block: C10
  736. // Expected head block : C10
  737. // Expected snapshot disk : C10
  738. test := &gappedSnapshotTest{
  739. snapshotTestBasic: snapshotTestBasic{
  740. legacy: false,
  741. chainBlocks: 8,
  742. snapshotBlock: 0,
  743. commitBlock: 0,
  744. expCanonicalBlocks: 10,
  745. expHeadHeader: 10,
  746. expHeadFastBlock: 10,
  747. expHeadBlock: 10,
  748. expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
  749. },
  750. gapped: 2,
  751. }
  752. test.test(t)
  753. test.teardown()
  754. }
  755. // Tests a Geth was running with leagcy snapshot enabled. Then restarts
  756. // without enabling snapshot and after that re-enable the snapshot again.
  757. // In this case the snapshot should be rebuilt with latest chain head.
  758. func TestGappedLegacySnapshot(t *testing.T) {
  759. // Chain:
  760. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  761. //
  762. // Commit: G
  763. // Snapshot: G
  764. //
  765. // SetHead(0)
  766. //
  767. // ------------------------------
  768. //
  769. // Expected in leveldb:
  770. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  771. //
  772. // Expected head header : C10
  773. // Expected head fast block: C10
  774. // Expected head block : C10
  775. // Expected snapshot disk : C10
  776. t.Skip("Legacy format testing is not supported")
  777. test := &gappedSnapshotTest{
  778. snapshotTestBasic: snapshotTestBasic{
  779. legacy: true,
  780. chainBlocks: 8,
  781. snapshotBlock: 0,
  782. commitBlock: 0,
  783. expCanonicalBlocks: 10,
  784. expHeadHeader: 10,
  785. expHeadFastBlock: 10,
  786. expHeadBlock: 10,
  787. expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD
  788. },
  789. gapped: 2,
  790. }
  791. test.test(t)
  792. test.teardown()
  793. }
  794. // Tests the Geth was running with snapshot enabled and resetHead is applied.
  795. // In this case the head is rewound to the target(with state available). After
  796. // that the chain is restarted and the original disk layer is kept.
  797. func TestSetHeadWithNewSnapshot(t *testing.T) {
  798. // Chain:
  799. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  800. //
  801. // Commit: G
  802. // Snapshot: G
  803. //
  804. // SetHead(4)
  805. //
  806. // ------------------------------
  807. //
  808. // Expected in leveldb:
  809. // G->C1->C2->C3->C4
  810. //
  811. // Expected head header : C4
  812. // Expected head fast block: C4
  813. // Expected head block : C4
  814. // Expected snapshot disk : G
  815. test := &setHeadSnapshotTest{
  816. snapshotTestBasic: snapshotTestBasic{
  817. legacy: false,
  818. chainBlocks: 8,
  819. snapshotBlock: 0,
  820. commitBlock: 0,
  821. expCanonicalBlocks: 4,
  822. expHeadHeader: 4,
  823. expHeadFastBlock: 4,
  824. expHeadBlock: 4,
  825. expSnapshotBottom: 0, // The initial disk layer is built from the genesis
  826. },
  827. setHead: 4,
  828. }
  829. test.test(t)
  830. test.teardown()
  831. }
  832. // Tests the Geth was running with snapshot(legacy-format) enabled and resetHead
  833. // is applied. In this case the head is rewound to the target(with state available).
  834. // After that the chain is restarted and the original disk layer is kept.
  835. func TestSetHeadWithLegacySnapshot(t *testing.T) {
  836. // Chain:
  837. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  838. //
  839. // Commit: G
  840. // Snapshot: G
  841. //
  842. // SetHead(4)
  843. //
  844. // ------------------------------
  845. //
  846. // Expected in leveldb:
  847. // G->C1->C2->C3->C4
  848. //
  849. // Expected head header : C4
  850. // Expected head fast block: C4
  851. // Expected head block : C4
  852. // Expected snapshot disk : G
  853. t.Skip("Legacy format testing is not supported")
  854. test := &setHeadSnapshotTest{
  855. snapshotTestBasic: snapshotTestBasic{
  856. legacy: true,
  857. chainBlocks: 8,
  858. snapshotBlock: 0,
  859. commitBlock: 0,
  860. expCanonicalBlocks: 4,
  861. expHeadHeader: 4,
  862. expHeadFastBlock: 4,
  863. expHeadBlock: 4,
  864. expSnapshotBottom: 0, // The initial disk layer is built from the genesis
  865. },
  866. setHead: 4,
  867. }
  868. test.test(t)
  869. test.teardown()
  870. }
  871. // Tests the Geth was running with snapshot(legacy-format) enabled and upgrades
  872. // the disk layer journal(journal generator) to latest format. After that the Geth
  873. // is restarted from a crash. In this case Geth will find the new-format disk layer
  874. // journal but with legacy-format diff journal(the new-format is never committed),
  875. // and the invalid diff journal is expected to be dropped.
  876. func TestRecoverSnapshotFromCrashWithLegacyDiffJournal(t *testing.T) {
  877. // Chain:
  878. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  879. //
  880. // Commit: G
  881. // Snapshot: G
  882. //
  883. // SetHead(0)
  884. //
  885. // ------------------------------
  886. //
  887. // Expected in leveldb:
  888. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  889. //
  890. // Expected head header : C10
  891. // Expected head fast block: C10
  892. // Expected head block : C8
  893. // Expected snapshot disk : C10
  894. t.Skip("Legacy format testing is not supported")
  895. test := &restartCrashSnapshotTest{
  896. snapshotTestBasic: snapshotTestBasic{
  897. legacy: true,
  898. chainBlocks: 8,
  899. snapshotBlock: 0,
  900. commitBlock: 0,
  901. expCanonicalBlocks: 10,
  902. expHeadHeader: 10,
  903. expHeadFastBlock: 10,
  904. expHeadBlock: 8, // The persisted state in the first running
  905. expSnapshotBottom: 10, // The persisted disk layer in the second running
  906. },
  907. newBlocks: 2,
  908. }
  909. test.test(t)
  910. test.teardown()
  911. }
  912. // Tests the Geth was running with a complete snapshot and then imports a few
  913. // more new blocks on top without enabling the snapshot. After the restart,
  914. // crash happens. Check everything is ok after the restart.
  915. func TestRecoverSnapshotFromWipingCrash(t *testing.T) {
  916. // Chain:
  917. // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD)
  918. //
  919. // Commit: G
  920. // Snapshot: G
  921. //
  922. // SetHead(0)
  923. //
  924. // ------------------------------
  925. //
  926. // Expected in leveldb:
  927. // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10
  928. //
  929. // Expected head header : C10
  930. // Expected head fast block: C10
  931. // Expected head block : C8
  932. // Expected snapshot disk : C10
  933. test := &wipeCrashSnapshotTest{
  934. snapshotTestBasic: snapshotTestBasic{
  935. legacy: false,
  936. chainBlocks: 8,
  937. snapshotBlock: 4,
  938. commitBlock: 0,
  939. expCanonicalBlocks: 10,
  940. expHeadHeader: 10,
  941. expHeadFastBlock: 10,
  942. expHeadBlock: 10,
  943. expSnapshotBottom: 10,
  944. },
  945. newBlocks: 2,
  946. }
  947. test.test(t)
  948. test.teardown()
  949. }