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