blockchain_snapshot_test.go 23 KB

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