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