github.com/Cleverse/go-ethereum@v0.0.0-20220927095127-45113064e7f2/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 296 // Arbitrum 297 TriesInMemory: 128, 298 TrieRetention: 30 * time.Minute, 299 300 TrieCleanLimit: 256, 301 TrieDirtyLimit: 256, 302 TrieTimeLimit: 5 * time.Minute, 303 SnapshotLimit: 0, 304 } 305 newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, 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, params.AllEthashProtocolChanges, 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, params.AllEthashProtocolChanges, 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 372 // Arbitrum 373 TriesInMemory: 128, 374 TrieRetention: 30 * time.Minute, 375 376 TrieCleanLimit: 256, 377 TrieDirtyLimit: 256, 378 TrieTimeLimit: 5 * time.Minute, 379 SnapshotLimit: 0, 380 } 381 newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 382 if err != nil { 383 t.Fatalf("Failed to recreate chain: %v", err) 384 } 385 newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) 386 newchain.InsertChain(newBlocks) 387 newchain.Stop() 388 389 // Restart the chain, the wiper should starts working 390 config = &CacheConfig{ 391 392 // Arbitrum 393 TriesInMemory: 128, 394 TrieRetention: 30 * time.Minute, 395 396 TrieCleanLimit: 256, 397 TrieDirtyLimit: 256, 398 TrieTimeLimit: 5 * time.Minute, 399 SnapshotLimit: 256, 400 SnapshotWait: false, // Don't wait rebuild 401 } 402 _, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 403 if err != nil { 404 t.Fatalf("Failed to recreate chain: %v", err) 405 } 406 // Simulate the blockchain crash. 407 408 newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 409 if err != nil { 410 t.Fatalf("Failed to recreate chain: %v", err) 411 } 412 snaptest.verify(t, newchain, blocks) 413 } 414 415 // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot 416 // journal will be persisted correctly. In this case no snapshot recovery is 417 // required. 418 func TestRestartWithNewSnapshot(t *testing.T) { 419 // Chain: 420 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 421 // 422 // Commit: G 423 // Snapshot: G 424 // 425 // SetHead(0) 426 // 427 // ------------------------------ 428 // 429 // Expected in leveldb: 430 // G->C1->C2->C3->C4->C5->C6->C7->C8 431 // 432 // Expected head header : C8 433 // Expected head fast block: C8 434 // Expected head block : C8 435 // Expected snapshot disk : G 436 test := &snapshotTest{ 437 snapshotTestBasic{ 438 chainBlocks: 8, 439 snapshotBlock: 0, 440 commitBlock: 0, 441 expCanonicalBlocks: 8, 442 expHeadHeader: 8, 443 expHeadFastBlock: 8, 444 expHeadBlock: 8, 445 expSnapshotBottom: 0, // Initial disk layer built from genesis 446 }, 447 } 448 test.test(t) 449 test.teardown() 450 } 451 452 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 453 // chain head should be rewound to the point with available state. And also the 454 // new head should must be lower than disk layer. But there is no committed point 455 // so the chain should be rewound to genesis and the disk layer should be left 456 // for recovery. 457 func TestNoCommitCrashWithNewSnapshot(t *testing.T) { 458 // Chain: 459 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 460 // 461 // Commit: G 462 // Snapshot: G, C4 463 // 464 // CRASH 465 // 466 // ------------------------------ 467 // 468 // Expected in leveldb: 469 // G->C1->C2->C3->C4->C5->C6->C7->C8 470 // 471 // Expected head header : C8 472 // Expected head fast block: C8 473 // Expected head block : G 474 // Expected snapshot disk : C4 475 test := &crashSnapshotTest{ 476 snapshotTestBasic{ 477 chainBlocks: 8, 478 snapshotBlock: 4, 479 commitBlock: 0, 480 expCanonicalBlocks: 8, 481 expHeadHeader: 8, 482 expHeadFastBlock: 8, 483 expHeadBlock: 0, 484 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 485 }, 486 } 487 test.test(t) 488 test.teardown() 489 } 490 491 // Tests a Geth was crashed and restarts with a broken snapshot. In this case the 492 // chain head should be rewound to the point with available state. And also the 493 // new head should must be lower than disk layer. But there is only a low committed 494 // point so the chain should be rewound to committed point and the disk layer 495 // should be left for recovery. 496 func TestLowCommitCrashWithNewSnapshot(t *testing.T) { 497 // Chain: 498 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 499 // 500 // Commit: G, C2 501 // Snapshot: G, C4 502 // 503 // CRASH 504 // 505 // ------------------------------ 506 // 507 // Expected in leveldb: 508 // G->C1->C2->C3->C4->C5->C6->C7->C8 509 // 510 // Expected head header : C8 511 // Expected head fast block: C8 512 // Expected head block : C2 513 // Expected snapshot disk : C4 514 test := &crashSnapshotTest{ 515 snapshotTestBasic{ 516 chainBlocks: 8, 517 snapshotBlock: 4, 518 commitBlock: 2, 519 expCanonicalBlocks: 8, 520 expHeadHeader: 8, 521 expHeadFastBlock: 8, 522 expHeadBlock: 2, 523 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 524 }, 525 } 526 test.test(t) 527 test.teardown() 528 } 529 530 // Tests a Geth was crashed and restarts with a broken snapshot. In this case 531 // the chain head should be rewound to the point with available state. And also 532 // the new head should must be lower than disk layer. But there is only a high 533 // committed point so the chain should be rewound to genesis and the disk layer 534 // should be left for recovery. 535 func TestHighCommitCrashWithNewSnapshot(t *testing.T) { 536 // Chain: 537 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 538 // 539 // Commit: G, C6 540 // Snapshot: G, C4 541 // 542 // CRASH 543 // 544 // ------------------------------ 545 // 546 // Expected in leveldb: 547 // G->C1->C2->C3->C4->C5->C6->C7->C8 548 // 549 // Expected head header : C8 550 // Expected head fast block: C8 551 // Expected head block : G 552 // Expected snapshot disk : C4 553 test := &crashSnapshotTest{ 554 snapshotTestBasic{ 555 chainBlocks: 8, 556 snapshotBlock: 4, 557 commitBlock: 6, 558 expCanonicalBlocks: 8, 559 expHeadHeader: 8, 560 expHeadFastBlock: 8, 561 expHeadBlock: 0, 562 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 563 }, 564 } 565 test.test(t) 566 test.teardown() 567 } 568 569 // Tests a Geth was running with snapshot enabled. Then restarts without 570 // enabling snapshot and after that re-enable the snapshot again. In this 571 // case the snapshot should be rebuilt with latest chain head. 572 func TestGappedNewSnapshot(t *testing.T) { 573 // Chain: 574 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 575 // 576 // Commit: G 577 // Snapshot: G 578 // 579 // SetHead(0) 580 // 581 // ------------------------------ 582 // 583 // Expected in leveldb: 584 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 585 // 586 // Expected head header : C10 587 // Expected head fast block: C10 588 // Expected head block : C10 589 // Expected snapshot disk : C10 590 test := &gappedSnapshotTest{ 591 snapshotTestBasic: snapshotTestBasic{ 592 chainBlocks: 8, 593 snapshotBlock: 0, 594 commitBlock: 0, 595 expCanonicalBlocks: 10, 596 expHeadHeader: 10, 597 expHeadFastBlock: 10, 598 expHeadBlock: 10, 599 expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD 600 }, 601 gapped: 2, 602 } 603 test.test(t) 604 test.teardown() 605 } 606 607 // Tests the Geth was running with snapshot enabled and resetHead is applied. 608 // In this case the head is rewound to the target(with state available). After 609 // that the chain is restarted and the original disk layer is kept. 610 func TestSetHeadWithNewSnapshot(t *testing.T) { 611 // Chain: 612 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 613 // 614 // Commit: G 615 // Snapshot: G 616 // 617 // SetHead(4) 618 // 619 // ------------------------------ 620 // 621 // Expected in leveldb: 622 // G->C1->C2->C3->C4 623 // 624 // Expected head header : C4 625 // Expected head fast block: C4 626 // Expected head block : C4 627 // Expected snapshot disk : G 628 test := &setHeadSnapshotTest{ 629 snapshotTestBasic: snapshotTestBasic{ 630 chainBlocks: 8, 631 snapshotBlock: 0, 632 commitBlock: 0, 633 expCanonicalBlocks: 4, 634 expHeadHeader: 4, 635 expHeadFastBlock: 4, 636 expHeadBlock: 4, 637 expSnapshotBottom: 0, // The initial disk layer is built from the genesis 638 }, 639 setHead: 4, 640 } 641 test.test(t) 642 test.teardown() 643 } 644 645 // Tests the Geth was running with a complete snapshot and then imports a few 646 // more new blocks on top without enabling the snapshot. After the restart, 647 // crash happens. Check everything is ok after the restart. 648 func TestRecoverSnapshotFromWipingCrash(t *testing.T) { 649 // Chain: 650 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 651 // 652 // Commit: G 653 // Snapshot: G 654 // 655 // SetHead(0) 656 // 657 // ------------------------------ 658 // 659 // Expected in leveldb: 660 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 661 // 662 // Expected head header : C10 663 // Expected head fast block: C10 664 // Expected head block : C8 665 // Expected snapshot disk : C10 666 test := &wipeCrashSnapshotTest{ 667 snapshotTestBasic: snapshotTestBasic{ 668 chainBlocks: 8, 669 snapshotBlock: 4, 670 commitBlock: 0, 671 expCanonicalBlocks: 10, 672 expHeadHeader: 10, 673 expHeadFastBlock: 10, 674 expHeadBlock: 10, 675 expSnapshotBottom: 10, 676 }, 677 newBlocks: 2, 678 } 679 test.test(t) 680 test.teardown() 681 }