blockchain_snapshot_test.go 25 KB

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