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