github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/chain_manager_test.go (about)

     1  // Copyright 2014 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 core
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"math/rand"
    23  	"os"
    24  	"path/filepath"
    25  	"runtime"
    26  	"strconv"
    27  	"testing"
    28  
    29  	"github.com/ethereum/ethash"
    30  	"github.com/ethereum/go-ethereum/common"
    31  	"github.com/ethereum/go-ethereum/core/state"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/ethdb"
    34  	"github.com/ethereum/go-ethereum/event"
    35  	"github.com/ethereum/go-ethereum/pow"
    36  	"github.com/ethereum/go-ethereum/rlp"
    37  	"github.com/hashicorp/golang-lru"
    38  )
    39  
    40  func init() {
    41  	runtime.GOMAXPROCS(runtime.NumCPU())
    42  }
    43  
    44  func thePow() pow.PoW {
    45  	pow, _ := ethash.NewForTesting()
    46  	return pow
    47  }
    48  
    49  func theChainManager(db common.Database, t *testing.T) *ChainManager {
    50  	var eventMux event.TypeMux
    51  	WriteTestNetGenesisBlock(db, 0)
    52  	chainMan, err := NewChainManager(db, thePow(), &eventMux)
    53  	if err != nil {
    54  		t.Error("failed creating chainmanager:", err)
    55  		t.FailNow()
    56  		return nil
    57  	}
    58  	blockMan := NewBlockProcessor(db, nil, chainMan, &eventMux)
    59  	chainMan.SetProcessor(blockMan)
    60  
    61  	return chainMan
    62  }
    63  
    64  // Test fork of length N starting from block i
    65  func testFork(t *testing.T, bman *BlockProcessor, i, N int, f func(td1, td2 *big.Int)) {
    66  	// switch databases to process the new chain
    67  	db, err := ethdb.NewMemDatabase()
    68  	if err != nil {
    69  		t.Fatal("Failed to create db:", err)
    70  	}
    71  	// copy old chain up to i into new db with deterministic canonical
    72  	bman2, err := newCanonical(i, db)
    73  	if err != nil {
    74  		t.Fatal("could not make new canonical in testFork", err)
    75  	}
    76  	// asert the bmans have the same block at i
    77  	bi1 := bman.bc.GetBlockByNumber(uint64(i)).Hash()
    78  	bi2 := bman2.bc.GetBlockByNumber(uint64(i)).Hash()
    79  	if bi1 != bi2 {
    80  		t.Fatal("chains do not have the same hash at height", i)
    81  	}
    82  	bman2.bc.SetProcessor(bman2)
    83  
    84  	// extend the fork
    85  	parent := bman2.bc.CurrentBlock()
    86  	chainB := makeChain(parent, N, db, forkSeed)
    87  	_, err = bman2.bc.InsertChain(chainB)
    88  	if err != nil {
    89  		t.Fatal("Insert chain error for fork:", err)
    90  	}
    91  
    92  	tdpre := bman.bc.Td()
    93  	// Test the fork's blocks on the original chain
    94  	td, err := testChain(chainB, bman)
    95  	if err != nil {
    96  		t.Fatal("expected chainB not to give errors:", err)
    97  	}
    98  	// Compare difficulties
    99  	f(tdpre, td)
   100  
   101  	// Loop over parents making sure reconstruction is done properly
   102  }
   103  
   104  func printChain(bc *ChainManager) {
   105  	for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- {
   106  		b := bc.GetBlockByNumber(uint64(i))
   107  		fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty())
   108  	}
   109  }
   110  
   111  // process blocks against a chain
   112  func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
   113  	td := new(big.Int)
   114  	for _, block := range chainB {
   115  		_, _, err := bman.bc.processor.Process(block)
   116  		if err != nil {
   117  			if IsKnownBlockErr(err) {
   118  				continue
   119  			}
   120  			return nil, err
   121  		}
   122  		parent := bman.bc.GetBlock(block.ParentHash())
   123  		block.Td = CalcTD(block, parent)
   124  		td = block.Td
   125  
   126  		bman.bc.mu.Lock()
   127  		{
   128  			WriteBlock(bman.bc.chainDb, block)
   129  		}
   130  		bman.bc.mu.Unlock()
   131  	}
   132  	return td, nil
   133  }
   134  
   135  func loadChain(fn string, t *testing.T) (types.Blocks, error) {
   136  	fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	defer fh.Close()
   141  
   142  	var chain types.Blocks
   143  	if err := rlp.Decode(fh, &chain); err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	return chain, nil
   148  }
   149  
   150  func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
   151  	_, err := chainMan.InsertChain(chain)
   152  	if err != nil {
   153  		fmt.Println(err)
   154  		t.FailNow()
   155  	}
   156  	done <- true
   157  }
   158  
   159  func TestExtendCanonical(t *testing.T) {
   160  	CanonicalLength := 5
   161  	db, err := ethdb.NewMemDatabase()
   162  	if err != nil {
   163  		t.Fatal("Failed to create db:", err)
   164  	}
   165  	// make first chain starting from genesis
   166  	bman, err := newCanonical(CanonicalLength, db)
   167  	if err != nil {
   168  		t.Fatal("Could not make new canonical chain:", err)
   169  	}
   170  	f := func(td1, td2 *big.Int) {
   171  		if td2.Cmp(td1) <= 0 {
   172  			t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
   173  		}
   174  	}
   175  	// Start fork from current height (CanonicalLength)
   176  	testFork(t, bman, CanonicalLength, 1, f)
   177  	testFork(t, bman, CanonicalLength, 2, f)
   178  	testFork(t, bman, CanonicalLength, 5, f)
   179  	testFork(t, bman, CanonicalLength, 10, f)
   180  }
   181  
   182  func TestShorterFork(t *testing.T) {
   183  	db, err := ethdb.NewMemDatabase()
   184  	if err != nil {
   185  		t.Fatal("Failed to create db:", err)
   186  	}
   187  	// make first chain starting from genesis
   188  	bman, err := newCanonical(10, db)
   189  	if err != nil {
   190  		t.Fatal("Could not make new canonical chain:", err)
   191  	}
   192  	f := func(td1, td2 *big.Int) {
   193  		if td2.Cmp(td1) >= 0 {
   194  			t.Error("expected chainB to have lower difficulty. Got", td2, "expected less than", td1)
   195  		}
   196  	}
   197  	// Sum of numbers must be less than 10
   198  	// for this to be a shorter fork
   199  	testFork(t, bman, 0, 3, f)
   200  	testFork(t, bman, 0, 7, f)
   201  	testFork(t, bman, 1, 1, f)
   202  	testFork(t, bman, 1, 7, f)
   203  	testFork(t, bman, 5, 3, f)
   204  	testFork(t, bman, 5, 4, f)
   205  }
   206  
   207  func TestLongerFork(t *testing.T) {
   208  	db, err := ethdb.NewMemDatabase()
   209  	if err != nil {
   210  		t.Fatal("Failed to create db:", err)
   211  	}
   212  	// make first chain starting from genesis
   213  	bman, err := newCanonical(10, db)
   214  	if err != nil {
   215  		t.Fatal("Could not make new canonical chain:", err)
   216  	}
   217  	f := func(td1, td2 *big.Int) {
   218  		if td2.Cmp(td1) <= 0 {
   219  			t.Error("expected chainB to have higher difficulty. Got", td2, "expected more than", td1)
   220  		}
   221  	}
   222  	// Sum of numbers must be greater than 10
   223  	// for this to be a longer fork
   224  	testFork(t, bman, 0, 11, f)
   225  	testFork(t, bman, 0, 15, f)
   226  	testFork(t, bman, 1, 10, f)
   227  	testFork(t, bman, 1, 12, f)
   228  	testFork(t, bman, 5, 6, f)
   229  	testFork(t, bman, 5, 8, f)
   230  }
   231  
   232  func TestEqualFork(t *testing.T) {
   233  	db, err := ethdb.NewMemDatabase()
   234  	if err != nil {
   235  		t.Fatal("Failed to create db:", err)
   236  	}
   237  	bman, err := newCanonical(10, db)
   238  	if err != nil {
   239  		t.Fatal("Could not make new canonical chain:", err)
   240  	}
   241  	f := func(td1, td2 *big.Int) {
   242  		if td2.Cmp(td1) != 0 {
   243  			t.Error("expected chainB to have equal difficulty. Got", td2, "expected ", td1)
   244  		}
   245  	}
   246  	// Sum of numbers must be equal to 10
   247  	// for this to be an equal fork
   248  	testFork(t, bman, 0, 10, f)
   249  	testFork(t, bman, 1, 9, f)
   250  	testFork(t, bman, 2, 8, f)
   251  	testFork(t, bman, 5, 5, f)
   252  	testFork(t, bman, 6, 4, f)
   253  	testFork(t, bman, 9, 1, f)
   254  }
   255  
   256  func TestBrokenChain(t *testing.T) {
   257  	db, err := ethdb.NewMemDatabase()
   258  	if err != nil {
   259  		t.Fatal("Failed to create db:", err)
   260  	}
   261  	bman, err := newCanonical(10, db)
   262  	if err != nil {
   263  		t.Fatal("Could not make new canonical chain:", err)
   264  	}
   265  	db2, err := ethdb.NewMemDatabase()
   266  	if err != nil {
   267  		t.Fatal("Failed to create db:", err)
   268  	}
   269  	bman2, err := newCanonical(10, db2)
   270  	if err != nil {
   271  		t.Fatal("Could not make new canonical chain:", err)
   272  	}
   273  	bman2.bc.SetProcessor(bman2)
   274  	parent := bman2.bc.CurrentBlock()
   275  	chainB := makeChain(parent, 5, db2, forkSeed)
   276  	chainB = chainB[1:]
   277  	_, err = testChain(chainB, bman)
   278  	if err == nil {
   279  		t.Error("expected broken chain to return error")
   280  	}
   281  }
   282  
   283  func TestChainInsertions(t *testing.T) {
   284  	t.Skip("Skipped: outdated test files")
   285  
   286  	db, _ := ethdb.NewMemDatabase()
   287  
   288  	chain1, err := loadChain("valid1", t)
   289  	if err != nil {
   290  		fmt.Println(err)
   291  		t.FailNow()
   292  	}
   293  
   294  	chain2, err := loadChain("valid2", t)
   295  	if err != nil {
   296  		fmt.Println(err)
   297  		t.FailNow()
   298  	}
   299  
   300  	chainMan := theChainManager(db, t)
   301  
   302  	const max = 2
   303  	done := make(chan bool, max)
   304  
   305  	go insertChain(done, chainMan, chain1, t)
   306  	go insertChain(done, chainMan, chain2, t)
   307  
   308  	for i := 0; i < max; i++ {
   309  		<-done
   310  	}
   311  
   312  	if chain2[len(chain2)-1].Hash() != chainMan.CurrentBlock().Hash() {
   313  		t.Error("chain2 is canonical and shouldn't be")
   314  	}
   315  
   316  	if chain1[len(chain1)-1].Hash() != chainMan.CurrentBlock().Hash() {
   317  		t.Error("chain1 isn't canonical and should be")
   318  	}
   319  }
   320  
   321  func TestChainMultipleInsertions(t *testing.T) {
   322  	t.Skip("Skipped: outdated test files")
   323  
   324  	db, _ := ethdb.NewMemDatabase()
   325  
   326  	const max = 4
   327  	chains := make([]types.Blocks, max)
   328  	var longest int
   329  	for i := 0; i < max; i++ {
   330  		var err error
   331  		name := "valid" + strconv.Itoa(i+1)
   332  		chains[i], err = loadChain(name, t)
   333  		if len(chains[i]) >= len(chains[longest]) {
   334  			longest = i
   335  		}
   336  		fmt.Println("loaded", name, "with a length of", len(chains[i]))
   337  		if err != nil {
   338  			fmt.Println(err)
   339  			t.FailNow()
   340  		}
   341  	}
   342  
   343  	chainMan := theChainManager(db, t)
   344  
   345  	done := make(chan bool, max)
   346  	for i, chain := range chains {
   347  		// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
   348  		i := i
   349  		chain := chain
   350  		go func() {
   351  			insertChain(done, chainMan, chain, t)
   352  			fmt.Println(i, "done")
   353  		}()
   354  	}
   355  
   356  	for i := 0; i < max; i++ {
   357  		<-done
   358  	}
   359  
   360  	if chains[longest][len(chains[longest])-1].Hash() != chainMan.CurrentBlock().Hash() {
   361  		t.Error("Invalid canonical chain")
   362  	}
   363  }
   364  
   365  type bproc struct{}
   366  
   367  func (bproc) Process(*types.Block) (state.Logs, types.Receipts, error) { return nil, nil, nil }
   368  
   369  func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {
   370  	var chain []*types.Block
   371  	for i, difficulty := range d {
   372  		header := &types.Header{
   373  			Coinbase:   common.Address{seed},
   374  			Number:     big.NewInt(int64(i + 1)),
   375  			Difficulty: big.NewInt(int64(difficulty)),
   376  		}
   377  		if i == 0 {
   378  			header.ParentHash = genesis.Hash()
   379  		} else {
   380  			header.ParentHash = chain[i-1].Hash()
   381  		}
   382  		block := types.NewBlockWithHeader(header)
   383  		chain = append(chain, block)
   384  	}
   385  	return chain
   386  }
   387  
   388  func chm(genesis *types.Block, db common.Database) *ChainManager {
   389  	var eventMux event.TypeMux
   390  	bc := &ChainManager{chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
   391  	bc.cache, _ = lru.New(100)
   392  	bc.futureBlocks, _ = lru.New(100)
   393  	bc.processor = bproc{}
   394  	bc.ResetWithGenesisBlock(genesis)
   395  
   396  	return bc
   397  }
   398  
   399  func TestReorgLongest(t *testing.T) {
   400  	db, _ := ethdb.NewMemDatabase()
   401  
   402  	genesis, err := WriteTestNetGenesisBlock(db, 0)
   403  	if err != nil {
   404  		t.Error(err)
   405  		t.FailNow()
   406  	}
   407  	bc := chm(genesis, db)
   408  
   409  	chain1 := makeChainWithDiff(genesis, []int{1, 2, 4}, 10)
   410  	chain2 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 11)
   411  
   412  	bc.InsertChain(chain1)
   413  	bc.InsertChain(chain2)
   414  
   415  	prev := bc.CurrentBlock()
   416  	for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) {
   417  		if prev.ParentHash() != block.Hash() {
   418  			t.Errorf("parent hash mismatch %x - %x", prev.ParentHash(), block.Hash())
   419  		}
   420  	}
   421  }
   422  
   423  func TestReorgShortest(t *testing.T) {
   424  	db, _ := ethdb.NewMemDatabase()
   425  	genesis, err := WriteTestNetGenesisBlock(db, 0)
   426  	if err != nil {
   427  		t.Error(err)
   428  		t.FailNow()
   429  	}
   430  	bc := chm(genesis, db)
   431  
   432  	chain1 := makeChainWithDiff(genesis, []int{1, 2, 3, 4}, 10)
   433  	chain2 := makeChainWithDiff(genesis, []int{1, 10}, 11)
   434  
   435  	bc.InsertChain(chain1)
   436  	bc.InsertChain(chain2)
   437  
   438  	prev := bc.CurrentBlock()
   439  	for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) {
   440  		if prev.ParentHash() != block.Hash() {
   441  			t.Errorf("parent hash mismatch %x - %x", prev.ParentHash(), block.Hash())
   442  		}
   443  	}
   444  }
   445  
   446  func TestInsertNonceError(t *testing.T) {
   447  	for i := 1; i < 25 && !t.Failed(); i++ {
   448  		db, _ := ethdb.NewMemDatabase()
   449  		genesis, err := WriteTestNetGenesisBlock(db, 0)
   450  		if err != nil {
   451  			t.Error(err)
   452  			t.FailNow()
   453  		}
   454  		bc := chm(genesis, db)
   455  		bc.processor = NewBlockProcessor(db, bc.pow, bc, bc.eventMux)
   456  		blocks := makeChain(bc.currentBlock, i, db, 0)
   457  
   458  		fail := rand.Int() % len(blocks)
   459  		failblock := blocks[fail]
   460  		bc.pow = failpow{failblock.NumberU64()}
   461  		n, err := bc.InsertChain(blocks)
   462  
   463  		// Check that the returned error indicates the nonce failure.
   464  		if n != fail {
   465  			t.Errorf("(i=%d) wrong failed block index: got %d, want %d", i, n, fail)
   466  		}
   467  		if !IsBlockNonceErr(err) {
   468  			t.Fatalf("(i=%d) got %q, want a nonce error", i, err)
   469  		}
   470  		nerr := err.(*BlockNonceErr)
   471  		if nerr.Number.Cmp(failblock.Number()) != 0 {
   472  			t.Errorf("(i=%d) wrong block number in error, got %v, want %v", i, nerr.Number, failblock.Number())
   473  		}
   474  		if nerr.Hash != failblock.Hash() {
   475  			t.Errorf("(i=%d) wrong block hash in error, got %v, want %v", i, nerr.Hash, failblock.Hash())
   476  		}
   477  
   478  		// Check that all no blocks after the failing block have been inserted.
   479  		for _, block := range blocks[fail:] {
   480  			if bc.HasBlock(block.Hash()) {
   481  				t.Errorf("(i=%d) invalid block %d present in chain", i, block.NumberU64())
   482  			}
   483  		}
   484  	}
   485  }
   486  
   487  /*
   488  func TestGenesisMismatch(t *testing.T) {
   489  	db, _ := ethdb.NewMemDatabase()
   490  	var mux event.TypeMux
   491  	genesis := GenesisBlock(0, db)
   492  	_, err := NewChainManager(genesis, db, db, db, thePow(), &mux)
   493  	if err != nil {
   494  		t.Error(err)
   495  	}
   496  	genesis = GenesisBlock(1, db)
   497  	_, err = NewChainManager(genesis, db, db, db, thePow(), &mux)
   498  	if err == nil {
   499  		t.Error("expected genesis mismatch error")
   500  	}
   501  }
   502  */
   503  
   504  // failpow returns false from Verify for a certain block number.
   505  type failpow struct{ num uint64 }
   506  
   507  func (pow failpow) Search(pow.Block, <-chan struct{}) (nonce uint64, mixHash []byte) {
   508  	return 0, nil
   509  }
   510  func (pow failpow) Verify(b pow.Block) bool {
   511  	return b.NumberU64() != pow.num
   512  }
   513  func (pow failpow) GetHashrate() int64 {
   514  	return 0
   515  }
   516  func (pow failpow) Turbo(bool) {
   517  }