blockchain_snapshot_test.go 31 KB

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