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