github.com/jimmyx0x/go-ethereum@v1.10.28/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 "math/big" 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 gspec *Genesis 58 } 59 60 func (basic *snapshotTestBasic) prepare(t *testing.T) (*BlockChain, []*types.Block) { 61 // Create a temporary persistent database 62 datadir := t.TempDir() 63 64 db, err := rawdb.NewLevelDBDatabaseWithFreezer(datadir, 0, 0, datadir, "", false) 65 if err != nil { 66 t.Fatalf("Failed to create persistent database: %v", err) 67 } 68 // Initialize a fresh chain 69 var ( 70 gspec = &Genesis{ 71 BaseFee: big.NewInt(params.InitialBaseFee), 72 Config: params.AllEthashProtocolChanges, 73 } 74 engine = ethash.NewFullFaker() 75 76 // Snapshot is enabled, the first snapshot is created from the Genesis. 77 // The snapshot memory allowance is 256MB, it means no snapshot flush 78 // will happen during the block insertion. 79 cacheConfig = defaultCacheConfig 80 ) 81 chain, err := NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, nil) 82 if err != nil { 83 t.Fatalf("Failed to create chain: %v", err) 84 } 85 genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, basic.chainBlocks, func(i int, b *BlockGen) {}) 86 87 // Insert the blocks with configured settings. 88 var breakpoints []uint64 89 if basic.commitBlock > basic.snapshotBlock { 90 breakpoints = append(breakpoints, basic.snapshotBlock, basic.commitBlock) 91 } else { 92 breakpoints = append(breakpoints, basic.commitBlock, basic.snapshotBlock) 93 } 94 var startPoint uint64 95 for _, point := range breakpoints { 96 if _, err := chain.InsertChain(blocks[startPoint:point]); err != nil { 97 t.Fatalf("Failed to import canonical chain start: %v", err) 98 } 99 startPoint = point 100 101 if basic.commitBlock > 0 && basic.commitBlock == point { 102 chain.stateCache.TrieDB().Commit(blocks[point-1].Root(), true, nil) 103 } 104 if basic.snapshotBlock > 0 && basic.snapshotBlock == point { 105 // Flushing the entire snap tree into the disk, the 106 // relevant (a) snapshot root and (b) snapshot generator 107 // will be persisted atomically. 108 chain.snaps.Cap(blocks[point-1].Root(), 0) 109 diskRoot, blockRoot := chain.snaps.DiskRoot(), blocks[point-1].Root() 110 if !bytes.Equal(diskRoot.Bytes(), blockRoot.Bytes()) { 111 t.Fatalf("Failed to flush disk layer change, want %x, got %x", blockRoot, diskRoot) 112 } 113 } 114 } 115 if _, err := chain.InsertChain(blocks[startPoint:]); err != nil { 116 t.Fatalf("Failed to import canonical chain tail: %v", err) 117 } 118 119 // Set runtime fields 120 basic.datadir = datadir 121 basic.db = db 122 basic.genDb = genDb 123 basic.engine = engine 124 basic.gspec = gspec 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 corresponding 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, snaptest.gspec, nil, 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 chain.stopWithoutSaving() 251 252 // Start a new blockchain back up and see where the repair leads us 253 newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false) 254 if err != nil { 255 t.Fatalf("Failed to reopen persistent database: %v", err) 256 } 257 defer newdb.Close() 258 259 // The interesting thing is: instead of starting the blockchain after 260 // the crash, we do restart twice here: one after the crash and one 261 // after the normal stop. It's used to ensure the broken snapshot 262 // can be detected all the time. 263 newchain, err := NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 264 if err != nil { 265 t.Fatalf("Failed to recreate chain: %v", err) 266 } 267 newchain.Stop() 268 269 newchain, err = NewBlockChain(newdb, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 270 if err != nil { 271 t.Fatalf("Failed to recreate chain: %v", err) 272 } 273 defer newchain.Stop() 274 275 snaptest.verify(t, newchain, blocks) 276 } 277 278 // gappedSnapshotTest is a test type used to test this scenario: 279 // - have a complete snapshot 280 // - restart without enabling the snapshot 281 // - insert a few blocks 282 // - restart with enabling the snapshot again 283 type gappedSnapshotTest struct { 284 snapshotTestBasic 285 gapped int // Number of blocks to insert without enabling snapshot 286 } 287 288 func (snaptest *gappedSnapshotTest) test(t *testing.T) { 289 // It's hard to follow the test case, visualize the input 290 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 291 // fmt.Println(tt.dump()) 292 chain, blocks := snaptest.prepare(t) 293 294 // Insert blocks without enabling snapshot if gapping is required. 295 chain.Stop() 296 gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.gapped, func(i int, b *BlockGen) {}) 297 298 // Insert a few more blocks without enabling snapshot 299 var cacheConfig = &CacheConfig{ 300 TrieCleanLimit: 256, 301 TrieDirtyLimit: 256, 302 TrieTimeLimit: 5 * time.Minute, 303 SnapshotLimit: 0, 304 } 305 newchain, err := NewBlockChain(snaptest.db, cacheConfig, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 306 if err != nil { 307 t.Fatalf("Failed to recreate chain: %v", err) 308 } 309 newchain.InsertChain(gappedBlocks) 310 newchain.Stop() 311 312 // Restart the chain with enabling the snapshot 313 newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 314 if err != nil { 315 t.Fatalf("Failed to recreate chain: %v", err) 316 } 317 defer newchain.Stop() 318 319 snaptest.verify(t, newchain, blocks) 320 } 321 322 // setHeadSnapshotTest is the test type used to test this scenario: 323 // - have a complete snapshot 324 // - set the head to a lower point 325 // - restart 326 type setHeadSnapshotTest struct { 327 snapshotTestBasic 328 setHead uint64 // Block number to set head back to 329 } 330 331 func (snaptest *setHeadSnapshotTest) test(t *testing.T) { 332 // It's hard to follow the test case, visualize the input 333 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 334 // fmt.Println(tt.dump()) 335 chain, blocks := snaptest.prepare(t) 336 337 // Rewind the chain if setHead operation is required. 338 chain.SetHead(snaptest.setHead) 339 chain.Stop() 340 341 newchain, err := NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 342 if err != nil { 343 t.Fatalf("Failed to recreate chain: %v", err) 344 } 345 defer newchain.Stop() 346 347 snaptest.verify(t, newchain, blocks) 348 } 349 350 // wipeCrashSnapshotTest is the test type used to test this scenario: 351 // - have a complete snapshot 352 // - restart, insert more blocks without enabling the snapshot 353 // - restart again with enabling the snapshot 354 // - crash 355 type wipeCrashSnapshotTest struct { 356 snapshotTestBasic 357 newBlocks int 358 } 359 360 func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { 361 // It's hard to follow the test case, visualize the input 362 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 363 // fmt.Println(tt.dump()) 364 chain, blocks := snaptest.prepare(t) 365 366 // Firstly, stop the chain properly, with all snapshot journal 367 // and state committed. 368 chain.Stop() 369 370 config := &CacheConfig{ 371 TrieCleanLimit: 256, 372 TrieDirtyLimit: 256, 373 TrieTimeLimit: 5 * time.Minute, 374 SnapshotLimit: 0, 375 } 376 newchain, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 377 if err != nil { 378 t.Fatalf("Failed to recreate chain: %v", err) 379 } 380 newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.genDb, snaptest.newBlocks, func(i int, b *BlockGen) {}) 381 newchain.InsertChain(newBlocks) 382 newchain.Stop() 383 384 // Restart the chain, the wiper should starts working 385 config = &CacheConfig{ 386 TrieCleanLimit: 256, 387 TrieDirtyLimit: 256, 388 TrieTimeLimit: 5 * time.Minute, 389 SnapshotLimit: 256, 390 SnapshotWait: false, // Don't wait rebuild 391 } 392 tmp, err := NewBlockChain(snaptest.db, config, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 393 if err != nil { 394 t.Fatalf("Failed to recreate chain: %v", err) 395 } 396 397 // Simulate the blockchain crash. 398 tmp.stopWithoutSaving() 399 400 newchain, err = NewBlockChain(snaptest.db, nil, snaptest.gspec, nil, snaptest.engine, vm.Config{}, nil, nil) 401 if err != nil { 402 t.Fatalf("Failed to recreate chain: %v", err) 403 } 404 defer newchain.Stop() 405 snaptest.verify(t, newchain, blocks) 406 } 407 408 // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot 409 // journal will be persisted correctly. In this case no snapshot recovery is 410 // required. 411 func TestRestartWithNewSnapshot(t *testing.T) { 412 // Chain: 413 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 414 // 415 // Commit: G 416 // Snapshot: G 417 // 418 // SetHead(0) 419 // 420 // ------------------------------ 421 // 422 // Expected in leveldb: 423 // G->C1->C2->C3->C4->C5->C6->C7->C8 424 // 425 // Expected head header : C8 426 // Expected head fast block: C8 427 // Expected head block : C8 428 // Expected snapshot disk : G 429 test := &snapshotTest{ 430 snapshotTestBasic{ 431 chainBlocks: 8, 432 snapshotBlock: 0, 433 commitBlock: 0, 434 expCanonicalBlocks: 8, 435 expHeadHeader: 8, 436 expHeadFastBlock: 8, 437 expHeadBlock: 8, 438 expSnapshotBottom: 0, // Initial disk layer built from genesis 439 }, 440 } 441 test.test(t) 442 test.teardown() 443 } 444 445 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 446 // chain head should be rewound to the point with available state. And also the 447 // new head should must be lower than disk layer. But there is no committed point 448 // so the chain should be rewound to genesis and the disk layer should be left 449 // for recovery. 450 func TestNoCommitCrashWithNewSnapshot(t *testing.T) { 451 // Chain: 452 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 453 // 454 // Commit: G 455 // Snapshot: G, C4 456 // 457 // CRASH 458 // 459 // ------------------------------ 460 // 461 // Expected in leveldb: 462 // G->C1->C2->C3->C4->C5->C6->C7->C8 463 // 464 // Expected head header : C8 465 // Expected head fast block: C8 466 // Expected head block : G 467 // Expected snapshot disk : C4 468 test := &crashSnapshotTest{ 469 snapshotTestBasic{ 470 chainBlocks: 8, 471 snapshotBlock: 4, 472 commitBlock: 0, 473 expCanonicalBlocks: 8, 474 expHeadHeader: 8, 475 expHeadFastBlock: 8, 476 expHeadBlock: 0, 477 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 478 }, 479 } 480 test.test(t) 481 test.teardown() 482 } 483 484 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 485 // chain head should be rewound to the point with available state. And also the 486 // new head should must be lower than disk layer. But there is only a low committed 487 // point so the chain should be rewound to committed point and the disk layer 488 // should be left for recovery. 489 func TestLowCommitCrashWithNewSnapshot(t *testing.T) { 490 // Chain: 491 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 492 // 493 // Commit: G, C2 494 // Snapshot: G, C4 495 // 496 // CRASH 497 // 498 // ------------------------------ 499 // 500 // Expected in leveldb: 501 // G->C1->C2->C3->C4->C5->C6->C7->C8 502 // 503 // Expected head header : C8 504 // Expected head fast block: C8 505 // Expected head block : C2 506 // Expected snapshot disk : C4 507 test := &crashSnapshotTest{ 508 snapshotTestBasic{ 509 chainBlocks: 8, 510 snapshotBlock: 4, 511 commitBlock: 2, 512 expCanonicalBlocks: 8, 513 expHeadHeader: 8, 514 expHeadFastBlock: 8, 515 expHeadBlock: 2, 516 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 517 }, 518 } 519 test.test(t) 520 test.teardown() 521 } 522 523 // Tests a Geth was crashed and restarts with a broken snapshot. In this case 524 // the chain head should be rewound to the point with available state. And also 525 // the new head should must be lower than disk layer. But there is only a high 526 // committed point so the chain should be rewound to genesis and the disk layer 527 // should be left for recovery. 528 func TestHighCommitCrashWithNewSnapshot(t *testing.T) { 529 // Chain: 530 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 531 // 532 // Commit: G, C6 533 // Snapshot: G, C4 534 // 535 // CRASH 536 // 537 // ------------------------------ 538 // 539 // Expected in leveldb: 540 // G->C1->C2->C3->C4->C5->C6->C7->C8 541 // 542 // Expected head header : C8 543 // Expected head fast block: C8 544 // Expected head block : G 545 // Expected snapshot disk : C4 546 test := &crashSnapshotTest{ 547 snapshotTestBasic{ 548 chainBlocks: 8, 549 snapshotBlock: 4, 550 commitBlock: 6, 551 expCanonicalBlocks: 8, 552 expHeadHeader: 8, 553 expHeadFastBlock: 8, 554 expHeadBlock: 0, 555 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 556 }, 557 } 558 test.test(t) 559 test.teardown() 560 } 561 562 // Tests a Geth was running with snapshot enabled. Then restarts without 563 // enabling snapshot and after that re-enable the snapshot again. In this 564 // case the snapshot should be rebuilt with latest chain head. 565 func TestGappedNewSnapshot(t *testing.T) { 566 // Chain: 567 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 568 // 569 // Commit: G 570 // Snapshot: G 571 // 572 // SetHead(0) 573 // 574 // ------------------------------ 575 // 576 // Expected in leveldb: 577 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 578 // 579 // Expected head header : C10 580 // Expected head fast block: C10 581 // Expected head block : C10 582 // Expected snapshot disk : C10 583 test := &gappedSnapshotTest{ 584 snapshotTestBasic: snapshotTestBasic{ 585 chainBlocks: 8, 586 snapshotBlock: 0, 587 commitBlock: 0, 588 expCanonicalBlocks: 10, 589 expHeadHeader: 10, 590 expHeadFastBlock: 10, 591 expHeadBlock: 10, 592 expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD 593 }, 594 gapped: 2, 595 } 596 test.test(t) 597 test.teardown() 598 } 599 600 // Tests the Geth was running with snapshot enabled and resetHead is applied. 601 // In this case the head is rewound to the target(with state available). After 602 // that the chain is restarted and the original disk layer is kept. 603 func TestSetHeadWithNewSnapshot(t *testing.T) { 604 // Chain: 605 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 606 // 607 // Commit: G 608 // Snapshot: G 609 // 610 // SetHead(4) 611 // 612 // ------------------------------ 613 // 614 // Expected in leveldb: 615 // G->C1->C2->C3->C4 616 // 617 // Expected head header : C4 618 // Expected head fast block: C4 619 // Expected head block : C4 620 // Expected snapshot disk : G 621 test := &setHeadSnapshotTest{ 622 snapshotTestBasic: snapshotTestBasic{ 623 chainBlocks: 8, 624 snapshotBlock: 0, 625 commitBlock: 0, 626 expCanonicalBlocks: 4, 627 expHeadHeader: 4, 628 expHeadFastBlock: 4, 629 expHeadBlock: 4, 630 expSnapshotBottom: 0, // The initial disk layer is built from the genesis 631 }, 632 setHead: 4, 633 } 634 test.test(t) 635 test.teardown() 636 } 637 638 // Tests the Geth was running with a complete snapshot and then imports a few 639 // more new blocks on top without enabling the snapshot. After the restart, 640 // crash happens. Check everything is ok after the restart. 641 func TestRecoverSnapshotFromWipingCrash(t *testing.T) { 642 // Chain: 643 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 644 // 645 // Commit: G 646 // Snapshot: G 647 // 648 // SetHead(0) 649 // 650 // ------------------------------ 651 // 652 // Expected in leveldb: 653 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 654 // 655 // Expected head header : C10 656 // Expected head fast block: C10 657 // Expected head block : C8 658 // Expected snapshot disk : C10 659 test := &wipeCrashSnapshotTest{ 660 snapshotTestBasic: snapshotTestBasic{ 661 chainBlocks: 8, 662 snapshotBlock: 4, 663 commitBlock: 0, 664 expCanonicalBlocks: 10, 665 expHeadHeader: 10, 666 expHeadFastBlock: 10, 667 expHeadBlock: 10, 668 expSnapshotBottom: 10, 669 }, 670 newBlocks: 2, 671 } 672 test.test(t) 673 test.teardown() 674 }