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