github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/eth/fetcher/fetcher_test.go (about)

     1  // Copyright 2015 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 fetcher
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"errors"
    22  	"math/big"
    23  	"sync"
    24  	"sync/atomic"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/wanchain/go-wanchain/common"
    29  	"github.com/wanchain/go-wanchain/consensus"
    30  	"github.com/wanchain/go-wanchain/consensus/ethash"
    31  	"github.com/wanchain/go-wanchain/core"
    32  	"github.com/wanchain/go-wanchain/core/types"
    33  	"github.com/wanchain/go-wanchain/core/vm"
    34  	"github.com/wanchain/go-wanchain/crypto"
    35  	"github.com/wanchain/go-wanchain/ethdb"
    36  	"github.com/wanchain/go-wanchain/params"
    37  )
    38  
    39  var (
    40  	testKey, _     = crypto.HexToECDSA("f1572f76b75b40a7da72d6f2ee7fda3d1189c2d28f0a2f096347055abe344d7f")
    41  	coinbaseKey, _ = crypto.HexToECDSA("900d0981bde924f82b7e8ccec52e2b07c2b0835cc22143d87f7dae2b733b3e57")
    42  	testAddress    = crypto.PubkeyToAddress(testKey.PublicKey)
    43  	coinbase       = crypto.PubkeyToAddress(coinbaseKey.PublicKey)
    44  
    45  	testdb, _    = ethdb.NewMemDatabase()
    46  	gspec        = core.DefaultPPOWTestingGenesisBlock()
    47  	genesis      = gspec.MustCommit(testdb)
    48  	engine       = ethash.NewFaker(testdb)
    49  	unknownBlock = types.NewBlock(&types.Header{GasLimit: params.GenesisGasLimit}, nil, nil, nil)
    50  )
    51  
    52  // makeChain creates a chain of n blocks starting at and including parent.
    53  // the returned hash chain is ordered head->parent. In addition, every 3rd block
    54  // contains a transaction and every 5th an uncle to allow testing correct block
    55  // reassembly.
    56  func makeChain(n int, seed common.Address, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
    57  	chain, _ := core.NewBlockChain(testdb, params.TestChainConfig, engine, vm.Config{})
    58  	defer chain.Stop()
    59  	env := core.NewChainEnv(params.TestChainConfig, gspec, engine, chain, testdb)
    60  
    61  	blocks, _ := env.GenerateChain(parent, n, func(i int, block *core.BlockGen) {
    62  		block.SetCoinbase(seed)
    63  
    64  		// If the block number is multiple of 3, send a bonus transaction to the miner
    65  		if parent == genesis && i%3 == 0 {
    66  			signer := types.MakeSigner(params.TestChainConfig, block.Number())
    67  			tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), seed, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
    68  			if err != nil {
    69  				panic(err)
    70  			}
    71  			block.AddTx(tx)
    72  		}
    73  
    74  	})
    75  
    76  	hashes := make([]common.Hash, n+1)
    77  	hashes[len(hashes)-1] = parent.Hash()
    78  	blockm := make(map[common.Hash]*types.Block, n+1)
    79  	blockm[parent.Hash()] = parent
    80  	for i, b := range blocks {
    81  		hashes[len(hashes)-i-2] = b.Hash()
    82  		blockm[b.Hash()] = b
    83  	}
    84  	return hashes, blockm
    85  }
    86  
    87  // fetcherTester is a test simulator for mocking out local block chain.
    88  type fetcherTester struct {
    89  	fetcher *Fetcher
    90  
    91  	hashes []common.Hash                // Hash chain belonging to the tester
    92  	blocks map[common.Hash]*types.Block // Blocks belonging to the tester
    93  	drops  map[string]bool              // Map of peers dropped by the fetcher
    94  
    95  	lock sync.RWMutex
    96  }
    97  
    98  // newTester creates a new fetcher test mocker.
    99  func newTester() *fetcherTester {
   100  	tester := &fetcherTester{
   101  		hashes: []common.Hash{genesis.Hash()},
   102  		blocks: map[common.Hash]*types.Block{genesis.Hash(): genesis},
   103  		drops:  make(map[string]bool),
   104  	}
   105  	tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer)
   106  	tester.fetcher.Start()
   107  
   108  	return tester
   109  }
   110  
   111  // getBlock retrieves a block from the tester's block chain.
   112  func (f *fetcherTester) getBlock(hash common.Hash) *types.Block {
   113  	f.lock.RLock()
   114  	defer f.lock.RUnlock()
   115  
   116  	return f.blocks[hash]
   117  }
   118  
   119  // verifyHeader is a nop placeholder for the block header verification.
   120  func (f *fetcherTester) verifyHeader(header *types.Header) error {
   121  	return nil
   122  }
   123  
   124  // broadcastBlock is a nop placeholder for the block broadcasting.
   125  func (f *fetcherTester) broadcastBlock(block *types.Block, propagate bool) {
   126  }
   127  
   128  // chainHeight retrieves the current height (block number) of the chain.
   129  func (f *fetcherTester) chainHeight() uint64 {
   130  	f.lock.RLock()
   131  	defer f.lock.RUnlock()
   132  
   133  	return f.blocks[f.hashes[len(f.hashes)-1]].NumberU64()
   134  }
   135  
   136  // insertChain injects a new blocks into the simulated chain.
   137  func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) {
   138  	f.lock.Lock()
   139  	defer f.lock.Unlock()
   140  
   141  	for i, block := range blocks {
   142  		// Make sure the parent in known
   143  		if _, ok := f.blocks[block.ParentHash()]; !ok {
   144  			return i, errors.New("unknown parent")
   145  		}
   146  		// Discard any new blocks if the same height already exists
   147  		if block.NumberU64() <= f.blocks[f.hashes[len(f.hashes)-1]].NumberU64() {
   148  			return i, nil
   149  		}
   150  		// Otherwise build our current chain
   151  		f.hashes = append(f.hashes, block.Hash())
   152  		f.blocks[block.Hash()] = block
   153  	}
   154  	return 0, nil
   155  }
   156  
   157  // dropPeer is an emulator for the peer removal, simply accumulating the various
   158  // peers dropped by the fetcher.
   159  func (f *fetcherTester) dropPeer(peer string) {
   160  	f.lock.Lock()
   161  	defer f.lock.Unlock()
   162  
   163  	f.drops[peer] = true
   164  }
   165  
   166  // makeHeaderFetcher retrieves a block header fetcher associated with a simulated peer.
   167  func (f *fetcherTester) makeHeaderFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) headerRequesterFn {
   168  	closure := make(map[common.Hash]*types.Block)
   169  	for hash, block := range blocks {
   170  		closure[hash] = block
   171  	}
   172  	// Create a function that return a header from the closure
   173  	return func(hash common.Hash) error {
   174  		// Gather the blocks to return
   175  		headers := make([]*types.Header, 0, 1)
   176  		if block, ok := closure[hash]; ok {
   177  			headers = append(headers, block.Header())
   178  		}
   179  		// Return on a new thread
   180  		go f.fetcher.FilterHeaders(peer, headers, time.Now().Add(drift))
   181  
   182  		return nil
   183  	}
   184  }
   185  
   186  // makeBodyFetcher retrieves a block body fetcher associated with a simulated peer.
   187  func (f *fetcherTester) makeBodyFetcher(peer string, blocks map[common.Hash]*types.Block, drift time.Duration) bodyRequesterFn {
   188  	closure := make(map[common.Hash]*types.Block)
   189  	for hash, block := range blocks {
   190  		closure[hash] = block
   191  	}
   192  	// Create a function that returns blocks from the closure
   193  	return func(hashes []common.Hash) error {
   194  		// Gather the block bodies to return
   195  		transactions := make([][]*types.Transaction, 0, len(hashes))
   196  		uncles := make([][]*types.Header, 0, len(hashes))
   197  
   198  		for _, hash := range hashes {
   199  			if block, ok := closure[hash]; ok {
   200  				transactions = append(transactions, block.Transactions())
   201  				uncles = append(uncles, block.Uncles())
   202  			}
   203  		}
   204  		// Return on a new thread
   205  		go f.fetcher.FilterBodies(peer, transactions, uncles, time.Now().Add(drift))
   206  
   207  		return nil
   208  	}
   209  }
   210  
   211  // verifyFetchingEvent verifies that one single event arrive on an fetching channel.
   212  func verifyFetchingEvent(t *testing.T, fetching chan []common.Hash, arrive bool) {
   213  	if arrive {
   214  		select {
   215  		case <-fetching:
   216  		case <-time.After(time.Second):
   217  			t.Fatalf("fetching timeout")
   218  		}
   219  	} else {
   220  		select {
   221  		case <-fetching:
   222  			t.Fatalf("fetching invoked")
   223  		case <-time.After(10 * time.Millisecond):
   224  		}
   225  	}
   226  }
   227  
   228  // verifyCompletingEvent verifies that one single event arrive on an completing channel.
   229  func verifyCompletingEvent(t *testing.T, completing chan []common.Hash, arrive bool) {
   230  	if arrive {
   231  		select {
   232  		case <-completing:
   233  		case <-time.After(time.Second):
   234  			t.Fatalf("completing timeout")
   235  		}
   236  	} else {
   237  		select {
   238  		case <-completing:
   239  			t.Fatalf("completing invoked")
   240  		case <-time.After(10 * time.Millisecond):
   241  		}
   242  	}
   243  }
   244  
   245  // verifyImportEvent verifies that one single event arrive on an import channel.
   246  func verifyImportEvent(t *testing.T, imported chan *types.Block, arrive bool) {
   247  	if arrive {
   248  		select {
   249  		case <-imported:
   250  		case <-time.After(time.Second):
   251  			t.Fatalf("import timeout")
   252  		}
   253  	} else {
   254  		select {
   255  		case <-imported:
   256  			t.Fatalf("import invoked")
   257  		case <-time.After(10 * time.Millisecond):
   258  		}
   259  	}
   260  }
   261  
   262  // verifyImportCount verifies that exactly count number of events arrive on an
   263  // import hook channel.
   264  func verifyImportCount(t *testing.T, imported chan *types.Block, count int) {
   265  	for i := 0; i < count; i++ {
   266  		select {
   267  		case <-imported:
   268  		case <-time.After(time.Second):
   269  			t.Fatalf("block %d: import timeout", i+1)
   270  		}
   271  	}
   272  	verifyImportDone(t, imported)
   273  }
   274  
   275  // verifyImportDone verifies that no more events are arriving on an import channel.
   276  func verifyImportDone(t *testing.T, imported chan *types.Block) {
   277  	select {
   278  	case <-imported:
   279  		t.Fatalf("extra block imported")
   280  	case <-time.After(50 * time.Millisecond):
   281  	}
   282  }
   283  
   284  // Tests that a fetcher accepts block announcements and initiates retrievals for
   285  // them, successfully importing into the local chain.
   286  func TestSequentialAnnouncements62(t *testing.T) { testSequentialAnnouncements(t, 62) }
   287  func TestSequentialAnnouncements63(t *testing.T) { testSequentialAnnouncements(t, 63) }
   288  func TestSequentialAnnouncements64(t *testing.T) { testSequentialAnnouncements(t, 64) }
   289  
   290  func testSequentialAnnouncements(t *testing.T, protocol int) {
   291  	// Create a chain of blocks to import
   292  	targetBlocks := 4 * hashLimit
   293  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   294  
   295  	tester := newTester()
   296  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   297  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   298  
   299  	// Iteratively announce blocks until all are imported
   300  	imported := make(chan *types.Block)
   301  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   302  
   303  	for i := len(hashes) - 2; i >= 0; i-- {
   304  		tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   305  		verifyImportEvent(t, imported, true)
   306  	}
   307  	verifyImportDone(t, imported)
   308  }
   309  
   310  // Tests that if blocks are announced by multiple peers (or even the same buggy
   311  // peer), they will only get downloaded at most once.
   312  func TestConcurrentAnnouncements62(t *testing.T) { testConcurrentAnnouncements(t, 62) }
   313  func TestConcurrentAnnouncements63(t *testing.T) { testConcurrentAnnouncements(t, 63) }
   314  func TestConcurrentAnnouncements64(t *testing.T) { testConcurrentAnnouncements(t, 64) }
   315  
   316  func testConcurrentAnnouncements(t *testing.T, protocol int) {
   317  	// Create a chain of blocks to import
   318  	targetBlocks := 4 * hashLimit
   319  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   320  
   321  	// Assemble a tester with a built in counter for the requests
   322  	tester := newTester()
   323  	firstHeaderFetcher := tester.makeHeaderFetcher("first", blocks, -gatherSlack)
   324  	firstBodyFetcher := tester.makeBodyFetcher("first", blocks, 0)
   325  	secondHeaderFetcher := tester.makeHeaderFetcher("second", blocks, -gatherSlack)
   326  	secondBodyFetcher := tester.makeBodyFetcher("second", blocks, 0)
   327  
   328  	counter := uint32(0)
   329  	firstHeaderWrapper := func(hash common.Hash) error {
   330  		atomic.AddUint32(&counter, 1)
   331  		return firstHeaderFetcher(hash)
   332  	}
   333  	secondHeaderWrapper := func(hash common.Hash) error {
   334  		atomic.AddUint32(&counter, 1)
   335  		return secondHeaderFetcher(hash)
   336  	}
   337  	// Iteratively announce blocks until all are imported
   338  	imported := make(chan *types.Block)
   339  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   340  
   341  	for i := len(hashes) - 2; i >= 0; i-- {
   342  		tester.fetcher.Notify("first", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), firstHeaderWrapper, firstBodyFetcher)
   343  		tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout+time.Millisecond), secondHeaderWrapper, secondBodyFetcher)
   344  		tester.fetcher.Notify("second", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout-time.Millisecond), secondHeaderWrapper, secondBodyFetcher)
   345  		verifyImportEvent(t, imported, true)
   346  	}
   347  	verifyImportDone(t, imported)
   348  
   349  	// Make sure no blocks were retrieved twice
   350  	if int(counter) != targetBlocks {
   351  		t.Fatalf("retrieval count mismatch: have %v, want %v", counter, targetBlocks)
   352  	}
   353  }
   354  
   355  // Tests that announcements arriving while a previous is being fetched still
   356  // results in a valid import.
   357  func TestOverlappingAnnouncements62(t *testing.T) { testOverlappingAnnouncements(t, 62) }
   358  func TestOverlappingAnnouncements63(t *testing.T) { testOverlappingAnnouncements(t, 63) }
   359  func TestOverlappingAnnouncements64(t *testing.T) { testOverlappingAnnouncements(t, 64) }
   360  
   361  func testOverlappingAnnouncements(t *testing.T, protocol int) {
   362  	// Create a chain of blocks to import
   363  	targetBlocks := 4 * hashLimit
   364  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   365  
   366  	tester := newTester()
   367  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   368  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   369  
   370  	// Iteratively announce blocks, but overlap them continuously
   371  	overlap := 16
   372  	imported := make(chan *types.Block, len(hashes)-1)
   373  	for i := 0; i < overlap; i++ {
   374  		imported <- nil
   375  	}
   376  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   377  
   378  	for i := len(hashes) - 2; i >= 0; i-- {
   379  		tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   380  		select {
   381  		case <-imported:
   382  		case <-time.After(time.Second):
   383  			t.Fatalf("block %d: import timeout", len(hashes)-i)
   384  		}
   385  	}
   386  	// Wait for all the imports to complete and check count
   387  	verifyImportCount(t, imported, overlap)
   388  }
   389  
   390  // Tests that announces already being retrieved will not be duplicated.
   391  func TestPendingDeduplication62(t *testing.T) { testPendingDeduplication(t, 62) }
   392  func TestPendingDeduplication63(t *testing.T) { testPendingDeduplication(t, 63) }
   393  func TestPendingDeduplication64(t *testing.T) { testPendingDeduplication(t, 64) }
   394  
   395  func testPendingDeduplication(t *testing.T, protocol int) {
   396  	// Create a hash and corresponding block
   397  	hashes, blocks := makeChain(1, testAddress, genesis)
   398  
   399  	// Assemble a tester with a built in counter and delayed fetcher
   400  	tester := newTester()
   401  	headerFetcher := tester.makeHeaderFetcher("repeater", blocks, -gatherSlack)
   402  	bodyFetcher := tester.makeBodyFetcher("repeater", blocks, 0)
   403  
   404  	delay := 50 * time.Millisecond
   405  	counter := uint32(0)
   406  	headerWrapper := func(hash common.Hash) error {
   407  		atomic.AddUint32(&counter, 1)
   408  
   409  		// Simulate a long running fetch
   410  		go func() {
   411  			time.Sleep(delay)
   412  			headerFetcher(hash)
   413  		}()
   414  		return nil
   415  	}
   416  	// Announce the same block many times until it's fetched (wait for any pending ops)
   417  	for tester.getBlock(hashes[0]) == nil {
   418  		tester.fetcher.Notify("repeater", hashes[0], 1, time.Now().Add(-arriveTimeout), headerWrapper, bodyFetcher)
   419  		time.Sleep(time.Millisecond)
   420  	}
   421  	time.Sleep(delay)
   422  
   423  	// Check that all blocks were imported and none fetched twice
   424  	if imported := len(tester.blocks); imported != 2 {
   425  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, 2)
   426  	}
   427  	if int(counter) != 1 {
   428  		t.Fatalf("retrieval count mismatch: have %v, want %v", counter, 1)
   429  	}
   430  }
   431  
   432  // Tests that announcements retrieved in a random order are cached and eventually
   433  // imported when all the gaps are filled in.
   434  func TestRandomArrivalImport62(t *testing.T) { testRandomArrivalImport(t, 62) }
   435  func TestRandomArrivalImport63(t *testing.T) { testRandomArrivalImport(t, 63) }
   436  func TestRandomArrivalImport64(t *testing.T) { testRandomArrivalImport(t, 64) }
   437  
   438  func testRandomArrivalImport(t *testing.T, protocol int) {
   439  	// Create a chain of blocks to import, and choose one to delay
   440  	targetBlocks := maxQueueDist
   441  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   442  	skip := targetBlocks / 2
   443  
   444  	tester := newTester()
   445  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   446  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   447  
   448  	// Iteratively announce blocks, skipping one entry
   449  	imported := make(chan *types.Block, len(hashes)-1)
   450  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   451  
   452  	for i := len(hashes) - 1; i >= 0; i-- {
   453  		if i != skip {
   454  			tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   455  			time.Sleep(time.Millisecond)
   456  		}
   457  	}
   458  	// Finally announce the skipped entry and check full import
   459  	tester.fetcher.Notify("valid", hashes[skip], uint64(len(hashes)-skip-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   460  	verifyImportCount(t, imported, len(hashes)-1)
   461  }
   462  
   463  // Tests that direct block enqueues (due to block propagation vs. hash announce)
   464  // are correctly schedule, filling and import queue gaps.
   465  func TestQueueGapFill62(t *testing.T) { testQueueGapFill(t, 62) }
   466  func TestQueueGapFill63(t *testing.T) { testQueueGapFill(t, 63) }
   467  func TestQueueGapFill64(t *testing.T) { testQueueGapFill(t, 64) }
   468  
   469  func testQueueGapFill(t *testing.T, protocol int) {
   470  	// Create a chain of blocks to import, and choose one to not announce at all
   471  	targetBlocks := maxQueueDist
   472  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   473  	skip := targetBlocks / 2
   474  
   475  	tester := newTester()
   476  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   477  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   478  
   479  	// Iteratively announce blocks, skipping one entry
   480  	imported := make(chan *types.Block, len(hashes)-1)
   481  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   482  
   483  	for i := len(hashes) - 1; i >= 0; i-- {
   484  		if i != skip {
   485  			tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   486  			time.Sleep(time.Millisecond)
   487  		}
   488  	}
   489  	// Fill the missing block directly as if propagated
   490  	tester.fetcher.Enqueue("valid", blocks[hashes[skip]])
   491  	verifyImportCount(t, imported, len(hashes)-1)
   492  }
   493  
   494  // Tests that blocks arriving from various sources (multiple propagations, hash
   495  // announces, etc) do not get scheduled for import multiple times.
   496  func TestImportDeduplication62(t *testing.T) { testImportDeduplication(t, 62) }
   497  func TestImportDeduplication63(t *testing.T) { testImportDeduplication(t, 63) }
   498  func TestImportDeduplication64(t *testing.T) { testImportDeduplication(t, 64) }
   499  
   500  func testImportDeduplication(t *testing.T, protocol int) {
   501  	// Create two blocks to import (one for duplication, the other for stalling)
   502  	hashes, blocks := makeChain(2, testAddress, genesis)
   503  
   504  	// Create the tester and wrap the importer with a counter
   505  	tester := newTester()
   506  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   507  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   508  
   509  	counter := uint32(0)
   510  	tester.fetcher.insertChain = func(blocks types.Blocks) (int, error) {
   511  		atomic.AddUint32(&counter, uint32(len(blocks)))
   512  		return tester.insertChain(blocks)
   513  	}
   514  	// Instrument the fetching and imported events
   515  	fetching := make(chan []common.Hash)
   516  	imported := make(chan *types.Block, len(hashes)-1)
   517  	tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes }
   518  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   519  
   520  	// Announce the duplicating block, wait for retrieval, and also propagate directly
   521  	tester.fetcher.Notify("valid", hashes[0], 1, time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   522  	<-fetching
   523  
   524  	tester.fetcher.Enqueue("valid", blocks[hashes[0]])
   525  	tester.fetcher.Enqueue("valid", blocks[hashes[0]])
   526  	tester.fetcher.Enqueue("valid", blocks[hashes[0]])
   527  
   528  	// Fill the missing block directly as if propagated, and check import uniqueness
   529  	tester.fetcher.Enqueue("valid", blocks[hashes[1]])
   530  	verifyImportCount(t, imported, 2)
   531  
   532  	if counter != 2 {
   533  		t.Fatalf("import invocation count mismatch: have %v, want %v", counter, 2)
   534  	}
   535  }
   536  
   537  // Tests that blocks with numbers much lower or higher than out current head get
   538  // discarded to prevent wasting resources on useless blocks from faulty peers.
   539  func TestDistantPropagationDiscarding(t *testing.T) {
   540  	// Create a long chain to import and define the discard boundaries
   541  	hashes, blocks := makeChain(3*maxQueueDist, testAddress, genesis)
   542  	head := hashes[len(hashes)/2]
   543  
   544  	low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1
   545  
   546  	// Create a tester and simulate a head block being the middle of the above chain
   547  	tester := newTester()
   548  
   549  	tester.lock.Lock()
   550  	tester.hashes = []common.Hash{head}
   551  	tester.blocks = map[common.Hash]*types.Block{head: blocks[head]}
   552  	tester.lock.Unlock()
   553  
   554  	// Ensure that a block with a lower number than the threshold is discarded
   555  	tester.fetcher.Enqueue("lower", blocks[hashes[low]])
   556  	time.Sleep(10 * time.Millisecond)
   557  	if !tester.fetcher.queue.Empty() {
   558  		t.Fatalf("fetcher queued stale block")
   559  	}
   560  	// Ensure that a block with a higher number than the threshold is discarded
   561  	tester.fetcher.Enqueue("higher", blocks[hashes[high]])
   562  	time.Sleep(10 * time.Millisecond)
   563  	if !tester.fetcher.queue.Empty() {
   564  		t.Fatalf("fetcher queued future block")
   565  	}
   566  }
   567  
   568  // Tests that announcements with numbers much lower or higher than out current
   569  // head get discarded to prevent wasting resources on useless blocks from faulty
   570  // peers.
   571  func TestDistantAnnouncementDiscarding62(t *testing.T) { testDistantAnnouncementDiscarding(t, 62) }
   572  func TestDistantAnnouncementDiscarding63(t *testing.T) { testDistantAnnouncementDiscarding(t, 63) }
   573  func TestDistantAnnouncementDiscarding64(t *testing.T) { testDistantAnnouncementDiscarding(t, 64) }
   574  
   575  func testDistantAnnouncementDiscarding(t *testing.T, protocol int) {
   576  	// Create a long chain to import and define the discard boundaries
   577  	hashes, blocks := makeChain(3*maxQueueDist, testAddress, genesis)
   578  	head := hashes[len(hashes)/2]
   579  
   580  	low, high := len(hashes)/2+maxUncleDist+1, len(hashes)/2-maxQueueDist-1
   581  
   582  	// Create a tester and simulate a head block being the middle of the above chain
   583  	tester := newTester()
   584  
   585  	tester.lock.Lock()
   586  	tester.hashes = []common.Hash{head}
   587  	tester.blocks = map[common.Hash]*types.Block{head: blocks[head]}
   588  	tester.lock.Unlock()
   589  
   590  	headerFetcher := tester.makeHeaderFetcher("lower", blocks, -gatherSlack)
   591  	bodyFetcher := tester.makeBodyFetcher("lower", blocks, 0)
   592  
   593  	fetching := make(chan struct{}, 2)
   594  	tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- struct{}{} }
   595  
   596  	// Ensure that a block with a lower number than the threshold is discarded
   597  	tester.fetcher.Notify("lower", hashes[low], blocks[hashes[low]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   598  	select {
   599  	case <-time.After(50 * time.Millisecond):
   600  	case <-fetching:
   601  		t.Fatalf("fetcher requested stale header")
   602  	}
   603  	// Ensure that a block with a higher number than the threshold is discarded
   604  	tester.fetcher.Notify("higher", hashes[high], blocks[hashes[high]].NumberU64(), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   605  	select {
   606  	case <-time.After(50 * time.Millisecond):
   607  	case <-fetching:
   608  		t.Fatalf("fetcher requested future header")
   609  	}
   610  }
   611  
   612  // Tests that peers announcing blocks with invalid numbers (i.e. not matching
   613  // the headers provided afterwards) get dropped as malicious.
   614  func TestInvalidNumberAnnouncement62(t *testing.T) { testInvalidNumberAnnouncement(t, 62) }
   615  func TestInvalidNumberAnnouncement63(t *testing.T) { testInvalidNumberAnnouncement(t, 63) }
   616  func TestInvalidNumberAnnouncement64(t *testing.T) { testInvalidNumberAnnouncement(t, 64) }
   617  
   618  func testInvalidNumberAnnouncement(t *testing.T, protocol int) {
   619  	// Create a single block to import and check numbers against
   620  	hashes, blocks := makeChain(1, testAddress, genesis)
   621  
   622  	tester := newTester()
   623  	badHeaderFetcher := tester.makeHeaderFetcher("bad", blocks, -gatherSlack)
   624  	badBodyFetcher := tester.makeBodyFetcher("bad", blocks, 0)
   625  
   626  	imported := make(chan *types.Block)
   627  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   628  
   629  	// Announce a block with a bad number, check for immediate drop
   630  	tester.fetcher.Notify("bad", hashes[0], 2, time.Now().Add(-arriveTimeout), badHeaderFetcher, badBodyFetcher)
   631  	verifyImportEvent(t, imported, false)
   632  
   633  	tester.lock.RLock()
   634  	dropped := tester.drops["bad"]
   635  	tester.lock.RUnlock()
   636  
   637  	if !dropped {
   638  		t.Fatalf("peer with invalid numbered announcement not dropped")
   639  	}
   640  
   641  	goodHeaderFetcher := tester.makeHeaderFetcher("good", blocks, -gatherSlack)
   642  	goodBodyFetcher := tester.makeBodyFetcher("good", blocks, 0)
   643  	// Make sure a good announcement passes without a drop
   644  	tester.fetcher.Notify("good", hashes[0], 1, time.Now().Add(-arriveTimeout), goodHeaderFetcher, goodBodyFetcher)
   645  	verifyImportEvent(t, imported, true)
   646  
   647  	tester.lock.RLock()
   648  	dropped = tester.drops["good"]
   649  	tester.lock.RUnlock()
   650  
   651  	if dropped {
   652  		t.Fatalf("peer with valid numbered announcement dropped")
   653  	}
   654  	verifyImportDone(t, imported)
   655  }
   656  
   657  // Tests that if a block is empty (i.e. header only), no body request should be
   658  // made, and instead the header should be assembled into a whole block in itself.
   659  func TestEmptyBlockShortCircuit62(t *testing.T) { testEmptyBlockShortCircuit(t, 62) }
   660  func TestEmptyBlockShortCircuit63(t *testing.T) { testEmptyBlockShortCircuit(t, 63) }
   661  func TestEmptyBlockShortCircuit64(t *testing.T) { testEmptyBlockShortCircuit(t, 64) }
   662  
   663  func testEmptyBlockShortCircuit(t *testing.T, protocol int) {
   664  	// Create a chain of blocks to import
   665  	hashes, blocks := makeChain(32, testAddress, genesis)
   666  
   667  	tester := newTester()
   668  	headerFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   669  	bodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   670  
   671  	// Add a monitoring hook for all internal events
   672  	fetching := make(chan []common.Hash)
   673  	tester.fetcher.fetchingHook = func(hashes []common.Hash) { fetching <- hashes }
   674  
   675  	completing := make(chan []common.Hash)
   676  	tester.fetcher.completingHook = func(hashes []common.Hash) { completing <- hashes }
   677  
   678  	imported := make(chan *types.Block)
   679  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   680  
   681  	// Iteratively announce blocks until all are imported
   682  	for i := len(hashes) - 2; i >= 0; i-- {
   683  		tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), headerFetcher, bodyFetcher)
   684  
   685  		// All announces should fetch the header
   686  		verifyFetchingEvent(t, fetching, true)
   687  
   688  		// Only blocks with data contents should request bodies
   689  		verifyCompletingEvent(t, completing, len(blocks[hashes[i]].Transactions()) > 0 || len(blocks[hashes[i]].Uncles()) > 0)
   690  
   691  		// Irrelevant of the construct, import should succeed
   692  		verifyImportEvent(t, imported, true)
   693  	}
   694  	verifyImportDone(t, imported)
   695  }
   696  
   697  // Tests that a peer is unable to use unbounded memory with sending infinite
   698  // block announcements to a node, but that even in the face of such an attack,
   699  // the fetcher remains operational.
   700  func TestHashMemoryExhaustionAttack62(t *testing.T) { testHashMemoryExhaustionAttack(t, 62) }
   701  func TestHashMemoryExhaustionAttack63(t *testing.T) { testHashMemoryExhaustionAttack(t, 63) }
   702  func TestHashMemoryExhaustionAttack64(t *testing.T) { testHashMemoryExhaustionAttack(t, 64) }
   703  
   704  func testHashMemoryExhaustionAttack(t *testing.T, protocol int) {
   705  	// Create a tester with instrumented import hooks
   706  	tester := newTester()
   707  
   708  	imported, announces := make(chan *types.Block), int32(0)
   709  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   710  	tester.fetcher.announceChangeHook = func(hash common.Hash, added bool) {
   711  		if added {
   712  			atomic.AddInt32(&announces, 1)
   713  		} else {
   714  			atomic.AddInt32(&announces, -1)
   715  		}
   716  	}
   717  	// Create a valid chain and an infinite junk chain
   718  	targetBlocks := hashLimit + 2*maxQueueDist
   719  	hashes, blocks := makeChain(targetBlocks, testAddress, genesis)
   720  	validHeaderFetcher := tester.makeHeaderFetcher("valid", blocks, -gatherSlack)
   721  	validBodyFetcher := tester.makeBodyFetcher("valid", blocks, 0)
   722  
   723  	attack, _ := makeChain(targetBlocks, testAddress, unknownBlock)
   724  	attackerHeaderFetcher := tester.makeHeaderFetcher("attacker", nil, -gatherSlack)
   725  	attackerBodyFetcher := tester.makeBodyFetcher("attacker", nil, 0)
   726  
   727  	// Feed the tester a huge hashset from the attacker, and a limited from the valid peer
   728  	for i := 0; i < len(attack); i++ {
   729  		if i < maxQueueDist {
   730  			tester.fetcher.Notify("valid", hashes[len(hashes)-2-i], uint64(i+1), time.Now(), validHeaderFetcher, validBodyFetcher)
   731  		}
   732  		tester.fetcher.Notify("attacker", attack[i], 1 /* don't distance drop */, time.Now(), attackerHeaderFetcher, attackerBodyFetcher)
   733  	}
   734  	if count := atomic.LoadInt32(&announces); count != hashLimit+maxQueueDist {
   735  		t.Fatalf("queued announce count mismatch: have %d, want %d", count, hashLimit+maxQueueDist)
   736  	}
   737  	// Wait for fetches to complete
   738  	verifyImportCount(t, imported, maxQueueDist)
   739  
   740  	// Feed the remaining valid hashes to ensure DOS protection state remains clean
   741  	for i := len(hashes) - maxQueueDist - 2; i >= 0; i-- {
   742  		tester.fetcher.Notify("valid", hashes[i], uint64(len(hashes)-i-1), time.Now().Add(-arriveTimeout), validHeaderFetcher, validBodyFetcher)
   743  		verifyImportEvent(t, imported, true)
   744  	}
   745  	verifyImportDone(t, imported)
   746  }
   747  
   748  // mock environment to generate blocks with different coinbase
   749  type fetcherEnv struct {
   750  	keyS     []*ecdsa.PrivateKey
   751  	addrS    []common.Address
   752  	genesis  *types.Block
   753  	engine   consensus.Engine
   754  	chainEnv *core.ChainEnv
   755  }
   756  
   757  func genEnv() fetcherEnv {
   758  	db, _ := ethdb.NewMemDatabase()
   759  	engine := ethash.NewFaker(db)
   760  	l := 5
   761  	extraData := make([]byte, 0)
   762  	keySlice, addrSlice := make([]*ecdsa.PrivateKey, l), make([]common.Address, l)
   763  	for i := 0; i < l; i++ {
   764  		keySlice[i], _ = crypto.GenerateKey()
   765  		addrSlice[i] = crypto.PubkeyToAddress(keySlice[i].PublicKey)
   766  		extraData = append(extraData, addrSlice[i].Bytes()...)
   767  	}
   768  
   769  	gspec := &core.Genesis{
   770  		Config:     params.TestChainConfig,
   771  		ExtraData:  extraData,
   772  		Difficulty: big.NewInt(1),
   773  	}
   774  
   775  	genesis := gspec.MustCommit(db)
   776  
   777  	chain, _ := core.NewBlockChain(db, params.TestChainConfig, engine, vm.Config{})
   778  	defer chain.Stop()
   779  	env := core.NewChainEnv(params.TestChainConfig, gspec, engine, chain, db)
   780  
   781  	return fetcherEnv{
   782  		keyS:     keySlice,
   783  		addrS:    addrSlice,
   784  		genesis:  genesis,
   785  		engine:   engine,
   786  		chainEnv: env,
   787  	}
   788  }
   789  
   790  func genChain(n int, addr common.Address, parent *types.Block, env *core.ChainEnv) ([]common.Hash, map[common.Hash]*types.Block) {
   791  	blocks, _ := env.GenerateChainMulti(parent, n, func(i int, block *core.BlockGen) {
   792  
   793  		block.SetCoinbase(addr)
   794  
   795  		// If the block number is multiple of 3, send a bonus transaction to the miner
   796  		// if parent == genesis && i%3 == 0 {
   797  		// 	signer := types.MakeSigner(params.TestChainConfig, block.Number())
   798  		// 	tx, err := types.SignTx(types.NewTransaction(block.TxNonce(addr), addresses[i], big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey)
   799  		// 	if err != nil {
   800  		// 		panic(err)
   801  		// 	}
   802  		// 	block.AddTx(tx)
   803  		// }
   804  
   805  	})
   806  
   807  	hashes := make([]common.Hash, n+1)
   808  	hashes[len(hashes)-1] = parent.Hash()
   809  	blockm := make(map[common.Hash]*types.Block, n+1)
   810  	blockm[parent.Hash()] = parent
   811  	for i, b := range blocks {
   812  		hashes[len(hashes)-i-2] = b.Hash()
   813  		blockm[b.Hash()] = b
   814  	}
   815  	return hashes, blockm
   816  }
   817  
   818  // Tests that blocks sent to the fetcher (either through propagation or via hash
   819  // announces and retrievals) don't pile up indefinitely, exhausting available
   820  // system memory.
   821  func TestBlockMemoryExhaustionAttack(t *testing.T) {
   822  	// Create a tester with instrumented import hooks
   823  	env := genEnv()
   824  	tester := &fetcherTester{
   825  		hashes: []common.Hash{env.genesis.Hash()},
   826  		blocks: map[common.Hash]*types.Block{env.genesis.Hash(): env.genesis},
   827  		drops:  make(map[string]bool),
   828  	}
   829  	tester.fetcher = New(tester.getBlock, tester.verifyHeader, tester.broadcastBlock, tester.chainHeight, tester.insertChain, tester.dropPeer)
   830  	tester.fetcher.Start()
   831  
   832  	imported, enqueued := make(chan *types.Block), int32(0)
   833  	tester.fetcher.importedHook = func(block *types.Block) { imported <- block }
   834  	tester.fetcher.queueChangeHook = func(hash common.Hash, added bool) {
   835  		if added {
   836  			atomic.AddInt32(&enqueued, 1)
   837  		} else {
   838  			atomic.AddInt32(&enqueued, -1)
   839  		}
   840  	}
   841  
   842  	// Create a valid chain and a batch of dangling (but in range) blocks
   843  	targetBlocks := hashLimit + 2*maxQueueDist
   844  	hashes, blocks := genChain(targetBlocks, env.addrS[0], env.genesis, env.chainEnv)
   845  	attack := make(map[common.Hash]*types.Block)
   846  	for i := byte(0); len(attack) < blockLimit+2*maxQueueDist; i++ {
   847  		hashes, blocks := genChain(maxQueueDist-1, env.addrS[i], unknownBlock, env.chainEnv)
   848  		for _, hash := range hashes[:maxQueueDist-2] {
   849  			attack[hash] = blocks[hash]
   850  		}
   851  	}
   852  
   853  	// // Try to feed all the attacker blocks make sure only a limited batch is accepted
   854  	for _, block := range attack {
   855  		tester.fetcher.Enqueue("attacker", block)
   856  	}
   857  	time.Sleep(200 * time.Millisecond)
   858  	if queued := atomic.LoadInt32(&enqueued); queued != blockLimit {
   859  		t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit)
   860  	}
   861  	// Queue up a batch of valid blocks, and check that a new peer is allowed to do so
   862  	for i := 0; i < maxQueueDist-1; i++ {
   863  		tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-3-i]])
   864  	}
   865  	time.Sleep(100 * time.Millisecond)
   866  	if queued := atomic.LoadInt32(&enqueued); queued != blockLimit+maxQueueDist-1 {
   867  		t.Fatalf("queued block count mismatch: have %d, want %d", queued, blockLimit+maxQueueDist-1)
   868  	}
   869  	// // Insert the missing piece (and sanity check the import)
   870  	tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2]])
   871  	verifyImportCount(t, imported, maxQueueDist)
   872  
   873  	// Insert the remaining blocks in chunks to ensure clean DOS protection
   874  	for i := maxQueueDist; i < len(hashes)-1; i++ {
   875  		tester.fetcher.Enqueue("valid", blocks[hashes[len(hashes)-2-i]])
   876  		verifyImportEvent(t, imported, true)
   877  	}
   878  	verifyImportDone(t, imported)
   879  }