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