github.com/ebakus/go-ebakus@v1.0.5-0.20200520105415-dbccef9ec421/light/lightchain_test.go (about)

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