github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/qct/fetcher/fetcher_test.go (about)

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