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