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