github.com/jimmyx0x/go-ethereum@v1.10.28/light/lightchain_test.go (about)

     1  // Copyright 2016 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  package light
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/consensus/ethash"
    27  	"github.com/ethereum/go-ethereum/core"
    28  	"github.com/ethereum/go-ethereum/core/rawdb"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/ethdb"
    31  	"github.com/ethereum/go-ethereum/params"
    32  )
    33  
    34  // So we can deterministically seed different blockchains
    35  var (
    36  	canonicalSeed = 1
    37  	forkSeed      = 2
    38  )
    39  
    40  // makeHeaderChain creates a deterministic chain of headers rooted at parent.
    41  func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
    42  	blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), ethash.NewFaker(), db, n, func(i int, b *core.BlockGen) {
    43  		b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
    44  	})
    45  	headers := make([]*types.Header, len(blocks))
    46  	for i, block := range blocks {
    47  		headers[i] = block.Header()
    48  	}
    49  	return headers
    50  }
    51  
    52  // newCanonical creates a chain database, and injects a deterministic canonical
    53  // chain. Depending on the full flag, if creates either a full block chain or a
    54  // header only chain.
    55  func newCanonical(n int) (ethdb.Database, *LightChain, error) {
    56  	db := rawdb.NewMemoryDatabase()
    57  	gspec := core.Genesis{Config: params.TestChainConfig}
    58  	genesis := gspec.MustCommit(db)
    59  	blockchain, _ := NewLightChain(&dummyOdr{db: db, indexerConfig: TestClientIndexerConfig}, gspec.Config, ethash.NewFaker(), nil)
    60  
    61  	// Create and inject the requested chain
    62  	if n == 0 {
    63  		return db, blockchain, nil
    64  	}
    65  	// Header-only chain requested
    66  	headers := makeHeaderChain(genesis.Header(), n, db, canonicalSeed)
    67  	_, err := blockchain.InsertHeaderChain(headers, 1)
    68  	return db, blockchain, err
    69  }
    70  
    71  // newTestLightChain creates a LightChain that doesn't validate anything.
    72  func newTestLightChain() *LightChain {
    73  	db := rawdb.NewMemoryDatabase()
    74  	gspec := &core.Genesis{
    75  		Difficulty: big.NewInt(1),
    76  		Config:     params.TestChainConfig,
    77  	}
    78  	gspec.MustCommit(db)
    79  	lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFullFaker(), nil)
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  	return lc
    84  }
    85  
    86  // Test fork of length N starting from block i
    87  func testFork(t *testing.T, LightChain *LightChain, i, n int, comparator func(td1, td2 *big.Int)) {
    88  	// Copy old chain up to #i into a new db
    89  	db, LightChain2, err := newCanonical(i)
    90  	if err != nil {
    91  		t.Fatal("could not make new canonical in testFork", err)
    92  	}
    93  	// Assert the chains have the same header/block at #i
    94  	var hash1, hash2 common.Hash
    95  	hash1 = LightChain.GetHeaderByNumber(uint64(i)).Hash()
    96  	hash2 = LightChain2.GetHeaderByNumber(uint64(i)).Hash()
    97  	if hash1 != hash2 {
    98  		t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1)
    99  	}
   100  	// Extend the newly created chain
   101  	headerChainB := makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed)
   102  	if _, err := LightChain2.InsertHeaderChain(headerChainB, 1); err != nil {
   103  		t.Fatalf("failed to insert forking chain: %v", err)
   104  	}
   105  	// Sanity check that the forked chain can be imported into the original
   106  	var tdPre, tdPost *big.Int
   107  	cur := LightChain.CurrentHeader()
   108  	tdPre = LightChain.GetTd(cur.Hash(), cur.Number.Uint64())
   109  	if err := testHeaderChainImport(headerChainB, LightChain); err != nil {
   110  		t.Fatalf("failed to import forked header chain: %v", err)
   111  	}
   112  	last := headerChainB[len(headerChainB)-1]
   113  	tdPost = LightChain.GetTd(last.Hash(), last.Number.Uint64())
   114  	// Compare the total difficulties of the chains
   115  	comparator(tdPre, tdPost)
   116  }
   117  
   118  // testHeaderChainImport tries to process a chain of header, writing them into
   119  // the database if successful.
   120  func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error {
   121  	for _, header := range chain {
   122  		// Try and validate the header
   123  		if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil {
   124  			return err
   125  		}
   126  		// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
   127  		lightchain.chainmu.Lock()
   128  		rawdb.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(),
   129  			new(big.Int).Add(header.Difficulty, lightchain.GetTd(header.ParentHash, header.Number.Uint64()-1)))
   130  		rawdb.WriteHeader(lightchain.chainDb, header)
   131  		lightchain.chainmu.Unlock()
   132  	}
   133  	return nil
   134  }
   135  
   136  // Tests that given a starting canonical chain of a given size, it can be extended
   137  // with various length chains.
   138  func TestExtendCanonicalHeaders(t *testing.T) {
   139  	length := 5
   140  
   141  	// Make first chain starting from genesis
   142  	_, processor, err := newCanonical(length)
   143  	if err != nil {
   144  		t.Fatalf("failed to make new canonical chain: %v", err)
   145  	}
   146  	// Define the difficulty comparator
   147  	better := func(td1, td2 *big.Int) {
   148  		if td2.Cmp(td1) <= 0 {
   149  			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
   150  		}
   151  	}
   152  	// Start fork from current height
   153  	testFork(t, processor, length, 1, better)
   154  	testFork(t, processor, length, 2, better)
   155  	testFork(t, processor, length, 5, better)
   156  	testFork(t, processor, length, 10, better)
   157  }
   158  
   159  // Tests that given a starting canonical chain of a given size, creating shorter
   160  // forks do not take canonical ownership.
   161  func TestShorterForkHeaders(t *testing.T) {
   162  	length := 10
   163  
   164  	// Make first chain starting from genesis
   165  	_, processor, err := newCanonical(length)
   166  	if err != nil {
   167  		t.Fatalf("failed to make new canonical chain: %v", err)
   168  	}
   169  	// Define the difficulty comparator
   170  	worse := func(td1, td2 *big.Int) {
   171  		if td2.Cmp(td1) >= 0 {
   172  			t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1)
   173  		}
   174  	}
   175  	// Sum of numbers must be less than `length` for this to be a shorter fork
   176  	testFork(t, processor, 0, 3, worse)
   177  	testFork(t, processor, 0, 7, worse)
   178  	testFork(t, processor, 1, 1, worse)
   179  	testFork(t, processor, 1, 7, worse)
   180  	testFork(t, processor, 5, 3, worse)
   181  	testFork(t, processor, 5, 4, worse)
   182  }
   183  
   184  // Tests that given a starting canonical chain of a given size, creating longer
   185  // forks do take canonical ownership.
   186  func TestLongerForkHeaders(t *testing.T) {
   187  	length := 10
   188  
   189  	// Make first chain starting from genesis
   190  	_, processor, err := newCanonical(length)
   191  	if err != nil {
   192  		t.Fatalf("failed to make new canonical chain: %v", err)
   193  	}
   194  	// Define the difficulty comparator
   195  	better := func(td1, td2 *big.Int) {
   196  		if td2.Cmp(td1) <= 0 {
   197  			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
   198  		}
   199  	}
   200  	// Sum of numbers must be greater than `length` for this to be a longer fork
   201  	testFork(t, processor, 0, 11, better)
   202  	testFork(t, processor, 0, 15, better)
   203  	testFork(t, processor, 1, 10, better)
   204  	testFork(t, processor, 1, 12, better)
   205  	testFork(t, processor, 5, 6, better)
   206  	testFork(t, processor, 5, 8, better)
   207  }
   208  
   209  // Tests that given a starting canonical chain of a given size, creating equal
   210  // forks do take canonical ownership.
   211  func TestEqualForkHeaders(t *testing.T) {
   212  	length := 10
   213  
   214  	// Make first chain starting from genesis
   215  	_, processor, err := newCanonical(length)
   216  	if err != nil {
   217  		t.Fatalf("failed to make new canonical chain: %v", err)
   218  	}
   219  	// Define the difficulty comparator
   220  	equal := func(td1, td2 *big.Int) {
   221  		if td2.Cmp(td1) != 0 {
   222  			t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1)
   223  		}
   224  	}
   225  	// Sum of numbers must be equal to `length` for this to be an equal fork
   226  	testFork(t, processor, 0, 10, equal)
   227  	testFork(t, processor, 1, 9, equal)
   228  	testFork(t, processor, 2, 8, equal)
   229  	testFork(t, processor, 5, 5, equal)
   230  	testFork(t, processor, 6, 4, equal)
   231  	testFork(t, processor, 9, 1, equal)
   232  }
   233  
   234  // Tests that chains missing links do not get accepted by the processor.
   235  func TestBrokenHeaderChain(t *testing.T) {
   236  	// Make chain starting from genesis
   237  	db, LightChain, err := newCanonical(10)
   238  	if err != nil {
   239  		t.Fatalf("failed to make new canonical chain: %v", err)
   240  	}
   241  	// Create a forked chain, and try to insert with a missing link
   242  	chain := makeHeaderChain(LightChain.CurrentHeader(), 5, db, forkSeed)[1:]
   243  	if err := testHeaderChainImport(chain, LightChain); err == nil {
   244  		t.Errorf("broken header chain not reported")
   245  	}
   246  }
   247  
   248  func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
   249  	var chain []*types.Header
   250  	for i, difficulty := range d {
   251  		header := &types.Header{
   252  			Coinbase:    common.Address{seed},
   253  			Number:      big.NewInt(int64(i + 1)),
   254  			Difficulty:  big.NewInt(int64(difficulty)),
   255  			UncleHash:   types.EmptyUncleHash,
   256  			TxHash:      types.EmptyRootHash,
   257  			ReceiptHash: types.EmptyRootHash,
   258  		}
   259  		if i == 0 {
   260  			header.ParentHash = genesis.Hash()
   261  		} else {
   262  			header.ParentHash = chain[i-1].Hash()
   263  		}
   264  		chain = append(chain, types.CopyHeader(header))
   265  	}
   266  	return chain
   267  }
   268  
   269  type dummyOdr struct {
   270  	OdrBackend
   271  	db            ethdb.Database
   272  	indexerConfig *IndexerConfig
   273  }
   274  
   275  func (odr *dummyOdr) Database() ethdb.Database {
   276  	return odr.db
   277  }
   278  
   279  func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
   280  	return nil
   281  }
   282  
   283  func (odr *dummyOdr) IndexerConfig() *IndexerConfig {
   284  	return odr.indexerConfig
   285  }
   286  
   287  // Tests that reorganizing a long difficult chain after a short easy one
   288  // overwrites the canonical numbers and links in the database.
   289  func TestReorgLongHeaders(t *testing.T) {
   290  	testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10)
   291  }
   292  
   293  // Tests that reorganizing a short difficult chain after a long easy one
   294  // overwrites the canonical numbers and links in the database.
   295  func TestReorgShortHeaders(t *testing.T) {
   296  	testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11)
   297  }
   298  
   299  func testReorg(t *testing.T, first, second []int, td int64) {
   300  	bc := newTestLightChain()
   301  
   302  	// Insert an easy and a difficult chain afterwards
   303  	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
   304  	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
   305  	// Check that the chain is valid number and link wise
   306  	prev := bc.CurrentHeader()
   307  	for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
   308  		if prev.ParentHash != header.Hash() {
   309  			t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash())
   310  		}
   311  	}
   312  	// Make sure the chain total difficulty is the correct one
   313  	want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
   314  	if have := bc.GetTd(bc.CurrentHeader().Hash(), bc.CurrentHeader().Number.Uint64()); have.Cmp(want) != 0 {
   315  		t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
   316  	}
   317  }
   318  
   319  // Tests that the insertion functions detect banned hashes.
   320  func TestBadHeaderHashes(t *testing.T) {
   321  	bc := newTestLightChain()
   322  
   323  	// Create a chain, ban a hash and try to import
   324  	var err error
   325  	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
   326  	core.BadHashes[headers[2].Hash()] = true
   327  	if _, err = bc.InsertHeaderChain(headers, 1); !errors.Is(err, core.ErrBannedHash) {
   328  		t.Errorf("error mismatch: have: %v, want %v", err, core.ErrBannedHash)
   329  	}
   330  }
   331  
   332  // Tests that bad hashes are detected on boot, and the chan rolled back to a
   333  // good state prior to the bad hash.
   334  func TestReorgBadHeaderHashes(t *testing.T) {
   335  	bc := newTestLightChain()
   336  
   337  	// Create a chain, import and ban afterwards
   338  	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
   339  
   340  	if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
   341  		t.Fatalf("failed to import headers: %v", err)
   342  	}
   343  	if bc.CurrentHeader().Hash() != headers[3].Hash() {
   344  		t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash())
   345  	}
   346  	core.BadHashes[headers[3].Hash()] = true
   347  	defer func() { delete(core.BadHashes, headers[3].Hash()) }()
   348  
   349  	// Create a new LightChain and check that it rolled back the state.
   350  	ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), nil)
   351  	if err != nil {
   352  		t.Fatalf("failed to create new chain manager: %v", err)
   353  	}
   354  	if ncm.CurrentHeader().Hash() != headers[2].Hash() {
   355  		t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash())
   356  	}
   357  }