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  }