github.com/bearnetworkchain/go-bearnetwork@v1.10.19-0.20220604150648-d63890c2e42b/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/bearnetworkchain/go-bearnetwork/consensus" 32 "github.com/bearnetworkchain/go-bearnetwork/consensus/ethash" 33 "github.com/bearnetworkchain/go-bearnetwork/core/rawdb" 34 "github.com/bearnetworkchain/go-bearnetwork/core/types" 35 "github.com/bearnetworkchain/go-bearnetwork/core/vm" 36 "github.com/bearnetworkchain/go-bearnetwork/ethdb" 37 "github.com/bearnetworkchain/go-bearnetwork/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 func (basic *snapshotTestBasic) dump() string { 154 buffer := new(strings.Builder) 155 156 fmt.Fprint(buffer, "Chain:\n G") 157 for i := 0; i < basic.chainBlocks; i++ { 158 fmt.Fprintf(buffer, "->C%d", i+1) 159 } 160 fmt.Fprint(buffer, " (HEAD)\n\n") 161 162 fmt.Fprintf(buffer, "Commit: G") 163 if basic.commitBlock > 0 { 164 fmt.Fprintf(buffer, ", C%d", basic.commitBlock) 165 } 166 fmt.Fprint(buffer, "\n") 167 168 fmt.Fprintf(buffer, "Snapshot: G") 169 if basic.snapshotBlock > 0 { 170 fmt.Fprintf(buffer, ", C%d", basic.snapshotBlock) 171 } 172 fmt.Fprint(buffer, "\n") 173 174 //if crash { 175 // fmt.Fprintf(buffer, "\nCRASH\n\n") 176 //} else { 177 // fmt.Fprintf(buffer, "\nSetHead(%d)\n\n", basic.setHead) 178 //} 179 fmt.Fprintf(buffer, "------------------------------\n\n") 180 181 fmt.Fprint(buffer, "Expected in leveldb:\n G") 182 for i := 0; i < basic.expCanonicalBlocks; i++ { 183 fmt.Fprintf(buffer, "->C%d", i+1) 184 } 185 fmt.Fprintf(buffer, "\n\n") 186 fmt.Fprintf(buffer, "Expected head header : C%d\n", basic.expHeadHeader) 187 fmt.Fprintf(buffer, "Expected head fast block: C%d\n", basic.expHeadFastBlock) 188 if basic.expHeadBlock == 0 { 189 fmt.Fprintf(buffer, "Expected head block : G\n") 190 } else { 191 fmt.Fprintf(buffer, "Expected head block : C%d\n", basic.expHeadBlock) 192 } 193 if basic.expSnapshotBottom == 0 { 194 fmt.Fprintf(buffer, "Expected snapshot disk : G\n") 195 } else { 196 fmt.Fprintf(buffer, "Expected snapshot disk : C%d\n", basic.expSnapshotBottom) 197 } 198 return buffer.String() 199 } 200 201 func (basic *snapshotTestBasic) teardown() { 202 basic.db.Close() 203 basic.gendb.Close() 204 os.RemoveAll(basic.datadir) 205 } 206 207 // snapshotTest is a test case type for normal snapshot recovery. 208 // It can be used for testing that restart Geth normally. 209 type snapshotTest struct { 210 snapshotTestBasic 211 } 212 213 func (snaptest *snapshotTest) test(t *testing.T) { 214 // It's hard to follow the test case, visualize the input 215 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 216 // fmt.Println(tt.dump()) 217 chain, blocks := snaptest.prepare(t) 218 219 // Restart the chain normally 220 chain.Stop() 221 newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 222 if err != nil { 223 t.Fatalf("Failed to recreate chain: %v", err) 224 } 225 defer newchain.Stop() 226 227 snaptest.verify(t, newchain, blocks) 228 } 229 230 // crashSnapshotTest is a test case type for innormal snapshot recovery. 231 // It can be used for testing that restart Geth after the crash. 232 type crashSnapshotTest struct { 233 snapshotTestBasic 234 } 235 236 func (snaptest *crashSnapshotTest) test(t *testing.T) { 237 // It's hard to follow the test case, visualize the input 238 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 239 // fmt.Println(tt.dump()) 240 chain, blocks := snaptest.prepare(t) 241 242 // Pull the plug on the database, simulating a hard crash 243 db := chain.db 244 db.Close() 245 246 // Start a new blockchain back up and see where the repair leads us 247 newdb, err := rawdb.NewLevelDBDatabaseWithFreezer(snaptest.datadir, 0, 0, snaptest.datadir, "", false) 248 if err != nil { 249 t.Fatalf("Failed to reopen persistent database: %v", err) 250 } 251 defer newdb.Close() 252 253 // The interesting thing is: instead of starting the blockchain after 254 // the crash, we do restart twice here: one after the crash and one 255 // after the normal stop. It's used to ensure the broken snapshot 256 // can be detected all the time. 257 newchain, err := NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 258 if err != nil { 259 t.Fatalf("Failed to recreate chain: %v", err) 260 } 261 newchain.Stop() 262 263 newchain, err = NewBlockChain(newdb, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 264 if err != nil { 265 t.Fatalf("Failed to recreate chain: %v", err) 266 } 267 defer newchain.Stop() 268 269 snaptest.verify(t, newchain, blocks) 270 } 271 272 // gappedSnapshotTest is a test type used to test this scenario: 273 // - have a complete snapshot 274 // - restart without enabling the snapshot 275 // - insert a few blocks 276 // - restart with enabling the snapshot again 277 type gappedSnapshotTest struct { 278 snapshotTestBasic 279 gapped int // Number of blocks to insert without enabling snapshot 280 } 281 282 func (snaptest *gappedSnapshotTest) test(t *testing.T) { 283 // It's hard to follow the test case, visualize the input 284 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 285 // fmt.Println(tt.dump()) 286 chain, blocks := snaptest.prepare(t) 287 288 // Insert blocks without enabling snapshot if gapping is required. 289 chain.Stop() 290 gappedBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.gapped, func(i int, b *BlockGen) {}) 291 292 // Insert a few more blocks without enabling snapshot 293 var cacheConfig = &CacheConfig{ 294 TrieCleanLimit: 256, 295 TrieDirtyLimit: 256, 296 TrieTimeLimit: 5 * time.Minute, 297 SnapshotLimit: 0, 298 } 299 newchain, err := NewBlockChain(snaptest.db, cacheConfig, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 300 if err != nil { 301 t.Fatalf("Failed to recreate chain: %v", err) 302 } 303 newchain.InsertChain(gappedBlocks) 304 newchain.Stop() 305 306 // Restart the chain with enabling the snapshot 307 newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 308 if err != nil { 309 t.Fatalf("Failed to recreate chain: %v", err) 310 } 311 defer newchain.Stop() 312 313 snaptest.verify(t, newchain, blocks) 314 } 315 316 // setHeadSnapshotTest is the test type used to test this scenario: 317 // - have a complete snapshot 318 // - set the head to a lower point 319 // - restart 320 type setHeadSnapshotTest struct { 321 snapshotTestBasic 322 setHead uint64 // Block number to set head back to 323 } 324 325 func (snaptest *setHeadSnapshotTest) test(t *testing.T) { 326 // It's hard to follow the test case, visualize the input 327 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 328 // fmt.Println(tt.dump()) 329 chain, blocks := snaptest.prepare(t) 330 331 // Rewind the chain if setHead operation is required. 332 chain.SetHead(snaptest.setHead) 333 chain.Stop() 334 335 newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 336 if err != nil { 337 t.Fatalf("Failed to recreate chain: %v", err) 338 } 339 defer newchain.Stop() 340 341 snaptest.verify(t, newchain, blocks) 342 } 343 344 // restartCrashSnapshotTest is the test type used to test this scenario: 345 // - have a complete snapshot 346 // - restart chain 347 // - insert more blocks with enabling the snapshot 348 // - commit the snapshot 349 // - crash 350 // - restart again 351 type restartCrashSnapshotTest struct { 352 snapshotTestBasic 353 newBlocks int 354 } 355 356 func (snaptest *restartCrashSnapshotTest) test(t *testing.T) { 357 // It's hard to follow the test case, visualize the input 358 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 359 // fmt.Println(tt.dump()) 360 chain, blocks := snaptest.prepare(t) 361 362 // Firstly, stop the chain properly, with all snapshot journal 363 // and state committed. 364 chain.Stop() 365 366 newchain, err := NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 367 if err != nil { 368 t.Fatalf("Failed to recreate chain: %v", err) 369 } 370 newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) 371 newchain.InsertChain(newBlocks) 372 373 // Commit the entire snapshot into the disk if requested. Note only 374 // (a) snapshot root and (b) snapshot generator will be committed, 375 // the diff journal is not. 376 newchain.Snapshots().Cap(newBlocks[len(newBlocks)-1].Root(), 0) 377 378 // Simulate the blockchain crash 379 // Don't call chain.Stop here, so that no snapshot 380 // journal and latest state will be committed 381 382 // Restart the chain after the crash 383 newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 384 if err != nil { 385 t.Fatalf("Failed to recreate chain: %v", err) 386 } 387 defer newchain.Stop() 388 389 snaptest.verify(t, newchain, blocks) 390 } 391 392 // wipeCrashSnapshotTest is the test type used to test this scenario: 393 // - have a complete snapshot 394 // - restart, insert more blocks without enabling the snapshot 395 // - restart again with enabling the snapshot 396 // - crash 397 type wipeCrashSnapshotTest struct { 398 snapshotTestBasic 399 newBlocks int 400 } 401 402 func (snaptest *wipeCrashSnapshotTest) test(t *testing.T) { 403 // It's hard to follow the test case, visualize the input 404 // log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 405 // fmt.Println(tt.dump()) 406 chain, blocks := snaptest.prepare(t) 407 408 // Firstly, stop the chain properly, with all snapshot journal 409 // and state committed. 410 chain.Stop() 411 412 config := &CacheConfig{ 413 TrieCleanLimit: 256, 414 TrieDirtyLimit: 256, 415 TrieTimeLimit: 5 * time.Minute, 416 SnapshotLimit: 0, 417 } 418 newchain, err := NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 419 if err != nil { 420 t.Fatalf("Failed to recreate chain: %v", err) 421 } 422 newBlocks, _ := GenerateChain(params.TestChainConfig, blocks[len(blocks)-1], snaptest.engine, snaptest.gendb, snaptest.newBlocks, func(i int, b *BlockGen) {}) 423 newchain.InsertChain(newBlocks) 424 newchain.Stop() 425 426 // Restart the chain, the wiper should starts working 427 config = &CacheConfig{ 428 TrieCleanLimit: 256, 429 TrieDirtyLimit: 256, 430 TrieTimeLimit: 5 * time.Minute, 431 SnapshotLimit: 256, 432 SnapshotWait: false, // Don't wait rebuild 433 } 434 newchain, err = NewBlockChain(snaptest.db, config, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 435 if err != nil { 436 t.Fatalf("Failed to recreate chain: %v", err) 437 } 438 // Simulate the blockchain crash. 439 440 newchain, err = NewBlockChain(snaptest.db, nil, params.AllEthashProtocolChanges, snaptest.engine, vm.Config{}, nil, nil) 441 if err != nil { 442 t.Fatalf("Failed to recreate chain: %v", err) 443 } 444 snaptest.verify(t, newchain, blocks) 445 } 446 447 // Tests a Geth restart with valid snapshot. Before the shutdown, all snapshot 448 // journal will be persisted correctly. In this case no snapshot recovery is 449 // required. 450 func TestRestartWithNewSnapshot(t *testing.T) { 451 // Chain: 452 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 453 // 454 // Commit: G 455 // Snapshot: G 456 // 457 // SetHead(0) 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 : C8 467 // Expected snapshot disk : G 468 test := &snapshotTest{ 469 snapshotTestBasic{ 470 chainBlocks: 8, 471 snapshotBlock: 0, 472 commitBlock: 0, 473 expCanonicalBlocks: 8, 474 expHeadHeader: 8, 475 expHeadFastBlock: 8, 476 expHeadBlock: 8, 477 expSnapshotBottom: 0, // Initial disk layer built from genesis 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 no committed point 487 // so the chain should be rewound to genesis and the disk layer should be left 488 // for recovery. 489 func TestNoCommitCrashWithNewSnapshot(t *testing.T) { 490 // Chain: 491 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 492 // 493 // Commit: G 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 : G 506 // Expected snapshot disk : C4 507 test := &crashSnapshotTest{ 508 snapshotTestBasic{ 509 chainBlocks: 8, 510 snapshotBlock: 4, 511 commitBlock: 0, 512 expCanonicalBlocks: 8, 513 expHeadHeader: 8, 514 expHeadFastBlock: 8, 515 expHeadBlock: 0, 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 the 524 // chain head should be rewound to the point with available state. And also the 525 // new head should must be lower than disk layer. But there is only a low committed 526 // point so the chain should be rewound to committed point and the disk layer 527 // should be left for recovery. 528 func TestLowCommitCrashWithNewSnapshot(t *testing.T) { 529 // Chain: 530 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 531 // 532 // Commit: G, C2 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 : C2 545 // Expected snapshot disk : C4 546 test := &crashSnapshotTest{ 547 snapshotTestBasic{ 548 chainBlocks: 8, 549 snapshotBlock: 4, 550 commitBlock: 2, 551 expCanonicalBlocks: 8, 552 expHeadHeader: 8, 553 expHeadFastBlock: 8, 554 expHeadBlock: 2, 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 crashed and restarts with a broken snapshot. In this case 563 // the chain head should be rewound to the point with available state. And also 564 // the new head should must be lower than disk layer. But there is only a high 565 // committed point so the chain should be rewound to genesis and the disk layer 566 // should be left for recovery. 567 func TestHighCommitCrashWithNewSnapshot(t *testing.T) { 568 // Chain: 569 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 570 // 571 // Commit: G, C6 572 // Snapshot: G, C4 573 // 574 // CRASH 575 // 576 // ------------------------------ 577 // 578 // Expected in leveldb: 579 // G->C1->C2->C3->C4->C5->C6->C7->C8 580 // 581 // Expected head header : C8 582 // Expected head fast block: C8 583 // Expected head block : G 584 // Expected snapshot disk : C4 585 test := &crashSnapshotTest{ 586 snapshotTestBasic{ 587 chainBlocks: 8, 588 snapshotBlock: 4, 589 commitBlock: 6, 590 expCanonicalBlocks: 8, 591 expHeadHeader: 8, 592 expHeadFastBlock: 8, 593 expHeadBlock: 0, 594 expSnapshotBottom: 4, // Last committed disk layer, wait recovery 595 }, 596 } 597 test.test(t) 598 test.teardown() 599 } 600 601 // Tests a Geth was running with snapshot enabled. Then restarts without 602 // enabling snapshot and after that re-enable the snapshot again. In this 603 // case the snapshot should be rebuilt with latest chain head. 604 func TestGappedNewSnapshot(t *testing.T) { 605 // Chain: 606 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 607 // 608 // Commit: G 609 // Snapshot: G 610 // 611 // SetHead(0) 612 // 613 // ------------------------------ 614 // 615 // Expected in leveldb: 616 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 617 // 618 // Expected head header : C10 619 // Expected head fast block: C10 620 // Expected head block : C10 621 // Expected snapshot disk : C10 622 test := &gappedSnapshotTest{ 623 snapshotTestBasic: snapshotTestBasic{ 624 chainBlocks: 8, 625 snapshotBlock: 0, 626 commitBlock: 0, 627 expCanonicalBlocks: 10, 628 expHeadHeader: 10, 629 expHeadFastBlock: 10, 630 expHeadBlock: 10, 631 expSnapshotBottom: 10, // Rebuilt snapshot from the latest HEAD 632 }, 633 gapped: 2, 634 } 635 test.test(t) 636 test.teardown() 637 } 638 639 // Tests the Geth was running with snapshot enabled and resetHead is applied. 640 // In this case the head is rewound to the target(with state available). After 641 // that the chain is restarted and the original disk layer is kept. 642 func TestSetHeadWithNewSnapshot(t *testing.T) { 643 // Chain: 644 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 645 // 646 // Commit: G 647 // Snapshot: G 648 // 649 // SetHead(4) 650 // 651 // ------------------------------ 652 // 653 // Expected in leveldb: 654 // G->C1->C2->C3->C4 655 // 656 // Expected head header : C4 657 // Expected head fast block: C4 658 // Expected head block : C4 659 // Expected snapshot disk : G 660 test := &setHeadSnapshotTest{ 661 snapshotTestBasic: snapshotTestBasic{ 662 chainBlocks: 8, 663 snapshotBlock: 0, 664 commitBlock: 0, 665 expCanonicalBlocks: 4, 666 expHeadHeader: 4, 667 expHeadFastBlock: 4, 668 expHeadBlock: 4, 669 expSnapshotBottom: 0, // The initial disk layer is built from the genesis 670 }, 671 setHead: 4, 672 } 673 test.test(t) 674 test.teardown() 675 } 676 677 // Tests the Geth was running with a complete snapshot and then imports a few 678 // more new blocks on top without enabling the snapshot. After the restart, 679 // crash happens. Check everything is ok after the restart. 680 func TestRecoverSnapshotFromWipingCrash(t *testing.T) { 681 // Chain: 682 // G->C1->C2->C3->C4->C5->C6->C7->C8 (HEAD) 683 // 684 // Commit: G 685 // Snapshot: G 686 // 687 // SetHead(0) 688 // 689 // ------------------------------ 690 // 691 // Expected in leveldb: 692 // G->C1->C2->C3->C4->C5->C6->C7->C8->C9->C10 693 // 694 // Expected head header : C10 695 // Expected head fast block: C10 696 // Expected head block : C8 697 // Expected snapshot disk : C10 698 test := &wipeCrashSnapshotTest{ 699 snapshotTestBasic: snapshotTestBasic{ 700 chainBlocks: 8, 701 snapshotBlock: 4, 702 commitBlock: 0, 703 expCanonicalBlocks: 10, 704 expHeadHeader: 10, 705 expHeadFastBlock: 10, 706 expHeadBlock: 10, 707 expSnapshotBottom: 10, 708 }, 709 newBlocks: 2, 710 } 711 test.test(t) 712 test.teardown() 713 }