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