github.com/ylsGit/go-ethereum@v1.6.5/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  	"fmt"
    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/types"
    29  	"github.com/ethereum/go-ethereum/ethdb"
    30  	"github.com/ethereum/go-ethereum/event"
    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), 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, _ := ethdb.NewMemDatabase()
    57  	gspec := core.Genesis{Config: params.TestChainConfig}
    58  	genesis := gspec.MustCommit(db)
    59  	blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, ethash.NewFaker(), new(event.TypeMux))
    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, _ := ethdb.NewMemDatabase()
    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(), new(event.TypeMux))
    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  	var (
   102  		headerChainB []*types.Header
   103  	)
   104  	headerChainB = makeHeaderChain(LightChain2.CurrentHeader(), n, db, forkSeed)
   105  	if _, err := LightChain2.InsertHeaderChain(headerChainB, 1); err != nil {
   106  		t.Fatalf("failed to insert forking chain: %v", err)
   107  	}
   108  	// Sanity check that the forked chain can be imported into the original
   109  	var tdPre, tdPost *big.Int
   110  
   111  	tdPre = LightChain.GetTdByHash(LightChain.CurrentHeader().Hash())
   112  	if err := testHeaderChainImport(headerChainB, LightChain); err != nil {
   113  		t.Fatalf("failed to import forked header chain: %v", err)
   114  	}
   115  	tdPost = LightChain.GetTdByHash(headerChainB[len(headerChainB)-1].Hash())
   116  	// Compare the total difficulties of the chains
   117  	comparator(tdPre, tdPost)
   118  }
   119  
   120  func printChain(bc *LightChain) {
   121  	for i := bc.CurrentHeader().Number.Uint64(); i > 0; i-- {
   122  		b := bc.GetHeaderByNumber(uint64(i))
   123  		fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty)
   124  	}
   125  }
   126  
   127  // testHeaderChainImport tries to process a chain of header, writing them into
   128  // the database if successful.
   129  func testHeaderChainImport(chain []*types.Header, lightchain *LightChain) error {
   130  	for _, header := range chain {
   131  		// Try and validate the header
   132  		if err := lightchain.engine.VerifyHeader(lightchain.hc, header, true); err != nil {
   133  			return err
   134  		}
   135  		// Manually insert the header into the database, but don't reorganize (allows subsequent testing)
   136  		lightchain.mu.Lock()
   137  		core.WriteTd(lightchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, lightchain.GetTdByHash(header.ParentHash)))
   138  		core.WriteHeader(lightchain.chainDb, header)
   139  		lightchain.mu.Unlock()
   140  	}
   141  	return nil
   142  }
   143  
   144  // Tests that given a starting canonical chain of a given size, it can be extended
   145  // with various length chains.
   146  func TestExtendCanonicalHeaders(t *testing.T) {
   147  	length := 5
   148  
   149  	// Make first chain starting from genesis
   150  	_, processor, err := newCanonical(length)
   151  	if err != nil {
   152  		t.Fatalf("failed to make new canonical chain: %v", err)
   153  	}
   154  	// Define the difficulty comparator
   155  	better := func(td1, td2 *big.Int) {
   156  		if td2.Cmp(td1) <= 0 {
   157  			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
   158  		}
   159  	}
   160  	// Start fork from current height
   161  	testFork(t, processor, length, 1, better)
   162  	testFork(t, processor, length, 2, better)
   163  	testFork(t, processor, length, 5, better)
   164  	testFork(t, processor, length, 10, better)
   165  }
   166  
   167  // Tests that given a starting canonical chain of a given size, creating shorter
   168  // forks do not take canonical ownership.
   169  func TestShorterForkHeaders(t *testing.T) {
   170  	length := 10
   171  
   172  	// Make first chain starting from genesis
   173  	_, processor, err := newCanonical(length)
   174  	if err != nil {
   175  		t.Fatalf("failed to make new canonical chain: %v", err)
   176  	}
   177  	// Define the difficulty comparator
   178  	worse := func(td1, td2 *big.Int) {
   179  		if td2.Cmp(td1) >= 0 {
   180  			t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1)
   181  		}
   182  	}
   183  	// Sum of numbers must be less than `length` for this to be a shorter fork
   184  	testFork(t, processor, 0, 3, worse)
   185  	testFork(t, processor, 0, 7, worse)
   186  	testFork(t, processor, 1, 1, worse)
   187  	testFork(t, processor, 1, 7, worse)
   188  	testFork(t, processor, 5, 3, worse)
   189  	testFork(t, processor, 5, 4, worse)
   190  }
   191  
   192  // Tests that given a starting canonical chain of a given size, creating longer
   193  // forks do take canonical ownership.
   194  func TestLongerForkHeaders(t *testing.T) {
   195  	length := 10
   196  
   197  	// Make first chain starting from genesis
   198  	_, processor, err := newCanonical(length)
   199  	if err != nil {
   200  		t.Fatalf("failed to make new canonical chain: %v", err)
   201  	}
   202  	// Define the difficulty comparator
   203  	better := func(td1, td2 *big.Int) {
   204  		if td2.Cmp(td1) <= 0 {
   205  			t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)
   206  		}
   207  	}
   208  	// Sum of numbers must be greater than `length` for this to be a longer fork
   209  	testFork(t, processor, 0, 11, better)
   210  	testFork(t, processor, 0, 15, better)
   211  	testFork(t, processor, 1, 10, better)
   212  	testFork(t, processor, 1, 12, better)
   213  	testFork(t, processor, 5, 6, better)
   214  	testFork(t, processor, 5, 8, better)
   215  }
   216  
   217  // Tests that given a starting canonical chain of a given size, creating equal
   218  // forks do take canonical ownership.
   219  func TestEqualForkHeaders(t *testing.T) {
   220  	length := 10
   221  
   222  	// Make first chain starting from genesis
   223  	_, processor, err := newCanonical(length)
   224  	if err != nil {
   225  		t.Fatalf("failed to make new canonical chain: %v", err)
   226  	}
   227  	// Define the difficulty comparator
   228  	equal := func(td1, td2 *big.Int) {
   229  		if td2.Cmp(td1) != 0 {
   230  			t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1)
   231  		}
   232  	}
   233  	// Sum of numbers must be equal to `length` for this to be an equal fork
   234  	testFork(t, processor, 0, 10, equal)
   235  	testFork(t, processor, 1, 9, equal)
   236  	testFork(t, processor, 2, 8, equal)
   237  	testFork(t, processor, 5, 5, equal)
   238  	testFork(t, processor, 6, 4, equal)
   239  	testFork(t, processor, 9, 1, equal)
   240  }
   241  
   242  // Tests that chains missing links do not get accepted by the processor.
   243  func TestBrokenHeaderChain(t *testing.T) {
   244  	// Make chain starting from genesis
   245  	db, LightChain, err := newCanonical(10)
   246  	if err != nil {
   247  		t.Fatalf("failed to make new canonical chain: %v", err)
   248  	}
   249  	// Create a forked chain, and try to insert with a missing link
   250  	chain := makeHeaderChain(LightChain.CurrentHeader(), 5, db, forkSeed)[1:]
   251  	if err := testHeaderChainImport(chain, LightChain); err == nil {
   252  		t.Errorf("broken header chain not reported")
   253  	}
   254  }
   255  
   256  func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {
   257  	var chain []*types.Header
   258  	for i, difficulty := range d {
   259  		header := &types.Header{
   260  			Coinbase:    common.Address{seed},
   261  			Number:      big.NewInt(int64(i + 1)),
   262  			Difficulty:  big.NewInt(int64(difficulty)),
   263  			UncleHash:   types.EmptyUncleHash,
   264  			TxHash:      types.EmptyRootHash,
   265  			ReceiptHash: types.EmptyRootHash,
   266  		}
   267  		if i == 0 {
   268  			header.ParentHash = genesis.Hash()
   269  		} else {
   270  			header.ParentHash = chain[i-1].Hash()
   271  		}
   272  		chain = append(chain, types.CopyHeader(header))
   273  	}
   274  	return chain
   275  }
   276  
   277  type dummyOdr struct {
   278  	OdrBackend
   279  	db ethdb.Database
   280  }
   281  
   282  func (odr *dummyOdr) Database() ethdb.Database {
   283  	return odr.db
   284  }
   285  
   286  func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
   287  	return nil
   288  }
   289  
   290  // Tests that reorganizing a long difficult chain after a short easy one
   291  // overwrites the canonical numbers and links in the database.
   292  func TestReorgLongHeaders(t *testing.T) {
   293  	testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10)
   294  }
   295  
   296  // Tests that reorganizing a short difficult chain after a long easy one
   297  // overwrites the canonical numbers and links in the database.
   298  func TestReorgShortHeaders(t *testing.T) {
   299  	testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11)
   300  }
   301  
   302  func testReorg(t *testing.T, first, second []int, td int64) {
   303  	bc := newTestLightChain()
   304  
   305  	// Insert an easy and a difficult chain afterwards
   306  	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
   307  	bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
   308  	// Check that the chain is valid number and link wise
   309  	prev := bc.CurrentHeader()
   310  	for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
   311  		if prev.ParentHash != header.Hash() {
   312  			t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash())
   313  		}
   314  	}
   315  	// Make sure the chain total difficulty is the correct one
   316  	want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
   317  	if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
   318  		t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
   319  	}
   320  }
   321  
   322  // Tests that the insertion functions detect banned hashes.
   323  func TestBadHeaderHashes(t *testing.T) {
   324  	bc := newTestLightChain()
   325  
   326  	// Create a chain, ban a hash and try to import
   327  	var err error
   328  	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
   329  	core.BadHashes[headers[2].Hash()] = true
   330  	if _, err = bc.InsertHeaderChain(headers, 1); err != core.ErrBlacklistedHash {
   331  		t.Errorf("error mismatch: have: %v, want %v", err, core.ErrBlacklistedHash)
   332  	}
   333  }
   334  
   335  // Tests that bad hashes are detected on boot, and the chan rolled back to a
   336  // good state prior to the bad hash.
   337  func TestReorgBadHeaderHashes(t *testing.T) {
   338  	bc := newTestLightChain()
   339  
   340  	// Create a chain, import and ban aferwards
   341  	headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
   342  
   343  	if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
   344  		t.Fatalf("failed to import headers: %v", err)
   345  	}
   346  	if bc.CurrentHeader().Hash() != headers[3].Hash() {
   347  		t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash())
   348  	}
   349  	core.BadHashes[headers[3].Hash()] = true
   350  	defer func() { delete(core.BadHashes, headers[3].Hash()) }()
   351  
   352  	// Create a new LightChain and check that it rolled back the state.
   353  	ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, params.TestChainConfig, ethash.NewFaker(), new(event.TypeMux))
   354  	if err != nil {
   355  		t.Fatalf("failed to create new chain manager: %v", err)
   356  	}
   357  	if ncm.CurrentHeader().Hash() != headers[2].Hash() {
   358  		t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash())
   359  	}
   360  }