github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/eth/fetcher/fetcher_test.go (about)

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