github.com/Unheilbar/quorum@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 "os" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/ethereum/go-ethereum/consensus" 32 "github.com/ethereum/go-ethereum/consensus/ethash" 33 "github.com/ethereum/go-ethereum/core/rawdb" 34 "github.com/ethereum/go-ethereum/core/types" 35 "github.com/ethereum/go-ethereum/core/vm" 36 "github.com/ethereum/go-ethereum/ethdb" 37 "github.com/ethereum/go-ethereum/params" 38 ) 39 40 // snapshotTestBasic wraps the common testing fields in the snapshot tests. 41 type snapshotTestBasic struct { 42 chainBlocks int // Number of blocks to generate for the canonical chain 43 snapshotBlock uint64 // Block number of the relevant snapshot disk layer 44 commitBlock uint64 // Block number for which to commit the state to disk 45 46 expCanonicalBlocks int // Number of canonical blocks expected to remain in the database (excl. genesis) 47 expHeadHeader uint64 // Block number of the expected head header 48 expHeadFastBlock uint64 // Block number of the expected head fast sync block 49 expHeadBlock uint64 // Block number of the expected head full block 50 expSnapshotBottom uint64 // The block height corresponding to the snapshot disk layer 51 52 // share fields, set in runtime 53 datadir string 54 db ethdb.Database 55 gendb ethdb.Database 56 engine consensus.Engine 57 } 58 59 func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) { 60 // Create a temporary persistent database 61 datadir, err := ioutil.TempDir("", "") 62 if err != nil { 63 t.Fatalf("Failed to create temporary datadir: %v", err) 64 } 65 os.RemoveAll(datadir) 66 67 db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) 68 if err != nil { 69 t.Fatalf("Failed to create persistent database: %v", err) 70 } 71 // Initialize a fresh chain 72 var ( 73 genesis = new(Genesis).MustCommit(db) 74 engine = ethash.NewFullFaker() 75 gendb = rawdb.NewMemoryDatabase() 76 77 // Snapshot is enabled, the first snapshot is created from the Genesis. 78 // The snapshot memory allowance is 256MB, it means no snapshot flush 79 // will happen during the block insertion. 80 cacheConfig = defaultCacheConfig 81 ) 82 chain, err := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) 83 if err != nil { 84 t.Fatalf("Failed to create chain: %v", err) 85 } 86 blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, gendb, basic.chainBlocks, func(i int, b *BlockGen) {}) 87 88 // Insert the blocks with configured settings. 89 var breakpoints []uint64 90 if basic.commitBlock > basic.snapshotBlock { 91 breakpoints = append(breakpoints, basic.snapshotBlock, basic.commitBlock) 92 } else { 93 breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock) 94 } 95 var startPoint uint64 96 for _, point := range breakpoints { 97 if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil { 98 t.Fatalf("Failed to import canonical chain start: %v", err) 99 } 100 startPoint = point 101 102 if basic.commitBlock > 0 && basic.commitBlock == point { 103 chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil) 104 } 105 if basic.snapshotBlock > 0 && basic.snapshotBlock == point { 106 // Flushing the entire snap tree into the disk, the 107 // relavant (a) snapshot root and (b) snapshot generator 108 // will be persisted atomically. 109 chain.snaps.Cap(blocks[point-1].Root(), 0) 110 diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root() 111 if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) { 112 t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot) 113 } 114 } 115 } 116 if _, err := chain.InsertChain(blocks[startPoint:]); err != nil { 117 t.Fatalf("Failed to import canonical chain tail: %v", err) 118 } 119 120 // Set runtime fields 121 basic.datadir = datadir 122 basic.db = db 123 basic.gendb = gendb 124 basic.engine = engine 125 return chain, blocks 126 } 127 128 func (basic *snapshotTestBasic) verify(t *testing.T, chain *BlockChain, blocks []*types.Block) { 129 // Iterate over all the remaining blocks and ensure there are no gaps 130 verifyNoGaps(t, chain, true, blocks) 131 verifyCutoff(t, chain, true, blocks, basic.expCanonicalBlocks) 132 133 if head := chain.CurrentHeader(); head.Number.Uint64() != basic.expHeadHeader { 134 t.Errorf("Head header mismatch: have %d, want %d", head.Number, basic.expHeadHeader) 135 } 136 if head := chain.CurrentFastBlock(); head.NumberU64() != basic.expHeadFastBlock { 137 t.Errorf("Head fast block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadFastBlock) 138 } 139 if head := chain.CurrentBlock(); head.NumberU64() != basic.expHeadBlock { 140 t.Errorf("Head block mismatch: have %d, want %d", head.NumberU64(), basic.expHeadBlock) 141 } 142 143 // Check the disk layer, ensure they are matched 144 block := chain.GetBlockByNumber(basic.expSnapshotBottom) 145 if block == nil { 146 t.Errorf("The correspnding block[%d] of snapshot disk layer is missing", basic.expSnapshotBottom) 147 } else if !bytes.Equal(chain.snaps.DiskRoot().Bytes(), block.Root().Bytes()) { 148 t.Errorf("The snapshot disk layer root is incorrect, want %x, get %x", block.Root(), chain.snaps.DiskRoot()) 149 } 150 151 // Check the snapshot, ensure it's integrated 152 if err := chain.snaps.Verify(block.Root()); err != nil { 153 t.Errorf("The disk layer is not integrated %v", err) 154 } 155 } 156 157 //nolint:unused 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, 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, 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, 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, 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, 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, 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 // wipeCrashSnapshotTest is the test type used to test this scenario: 350 // - have a complete snapshot 351 // - restart, insert more blocks without enabling the snapshot 352 // - restart again with enabling the snapshot 353 // - crash 354 type wipeCrashSnapshotTest struct { 355 snapshotTestBasic 356 newBlocks int 357 } 358 359 func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { 360 // It's hard to follow the test case, visualize the input 361 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 362 // fmt.Println(tt.dump()) 363 chain, blocks := snaptest.prepare(t) 364 365 // Firstly, stop the chain properly, with all snapshot journal 366 // and state committed. 367 chain.Stop() 368 369 config := &CacheConfig{ 370 TrieCleanLimit: 256, 371 TrieDirtyLimit: 256, 372 TrieTimeLimit: 5 * time.Minute, 373 SnapshotLimit: 0, 374 } 375 newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) 376 if err != nil { 377 t.Fatalf("Failed to recreate chain: %v", err) 378 } 379 newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) 380 newchain.InsertChain(newBlocks) 381 newchain.Stop() 382 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 _, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) 392 if err != nil { 393 t.Fatalf("Failed to recreate chain: %v", err) 394 } 395 // Simulate the blockchain crash. 396 397 newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil, nil) 398 if err != nil { 399 t.Fatalf("Failed to recreate chain: %v", err) 400 } 401 snaptest.verify(t, newchain, blocks) 402 } 403 404 // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot 405 // journal will be persisted correctly. In this case no snapshot recovery is 406 // required. 407 func TestRestartWithNewSnapshot(t *testing.T) { 408 // Chain: 409 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 410 // 411 // Commit: G 412 // Snapshot: G 413 // 414 // SetHead(0) 415 // 416 // ------------------------------ 417 // 418 // Expected in leveldb: 419 // G->C1->C2->C3->C4->C5->C6->C7->C8 420 // 421 // Expected head header : C8 422 // Expected head fast block: C8 423 // Expected head block : C8 424 // Expected snapshot disk : G 425 test := &snapshotTest{ 426 snapshotTestBasic{ 427 chainBlocks: 8, 428 snapshotBlock: 0, 429 commitBlock: 0, 430 expCanonicalBlocks: 8, 431 expHeadHeader: 8, 432 expHeadFastBlock: 8, 433 expHeadBlock: 8, 434 expSnapshotBottom: 0, // Initial disk layer built from genesis 435 }, 436 } 437 test.test(t) 438 test.teardown() 439 } 440 441 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 442 // chain head should be rewound to the point with available state. And also the 443 // new head should must be lower than disk layer. But there is no committed point 444 // so the chain should be rewound to genesis and the disk layer should be left 445 // for recovery. 446 func TestNoCommitCrashWithNewSnapshot(t *testing.T) { 447 // Chain: 448 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 449 // 450 // Commit: G 451 // Snapshot: G, C4 452 // 453 // CRASH 454 // 455 // ------------------------------ 456 // 457 // Expected in leveldb: 458 // G->C1->C2->C3->C4->C5->C6->C7->C8 459 // 460 // Expected head header : C8 461 // Expected head fast block: C8 462 // Expected head block : G 463 // Expected snapshot disk : C4 464 test := &crashSnapshotTest{ 465 snapshotTestBasic{ 466 chainBlocks: 8, 467 snapshotBlock: 4, 468 commitBlock: 0, 469 expCanonicalBlocks: 8, 470 expHeadHeader: 8, 471 expHeadFastBlock: 8, 472 expHeadBlock: 0, 473 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 474 }, 475 } 476 test.test(t) 477 test.teardown() 478 } 479 480 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 481 // chain head should be rewound to the point with available state. And also the 482 // new head should must be lower than disk layer. But there is only a low committed 483 // point so the chain should be rewound to committed point and the disk layer 484 // should be left for recovery. 485 func TestLowCommitCrashWithNewSnapshot(t *testing.T) { 486 // Chain: 487 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 488 // 489 // Commit: G, C2 490 // Snapshot: G, C4 491 // 492 // CRASH 493 // 494 // ------------------------------ 495 // 496 // Expected in leveldb: 497 // G->C1->C2->C3->C4->C5->C6->C7->C8 498 // 499 // Expected head header : C8 500 // Expected head fast block: C8 501 // Expected head block : C2 502 // Expected snapshot disk : C4 503 test := &crashSnapshotTest{ 504 snapshotTestBasic{ 505 chainBlocks: 8, 506 snapshotBlock: 4, 507 commitBlock: 2, 508 expCanonicalBlocks: 8, 509 expHeadHeader: 8, 510 expHeadFastBlock: 8, 511 expHeadBlock: 2, 512 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 513 }, 514 } 515 test.test(t) 516 test.teardown() 517 } 518 519 // Tests a Geth was crashed and restarts with a broken snapshot. In this case 520 // the chain head should be rewound to the point with available state. And also 521 // the new head should must be lower than disk layer. But there is only a high 522 // committed point so the chain should be rewound to genesis and the disk layer 523 // should be left for recovery. 524 func TestHighCommitCrashWithNewSnapshot(t *testing.T) { 525 // Chain: 526 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 527 // 528 // Commit: G, C6 529 // Snapshot: G, C4 530 // 531 // CRASH 532 // 533 // ------------------------------ 534 // 535 // Expected in leveldb: 536 // G->C1->C2->C3->C4->C5->C6->C7->C8 537 // 538 // Expected head header : C8 539 // Expected head fast block: C8 540 // Expected head block : G 541 // Expected snapshot disk : C4 542 test := &crashSnapshotTest{ 543 snapshotTestBasic{ 544 chainBlocks: 8, 545 snapshotBlock: 4, 546 commitBlock: 6, 547 expCanonicalBlocks: 8, 548 expHeadHeader: 8, 549 expHeadFastBlock: 8, 550 expHeadBlock: 0, 551 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 552 }, 553 } 554 test.test(t) 555 test.teardown() 556 } 557 558 // Tests a Geth was running with snapshot enabled. Then restarts without 559 // enabling snapshot and after that re-enable the snapshot again. In this 560 // case the snapshot should be rebuilt with latest chain head. 561 func TestGappedNewSnapshot(t *testing.T) { 562 // Chain: 563 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 564 // 565 // Commit: G 566 // Snapshot: G 567 // 568 // SetHead(0) 569 // 570 // ------------------------------ 571 // 572 // Expected in leveldb: 573 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 574 // 575 // Expected head header : C10 576 // Expected head fast block: C10 577 // Expected head block : C10 578 // Expected snapshot disk : C10 579 test := &gappedSnapshotTest{ 580 snapshotTestBasic: snapshotTestBasic{ 581 chainBlocks: 8, 582 snapshotBlock: 0, 583 commitBlock: 0, 584 expCanonicalBlocks: 10, 585 expHeadHeader: 10, 586 expHeadFastBlock: 10, 587 expHeadBlock: 10, 588 expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD 589 }, 590 gapped: 2, 591 } 592 test.test(t) 593 test.teardown() 594 } 595 596 // Tests the Geth was running with snapshot enabled and resetHead is applied. 597 // In this case the head is rewound to the target(with state available). After 598 // that the chain is restarted and the original disk layer is kept. 599 func TestSetHeadWithNewSnapshot(t *testing.T) { 600 // Chain: 601 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 602 // 603 // Commit: G 604 // Snapshot: G 605 // 606 // SetHead(4) 607 // 608 // ------------------------------ 609 // 610 // Expected in leveldb: 611 // G->C1->C2->C3->C4 612 // 613 // Expected head header : C4 614 // Expected head fast block: C4 615 // Expected head block : C4 616 // Expected snapshot disk : G 617 test := &setHeadSnapshotTest{ 618 snapshotTestBasic: snapshotTestBasic{ 619 chainBlocks: 8, 620 snapshotBlock: 0, 621 commitBlock: 0, 622 expCanonicalBlocks: 4, 623 expHeadHeader: 4, 624 expHeadFastBlock: 4, 625 expHeadBlock: 4, 626 expSnapshotBottom: 0, // The initial disk layer is built from the genesis 627 }, 628 setHead: 4, 629 } 630 test.test(t) 631 test.teardown() 632 } 633 634 // Tests the Geth was running with a complete snapshot and then imports a few 635 // more new blocks on top without enabling the snapshot. After the restart, 636 // crash happens. Check everything is ok after the restart. 637 func TestRecoverSnapshotFromWipingCrash(t *testing.T) { 638 // Chain: 639 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 640 // 641 // Commit: G 642 // Snapshot: G 643 // 644 // SetHead(0) 645 // 646 // ------------------------------ 647 // 648 // Expected in leveldb: 649 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 650 // 651 // Expected head header : C10 652 // Expected head fast block: C10 653 // Expected head block : C8 654 // Expected snapshot disk : C10 655 test := &wipeCrashSnapshotTest{ 656 snapshotTestBasic: snapshotTestBasic{ 657 chainBlocks: 8, 658 snapshotBlock: 4, 659 commitBlock: 0, 660 expCanonicalBlocks: 10, 661 expHeadHeader: 10, 662 expHeadFastBlock: 10, 663 expHeadBlock: 10, 664 expSnapshotBottom: 10, 665 }, 666 newBlocks: 2, 667 } 668 test.test(t) 669 test.teardown() 670 }