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