github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/eth/downloader/downloader_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 downloader
    18  
    19  import (
    20  	"crypto/rand"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  	"sync/atomic"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  	"github.com/ethereum/go-ethereum/event"
    33  )
    34  
    35  var (
    36  	testdb, _ = ethdb.NewMemDatabase()
    37  	genesis   = core.GenesisBlockForTesting(testdb, common.Address{}, big.NewInt(0))
    38  )
    39  
    40  // makeChain creates a chain of n blocks starting at but not including
    41  // parent. the returned hash chain is ordered head->parent.
    42  func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
    43  	blocks := core.GenerateChain(parent, testdb, n, func(i int, gen *core.BlockGen) {
    44  		gen.SetCoinbase(common.Address{seed})
    45  	})
    46  	hashes := make([]common.Hash, n+1)
    47  	hashes[len(hashes)-1] = parent.Hash()
    48  	blockm := make(map[common.Hash]*types.Block, n+1)
    49  	blockm[parent.Hash()] = parent
    50  	for i, b := range blocks {
    51  		hashes[len(hashes)-i-2] = b.Hash()
    52  		blockm[b.Hash()] = b
    53  	}
    54  	return hashes, blockm
    55  }
    56  
    57  // makeChainFork creates two chains of length n, such that h1[:f] and
    58  // h2[:f] are different but have a common suffix of length n-f.
    59  func makeChainFork(n, f int, parent *types.Block) (h1, h2 []common.Hash, b1, b2 map[common.Hash]*types.Block) {
    60  	// Create the common suffix.
    61  	h, b := makeChain(n-f, 0, parent)
    62  	// Create the forks.
    63  	h1, b1 = makeChain(f, 1, b[h[0]])
    64  	h1 = append(h1, h[1:]...)
    65  	h2, b2 = makeChain(f, 2, b[h[0]])
    66  	h2 = append(h2, h[1:]...)
    67  	for hash, block := range b {
    68  		b1[hash] = block
    69  		b2[hash] = block
    70  	}
    71  	return h1, h2, b1, b2
    72  }
    73  
    74  // downloadTester is a test simulator for mocking out local block chain.
    75  type downloadTester struct {
    76  	downloader *Downloader
    77  
    78  	ownHashes  []common.Hash                           // Hash chain belonging to the tester
    79  	ownBlocks  map[common.Hash]*types.Block            // Blocks belonging to the tester
    80  	peerHashes map[string][]common.Hash                // Hash chain belonging to different test peers
    81  	peerBlocks map[string]map[common.Hash]*types.Block // Blocks belonging to different test peers
    82  
    83  	maxHashFetch int // Overrides the maximum number of retrieved hashes
    84  }
    85  
    86  // newTester creates a new downloader test mocker.
    87  func newTester() *downloadTester {
    88  	tester := &downloadTester{
    89  		ownHashes:  []common.Hash{genesis.Hash()},
    90  		ownBlocks:  map[common.Hash]*types.Block{genesis.Hash(): genesis},
    91  		peerHashes: make(map[string][]common.Hash),
    92  		peerBlocks: make(map[string]map[common.Hash]*types.Block),
    93  	}
    94  	tester.downloader = New(new(event.TypeMux), tester.hasBlock, tester.getBlock, tester.headBlock, tester.insertChain, tester.dropPeer)
    95  
    96  	return tester
    97  }
    98  
    99  // sync starts synchronizing with a remote peer, blocking until it completes.
   100  func (dl *downloadTester) sync(id string, td *big.Int) error {
   101  	hash := dl.peerHashes[id][0]
   102  
   103  	// If no particular TD was requested, load from the peer's blockchain
   104  	if td == nil {
   105  		td = big.NewInt(1)
   106  		if block, ok := dl.peerBlocks[id][hash]; ok {
   107  			td = block.Td
   108  		}
   109  	}
   110  	err := dl.downloader.synchronise(id, hash, td)
   111  
   112  	for {
   113  		// If the queue is empty and processing stopped, break
   114  		hashes, blocks := dl.downloader.queue.Size()
   115  		if hashes+blocks == 0 && atomic.LoadInt32(&dl.downloader.processing) == 0 {
   116  			break
   117  		}
   118  		// Otherwise sleep a bit and retry
   119  		time.Sleep(time.Millisecond)
   120  	}
   121  	return err
   122  }
   123  
   124  // hasBlock checks if a block is pres	ent in the testers canonical chain.
   125  func (dl *downloadTester) hasBlock(hash common.Hash) bool {
   126  	return dl.getBlock(hash) != nil
   127  }
   128  
   129  // getBlock retrieves a block from the testers canonical chain.
   130  func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
   131  	return dl.ownBlocks[hash]
   132  }
   133  
   134  // headBlock retrieves the current head block from the canonical chain.
   135  func (dl *downloadTester) headBlock() *types.Block {
   136  	return dl.getBlock(dl.ownHashes[len(dl.ownHashes)-1])
   137  }
   138  
   139  // insertChain injects a new batch of blocks into the simulated chain.
   140  func (dl *downloadTester) insertChain(blocks types.Blocks) (int, error) {
   141  	for i, block := range blocks {
   142  		if _, ok := dl.ownBlocks[block.ParentHash()]; !ok {
   143  			return i, errors.New("unknown parent")
   144  		}
   145  		dl.ownHashes = append(dl.ownHashes, block.Hash())
   146  		dl.ownBlocks[block.Hash()] = block
   147  	}
   148  	return len(blocks), nil
   149  }
   150  
   151  // newPeer registers a new block download source into the downloader.
   152  func (dl *downloadTester) newPeer(id string, version int, hashes []common.Hash, blocks map[common.Hash]*types.Block) error {
   153  	return dl.newSlowPeer(id, version, hashes, blocks, 0)
   154  }
   155  
   156  // newSlowPeer registers a new block download source into the downloader, with a
   157  // specific delay time on processing the network packets sent to it, simulating
   158  // potentially slow network IO.
   159  func (dl *downloadTester) newSlowPeer(id string, version int, hashes []common.Hash, blocks map[common.Hash]*types.Block, delay time.Duration) error {
   160  	err := dl.downloader.RegisterPeer(id, version, hashes[0], dl.peerGetRelHashesFn(id, delay), dl.peerGetAbsHashesFn(id, version, delay), dl.peerGetBlocksFn(id, delay))
   161  	if err == nil {
   162  		// Assign the owned hashes and blocks to the peer (deep copy)
   163  		dl.peerHashes[id] = make([]common.Hash, len(hashes))
   164  		copy(dl.peerHashes[id], hashes)
   165  		dl.peerBlocks[id] = make(map[common.Hash]*types.Block)
   166  		for hash, block := range blocks {
   167  			dl.peerBlocks[id][hash] = block
   168  		}
   169  	}
   170  	return err
   171  }
   172  
   173  // dropPeer simulates a hard peer removal from the connection pool.
   174  func (dl *downloadTester) dropPeer(id string) {
   175  	delete(dl.peerHashes, id)
   176  	delete(dl.peerBlocks, id)
   177  
   178  	dl.downloader.UnregisterPeer(id)
   179  }
   180  
   181  // peerGetRelHashesFn constructs a GetHashes function associated with a specific
   182  // peer in the download tester. The returned function can be used to retrieve
   183  // batches of hashes from the particularly requested peer.
   184  func (dl *downloadTester) peerGetRelHashesFn(id string, delay time.Duration) func(head common.Hash) error {
   185  	return func(head common.Hash) error {
   186  		time.Sleep(delay)
   187  
   188  		limit := MaxHashFetch
   189  		if dl.maxHashFetch > 0 {
   190  			limit = dl.maxHashFetch
   191  		}
   192  		// Gather the next batch of hashes
   193  		hashes := dl.peerHashes[id]
   194  		result := make([]common.Hash, 0, limit)
   195  		for i, hash := range hashes {
   196  			if hash == head {
   197  				i++
   198  				for len(result) < cap(result) && i < len(hashes) {
   199  					result = append(result, hashes[i])
   200  					i++
   201  				}
   202  				break
   203  			}
   204  		}
   205  		// Delay delivery a bit to allow attacks to unfold
   206  		go func() {
   207  			time.Sleep(time.Millisecond)
   208  			dl.downloader.DeliverHashes(id, result)
   209  		}()
   210  		return nil
   211  	}
   212  }
   213  
   214  // peerGetAbsHashesFn constructs a GetHashesFromNumber function associated with
   215  // a particular peer in the download tester. The returned function can be used to
   216  // retrieve batches of hashes from the particularly requested peer.
   217  func (dl *downloadTester) peerGetAbsHashesFn(id string, version int, delay time.Duration) func(uint64, int) error {
   218  	// If the simulated peer runs eth/60, this message is not supported
   219  	if version == eth60 {
   220  		return func(uint64, int) error { return nil }
   221  	}
   222  	// Otherwise create a method to request the blocks by number
   223  	return func(head uint64, count int) error {
   224  		time.Sleep(delay)
   225  
   226  		limit := count
   227  		if dl.maxHashFetch > 0 {
   228  			limit = dl.maxHashFetch
   229  		}
   230  		// Gather the next batch of hashes
   231  		hashes := dl.peerHashes[id]
   232  		result := make([]common.Hash, 0, limit)
   233  		for i := 0; i < limit && len(hashes)-int(head)-1-i >= 0; i++ {
   234  			result = append(result, hashes[len(hashes)-int(head)-1-i])
   235  		}
   236  		// Delay delivery a bit to allow attacks to unfold
   237  		go func() {
   238  			time.Sleep(time.Millisecond)
   239  			dl.downloader.DeliverHashes(id, result)
   240  		}()
   241  		return nil
   242  	}
   243  }
   244  
   245  // peerGetBlocksFn constructs a getBlocks function associated with a particular
   246  // peer in the download tester. The returned function can be used to retrieve
   247  // batches of blocks from the particularly requested peer.
   248  func (dl *downloadTester) peerGetBlocksFn(id string, delay time.Duration) func([]common.Hash) error {
   249  	return func(hashes []common.Hash) error {
   250  		time.Sleep(delay)
   251  		blocks := dl.peerBlocks[id]
   252  		result := make([]*types.Block, 0, len(hashes))
   253  		for _, hash := range hashes {
   254  			if block, ok := blocks[hash]; ok {
   255  				result = append(result, block)
   256  			}
   257  		}
   258  		go dl.downloader.DeliverBlocks(id, result)
   259  
   260  		return nil
   261  	}
   262  }
   263  
   264  // Tests that simple synchronization, without throttling from a good peer works.
   265  func TestSynchronisation60(t *testing.T) {
   266  	// Create a small enough block chain to download and the tester
   267  	targetBlocks := blockCacheLimit - 15
   268  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   269  
   270  	tester := newTester()
   271  	tester.newPeer("peer", eth60, hashes, blocks)
   272  
   273  	// Synchronise with the peer and make sure all blocks were retrieved
   274  	if err := tester.sync("peer", nil); err != nil {
   275  		t.Fatalf("failed to synchronise blocks: %v", err)
   276  	}
   277  	if imported := len(tester.ownBlocks); imported != targetBlocks+1 {
   278  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1)
   279  	}
   280  }
   281  
   282  // Tests that simple synchronization against a canonical chain works correctly.
   283  // In this test common ancestor lookup should be short circuited and not require
   284  // binary searching.
   285  func TestCanonicalSynchronisation61(t *testing.T) {
   286  	// Create a small enough block chain to download
   287  	targetBlocks := blockCacheLimit - 15
   288  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   289  
   290  	tester := newTester()
   291  	tester.newPeer("peer", eth61, hashes, blocks)
   292  
   293  	// Synchronise with the peer and make sure all blocks were retrieved
   294  	if err := tester.sync("peer", nil); err != nil {
   295  		t.Fatalf("failed to synchronise blocks: %v", err)
   296  	}
   297  	if imported := len(tester.ownBlocks); imported != targetBlocks+1 {
   298  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1)
   299  	}
   300  }
   301  
   302  // Tests that if a large batch of blocks are being downloaded, it is throttled
   303  // until the cached blocks are retrieved.
   304  func TestThrottling60(t *testing.T) { testThrottling(t, eth60) }
   305  func TestThrottling61(t *testing.T) { testThrottling(t, eth61) }
   306  
   307  func testThrottling(t *testing.T, protocol int) {
   308  	// Create a long block chain to download and the tester
   309  	targetBlocks := 8 * blockCacheLimit
   310  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   311  
   312  	tester := newTester()
   313  	tester.newPeer("peer", protocol, hashes, blocks)
   314  
   315  	// Wrap the importer to allow stepping
   316  	done := make(chan int)
   317  	tester.downloader.insertChain = func(blocks types.Blocks) (int, error) {
   318  		n, err := tester.insertChain(blocks)
   319  		done <- n
   320  		return n, err
   321  	}
   322  	// Start a synchronisation concurrently
   323  	errc := make(chan error)
   324  	go func() {
   325  		errc <- tester.sync("peer", nil)
   326  	}()
   327  	// Iteratively take some blocks, always checking the retrieval count
   328  	for len(tester.ownBlocks) < targetBlocks+1 {
   329  		// Wait a bit for sync to throttle itself
   330  		var cached int
   331  		for start := time.Now(); time.Since(start) < 3*time.Second; {
   332  			time.Sleep(25 * time.Millisecond)
   333  
   334  			cached = len(tester.downloader.queue.blockPool)
   335  			if cached == blockCacheLimit || len(tester.ownBlocks)+cached == targetBlocks+1 {
   336  				break
   337  			}
   338  		}
   339  		// Make sure we filled up the cache, then exhaust it
   340  		time.Sleep(25 * time.Millisecond) // give it a chance to screw up
   341  		if cached != blockCacheLimit && len(tester.ownBlocks)+cached < targetBlocks+1 {
   342  			t.Fatalf("block count mismatch: have %v, want %v", cached, blockCacheLimit)
   343  		}
   344  		<-done // finish previous blocking import
   345  		for cached > maxBlockProcess {
   346  			cached -= <-done
   347  		}
   348  		time.Sleep(25 * time.Millisecond) // yield to the insertion
   349  	}
   350  	<-done // finish the last blocking import
   351  
   352  	// Check that we haven't pulled more blocks than available
   353  	if len(tester.ownBlocks) > targetBlocks+1 {
   354  		t.Fatalf("target block count mismatch: have %v, want %v", len(tester.ownBlocks), targetBlocks+1)
   355  	}
   356  	if err := <-errc; err != nil {
   357  		t.Fatalf("block synchronization failed: %v", err)
   358  	}
   359  }
   360  
   361  // Tests that simple synchronization against a forked chain works correctly. In
   362  // this test common ancestor lookup should *not* be short circuited, and a full
   363  // binary search should be executed.
   364  func TestForkedSynchronisation61(t *testing.T) {
   365  	// Create a long enough forked chain
   366  	common, fork := MaxHashFetch, 2*MaxHashFetch
   367  	hashesA, hashesB, blocksA, blocksB := makeChainFork(common+fork, fork, genesis)
   368  
   369  	tester := newTester()
   370  	tester.newPeer("fork A", eth61, hashesA, blocksA)
   371  	tester.newPeer("fork B", eth61, hashesB, blocksB)
   372  
   373  	// Synchronise with the peer and make sure all blocks were retrieved
   374  	if err := tester.sync("fork A", nil); err != nil {
   375  		t.Fatalf("failed to synchronise blocks: %v", err)
   376  	}
   377  	if imported := len(tester.ownBlocks); imported != common+fork+1 {
   378  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, common+fork+1)
   379  	}
   380  	// Synchronise with the second peer and make sure that fork is pulled too
   381  	if err := tester.sync("fork B", nil); err != nil {
   382  		t.Fatalf("failed to synchronise blocks: %v", err)
   383  	}
   384  	if imported := len(tester.ownBlocks); imported != common+2*fork+1 {
   385  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, common+2*fork+1)
   386  	}
   387  }
   388  
   389  // Tests that an inactive downloader will not accept incoming hashes and blocks.
   390  func TestInactiveDownloader(t *testing.T) {
   391  	tester := newTester()
   392  
   393  	// Check that neither hashes nor blocks are accepted
   394  	if err := tester.downloader.DeliverHashes("bad peer", []common.Hash{}); err != errNoSyncActive {
   395  		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive)
   396  	}
   397  	if err := tester.downloader.DeliverBlocks("bad peer", []*types.Block{}); err != errNoSyncActive {
   398  		t.Errorf("error mismatch: have %v, want %v", err, errNoSyncActive)
   399  	}
   400  }
   401  
   402  // Tests that a canceled download wipes all previously accumulated state.
   403  func TestCancel60(t *testing.T) { testCancel(t, eth60) }
   404  func TestCancel61(t *testing.T) { testCancel(t, eth61) }
   405  
   406  func testCancel(t *testing.T, protocol int) {
   407  	// Create a small enough block chain to download and the tester
   408  	targetBlocks := blockCacheLimit - 15
   409  	if targetBlocks >= MaxHashFetch {
   410  		targetBlocks = MaxHashFetch - 15
   411  	}
   412  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   413  
   414  	tester := newTester()
   415  	tester.newPeer("peer", protocol, hashes, blocks)
   416  
   417  	// Make sure canceling works with a pristine downloader
   418  	tester.downloader.cancel()
   419  	hashCount, blockCount := tester.downloader.queue.Size()
   420  	if hashCount > 0 || blockCount > 0 {
   421  		t.Errorf("block or hash count mismatch: %d hashes, %d blocks, want 0", hashCount, blockCount)
   422  	}
   423  	// Synchronise with the peer, but cancel afterwards
   424  	if err := tester.sync("peer", nil); err != nil {
   425  		t.Fatalf("failed to synchronise blocks: %v", err)
   426  	}
   427  	tester.downloader.cancel()
   428  	hashCount, blockCount = tester.downloader.queue.Size()
   429  	if hashCount > 0 || blockCount > 0 {
   430  		t.Errorf("block or hash count mismatch: %d hashes, %d blocks, want 0", hashCount, blockCount)
   431  	}
   432  }
   433  
   434  // Tests that synchronisation from multiple peers works as intended (multi thread sanity test).
   435  func TestMultiSynchronisation60(t *testing.T) { testMultiSynchronisation(t, eth60) }
   436  func TestMultiSynchronisation61(t *testing.T) { testMultiSynchronisation(t, eth61) }
   437  
   438  func testMultiSynchronisation(t *testing.T, protocol int) {
   439  	// Create various peers with various parts of the chain
   440  	targetPeers := 16
   441  	targetBlocks := targetPeers*blockCacheLimit - 15
   442  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   443  
   444  	tester := newTester()
   445  	for i := 0; i < targetPeers; i++ {
   446  		id := fmt.Sprintf("peer #%d", i)
   447  		tester.newPeer(id, protocol, hashes[i*blockCacheLimit:], blocks)
   448  	}
   449  	// Synchronise with the middle peer and make sure half of the blocks were retrieved
   450  	id := fmt.Sprintf("peer #%d", targetPeers/2)
   451  	if err := tester.sync(id, nil); err != nil {
   452  		t.Fatalf("failed to synchronise blocks: %v", err)
   453  	}
   454  	if imported := len(tester.ownBlocks); imported != len(tester.peerHashes[id]) {
   455  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, len(tester.peerHashes[id]))
   456  	}
   457  	// Synchronise with the best peer and make sure everything is retrieved
   458  	if err := tester.sync("peer #0", nil); err != nil {
   459  		t.Fatalf("failed to synchronise blocks: %v", err)
   460  	}
   461  	if imported := len(tester.ownBlocks); imported != targetBlocks+1 {
   462  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1)
   463  	}
   464  }
   465  
   466  // Tests that synchronising with a peer who's very slow at network IO does not
   467  // stall the other peers in the system.
   468  func TestSlowSynchronisation60(t *testing.T) {
   469  	tester := newTester()
   470  
   471  	// Create a batch of blocks, with a slow and a full speed peer
   472  	targetCycles := 2
   473  	targetBlocks := targetCycles*blockCacheLimit - 15
   474  	targetIODelay := time.Second
   475  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   476  
   477  	tester.newSlowPeer("fast", eth60, hashes, blocks, 0)
   478  	tester.newSlowPeer("slow", eth60, hashes, blocks, targetIODelay)
   479  
   480  	// Try to sync with the peers (pull hashes from fast)
   481  	start := time.Now()
   482  	if err := tester.sync("fast", nil); err != nil {
   483  		t.Fatalf("failed to synchronise blocks: %v", err)
   484  	}
   485  	if imported := len(tester.ownBlocks); imported != targetBlocks+1 {
   486  		t.Fatalf("synchronised block mismatch: have %v, want %v", imported, targetBlocks+1)
   487  	}
   488  	// Check that the slow peer got hit at most once per block-cache-size import
   489  	limit := time.Duration(targetCycles+1) * targetIODelay
   490  	if delay := time.Since(start); delay >= limit {
   491  		t.Fatalf("synchronisation exceeded delay limit: have %v, want %v", delay, limit)
   492  	}
   493  }
   494  
   495  // Tests that if a peer returns an invalid chain with a block pointing to a non-
   496  // existing parent, it is correctly detected and handled.
   497  func TestNonExistingParentAttack60(t *testing.T) {
   498  	tester := newTester()
   499  
   500  	// Forge a single-link chain with a forged header
   501  	hashes, blocks := makeChain(1, 0, genesis)
   502  	tester.newPeer("valid", eth60, hashes, blocks)
   503  
   504  	wrongblock := types.NewBlock(&types.Header{}, nil, nil, nil)
   505  	wrongblock.Td = blocks[hashes[0]].Td
   506  	hashes, blocks = makeChain(1, 0, wrongblock)
   507  	tester.newPeer("attack", eth60, hashes, blocks)
   508  
   509  	// Try and sync with the malicious node and check that it fails
   510  	if err := tester.sync("attack", nil); err == nil {
   511  		t.Fatalf("block synchronization succeeded")
   512  	}
   513  	if tester.hasBlock(hashes[0]) {
   514  		t.Fatalf("tester accepted unknown-parent block: %v", blocks[hashes[0]])
   515  	}
   516  	// Try to synchronize with the valid chain and make sure it succeeds
   517  	if err := tester.sync("valid", nil); err != nil {
   518  		t.Fatalf("failed to synchronise blocks: %v", err)
   519  	}
   520  	if !tester.hasBlock(tester.peerHashes["valid"][0]) {
   521  		t.Fatalf("tester didn't accept known-parent block: %v", tester.peerBlocks["valid"][hashes[0]])
   522  	}
   523  }
   524  
   525  // Tests that if a malicious peers keeps sending us repeating hashes, we don't
   526  // loop indefinitely.
   527  func TestRepeatingHashAttack60(t *testing.T) { // TODO: Is this thing valid??
   528  	tester := newTester()
   529  
   530  	// Create a valid chain, but drop the last link
   531  	hashes, blocks := makeChain(blockCacheLimit, 0, genesis)
   532  	tester.newPeer("valid", eth60, hashes, blocks)
   533  	tester.newPeer("attack", eth60, hashes[:len(hashes)-1], blocks)
   534  
   535  	// Try and sync with the malicious node
   536  	errc := make(chan error)
   537  	go func() {
   538  		errc <- tester.sync("attack", nil)
   539  	}()
   540  	// Make sure that syncing returns and does so with a failure
   541  	select {
   542  	case <-time.After(time.Second):
   543  		t.Fatalf("synchronisation blocked")
   544  	case err := <-errc:
   545  		if err == nil {
   546  			t.Fatalf("synchronisation succeeded")
   547  		}
   548  	}
   549  	// Ensure that a valid chain can still pass sync
   550  	if err := tester.sync("valid", nil); err != nil {
   551  		t.Fatalf("failed to synchronise blocks: %v", err)
   552  	}
   553  }
   554  
   555  // Tests that if a malicious peers returns a non-existent block hash, it should
   556  // eventually time out and the sync reattempted.
   557  func TestNonExistingBlockAttack60(t *testing.T) {
   558  	tester := newTester()
   559  
   560  	// Create a valid chain, but forge the last link
   561  	hashes, blocks := makeChain(blockCacheLimit, 0, genesis)
   562  	tester.newPeer("valid", eth60, hashes, blocks)
   563  
   564  	hashes[len(hashes)/2] = common.Hash{}
   565  	tester.newPeer("attack", eth60, hashes, blocks)
   566  
   567  	// Try and sync with the malicious node and check that it fails
   568  	if err := tester.sync("attack", nil); err != errPeersUnavailable {
   569  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errPeersUnavailable)
   570  	}
   571  	// Ensure that a valid chain can still pass sync
   572  	if err := tester.sync("valid", nil); err != nil {
   573  		t.Fatalf("failed to synchronise blocks: %v", err)
   574  	}
   575  }
   576  
   577  // Tests that if a malicious peer is returning hashes in a weird order, that the
   578  // sync throttler doesn't choke on them waiting for the valid blocks.
   579  func TestInvalidHashOrderAttack60(t *testing.T) {
   580  	tester := newTester()
   581  
   582  	// Create a valid long chain, but reverse some hashes within
   583  	hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis)
   584  	tester.newPeer("valid", eth60, hashes, blocks)
   585  
   586  	chunk1 := make([]common.Hash, blockCacheLimit)
   587  	chunk2 := make([]common.Hash, blockCacheLimit)
   588  	copy(chunk1, hashes[blockCacheLimit:2*blockCacheLimit])
   589  	copy(chunk2, hashes[2*blockCacheLimit:3*blockCacheLimit])
   590  
   591  	copy(hashes[2*blockCacheLimit:], chunk1)
   592  	copy(hashes[blockCacheLimit:], chunk2)
   593  	tester.newPeer("attack", eth60, hashes, blocks)
   594  
   595  	// Try and sync with the malicious node and check that it fails
   596  	if err := tester.sync("attack", nil); err != errInvalidChain {
   597  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain)
   598  	}
   599  	// Ensure that a valid chain can still pass sync
   600  	if err := tester.sync("valid", nil); err != nil {
   601  		t.Fatalf("failed to synchronise blocks: %v", err)
   602  	}
   603  }
   604  
   605  // Tests that if a malicious peer makes up a random hash chain and tries to push
   606  // indefinitely, it actually gets caught with it.
   607  func TestMadeupHashChainAttack60(t *testing.T) {
   608  	tester := newTester()
   609  	blockSoftTTL = 100 * time.Millisecond
   610  	crossCheckCycle = 25 * time.Millisecond
   611  
   612  	// Create a long chain of hashes without backing blocks
   613  	hashes, blocks := makeChain(4*blockCacheLimit, 0, genesis)
   614  
   615  	randomHashes := make([]common.Hash, 1024*blockCacheLimit)
   616  	for i := range randomHashes {
   617  		rand.Read(randomHashes[i][:])
   618  	}
   619  
   620  	tester.newPeer("valid", eth60, hashes, blocks)
   621  	tester.newPeer("attack", eth60, randomHashes, nil)
   622  
   623  	// Try and sync with the malicious node and check that it fails
   624  	if err := tester.sync("attack", nil); err != errCrossCheckFailed {
   625  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errCrossCheckFailed)
   626  	}
   627  	// Ensure that a valid chain can still pass sync
   628  	if err := tester.sync("valid", nil); err != nil {
   629  		t.Fatalf("failed to synchronise blocks: %v", err)
   630  	}
   631  }
   632  
   633  // Tests that if a malicious peer makes up a random hash chain, and tries to push
   634  // indefinitely, one hash at a time, it actually gets caught with it. The reason
   635  // this is separate from the classical made up chain attack is that sending hashes
   636  // one by one prevents reliable block/parent verification.
   637  func TestMadeupHashChainDrippingAttack60(t *testing.T) {
   638  	// Create a random chain of hashes to drip
   639  	randomHashes := make([]common.Hash, 16*blockCacheLimit)
   640  	for i := range randomHashes {
   641  		rand.Read(randomHashes[i][:])
   642  	}
   643  	randomHashes[len(randomHashes)-1] = genesis.Hash()
   644  	tester := newTester()
   645  
   646  	// Try and sync with the attacker, one hash at a time
   647  	tester.maxHashFetch = 1
   648  	tester.newPeer("attack", eth60, randomHashes, nil)
   649  	if err := tester.sync("attack", nil); err != errStallingPeer {
   650  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer)
   651  	}
   652  }
   653  
   654  // Tests that if a malicious peer makes up a random block chain, and tried to
   655  // push indefinitely, it actually gets caught with it.
   656  func TestMadeupBlockChainAttack60(t *testing.T) {
   657  	defaultBlockTTL := blockSoftTTL
   658  	defaultCrossCheckCycle := crossCheckCycle
   659  
   660  	blockSoftTTL = 100 * time.Millisecond
   661  	crossCheckCycle = 25 * time.Millisecond
   662  
   663  	// Create a long chain of blocks and simulate an invalid chain by dropping every second
   664  	hashes, blocks := makeChain(16*blockCacheLimit, 0, genesis)
   665  	gapped := make([]common.Hash, len(hashes)/2)
   666  	for i := 0; i < len(gapped); i++ {
   667  		gapped[i] = hashes[2*i]
   668  	}
   669  	// Try and sync with the malicious node and check that it fails
   670  	tester := newTester()
   671  	tester.newPeer("attack", eth60, gapped, blocks)
   672  	if err := tester.sync("attack", nil); err != errCrossCheckFailed {
   673  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errCrossCheckFailed)
   674  	}
   675  	// Ensure that a valid chain can still pass sync
   676  	blockSoftTTL = defaultBlockTTL
   677  	crossCheckCycle = defaultCrossCheckCycle
   678  
   679  	tester.newPeer("valid", eth60, hashes, blocks)
   680  	if err := tester.sync("valid", nil); err != nil {
   681  		t.Fatalf("failed to synchronise blocks: %v", err)
   682  	}
   683  }
   684  
   685  // Tests that if one/multiple malicious peers try to feed a banned blockchain to
   686  // the downloader, it will not keep refetching the same chain indefinitely, but
   687  // gradually block pieces of it, until its head is also blocked.
   688  func TestBannedChainStarvationAttack60(t *testing.T) {
   689  	n := 8 * blockCacheLimit
   690  	fork := n/2 - 23
   691  	hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis)
   692  
   693  	// Create the tester and ban the selected hash.
   694  	tester := newTester()
   695  	tester.downloader.banned.Add(forkHashes[fork-1])
   696  	tester.newPeer("valid", eth60, hashes, blocks)
   697  	tester.newPeer("attack", eth60, forkHashes, forkBlocks)
   698  
   699  	// Iteratively try to sync, and verify that the banned hash list grows until
   700  	// the head of the invalid chain is blocked too.
   701  	for banned := tester.downloader.banned.Size(); ; {
   702  		// Try to sync with the attacker, check hash chain failure
   703  		if err := tester.sync("attack", nil); err != errInvalidChain {
   704  			if tester.downloader.banned.Has(forkHashes[0]) && err == errBannedHead {
   705  				break
   706  			}
   707  			t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain)
   708  		}
   709  		// Check that the ban list grew with at least 1 new item, or all banned
   710  		bans := tester.downloader.banned.Size()
   711  		if bans < banned+1 {
   712  			t.Fatalf("ban count mismatch: have %v, want %v+", bans, banned+1)
   713  		}
   714  		banned = bans
   715  	}
   716  	// Check that after banning an entire chain, bad peers get dropped
   717  	if err := tester.newPeer("new attacker", eth60, forkHashes, forkBlocks); err != errBannedHead {
   718  		t.Fatalf("peer registration mismatch: have %v, want %v", err, errBannedHead)
   719  	}
   720  	if peer := tester.downloader.peers.Peer("new attacker"); peer != nil {
   721  		t.Fatalf("banned attacker registered: %v", peer)
   722  	}
   723  	// Ensure that a valid chain can still pass sync
   724  	if err := tester.sync("valid", nil); err != nil {
   725  		t.Fatalf("failed to synchronise blocks: %v", err)
   726  	}
   727  }
   728  
   729  // Tests that if a peer sends excessively many/large invalid chains that are
   730  // gradually banned, it will have an upper limit on the consumed memory and also
   731  // the origin bad hashes will not be evacuated.
   732  func TestBannedChainMemoryExhaustionAttack60(t *testing.T) {
   733  	// Construct a banned chain with more chunks than the ban limit
   734  	n := 8 * blockCacheLimit
   735  	fork := n/2 - 23
   736  	hashes, forkHashes, blocks, forkBlocks := makeChainFork(n, fork, genesis)
   737  
   738  	// Create the tester and ban the root hash of the fork.
   739  	tester := newTester()
   740  	tester.downloader.banned.Add(forkHashes[fork-1])
   741  
   742  	// Reduce the test size a bit
   743  	defaultMaxBlockFetch := MaxBlockFetch
   744  	defaultMaxBannedHashes := maxBannedHashes
   745  
   746  	MaxBlockFetch = 4
   747  	maxBannedHashes = 256
   748  
   749  	tester.newPeer("valid", eth60, hashes, blocks)
   750  	tester.newPeer("attack", eth60, forkHashes, forkBlocks)
   751  
   752  	// Iteratively try to sync, and verify that the banned hash list grows until
   753  	// the head of the invalid chain is blocked too.
   754  	for {
   755  		// Try to sync with the attacker, check hash chain failure
   756  		if err := tester.sync("attack", nil); err != errInvalidChain {
   757  			t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errInvalidChain)
   758  		}
   759  		// Short circuit if the entire chain was banned.
   760  		if tester.downloader.banned.Has(forkHashes[0]) {
   761  			break
   762  		}
   763  		// Otherwise ensure we never exceed the memory allowance and the hard coded bans are untouched
   764  		if bans := tester.downloader.banned.Size(); bans > maxBannedHashes {
   765  			t.Fatalf("ban cap exceeded: have %v, want max %v", bans, maxBannedHashes)
   766  		}
   767  		for hash := range core.BadHashes {
   768  			if !tester.downloader.banned.Has(hash) {
   769  				t.Fatalf("hard coded ban evacuated: %x", hash)
   770  			}
   771  		}
   772  	}
   773  	// Ensure that a valid chain can still pass sync
   774  	MaxBlockFetch = defaultMaxBlockFetch
   775  	maxBannedHashes = defaultMaxBannedHashes
   776  
   777  	if err := tester.sync("valid", nil); err != nil {
   778  		t.Fatalf("failed to synchronise blocks: %v", err)
   779  	}
   780  }
   781  
   782  // Tests a corner case (potential attack) where a peer delivers both good as well
   783  // as unrequested blocks to a hash request. This may trigger a different code
   784  // path than the fully correct or fully invalid delivery, potentially causing
   785  // internal state problems
   786  //
   787  // No, don't delete this test, it actually did happen!
   788  func TestOverlappingDeliveryAttack60(t *testing.T) {
   789  	// Create an arbitrary batch of blocks ( < cache-size not to block)
   790  	targetBlocks := blockCacheLimit - 23
   791  	hashes, blocks := makeChain(targetBlocks, 0, genesis)
   792  
   793  	// Register an attacker that always returns non-requested blocks too
   794  	tester := newTester()
   795  	tester.newPeer("attack", eth60, hashes, blocks)
   796  
   797  	rawGetBlocks := tester.downloader.peers.Peer("attack").getBlocks
   798  	tester.downloader.peers.Peer("attack").getBlocks = func(request []common.Hash) error {
   799  		// Add a non requested hash the screw the delivery (genesis should be fine)
   800  		return rawGetBlocks(append(request, hashes[0]))
   801  	}
   802  	// Test that synchronisation can complete, check for import success
   803  	if err := tester.sync("attack", nil); err != nil {
   804  		t.Fatalf("failed to synchronise blocks: %v", err)
   805  	}
   806  	start := time.Now()
   807  	for len(tester.ownHashes) != len(hashes) && time.Since(start) < time.Second {
   808  		time.Sleep(50 * time.Millisecond)
   809  	}
   810  	if len(tester.ownHashes) != len(hashes) {
   811  		t.Fatalf("chain length mismatch: have %v, want %v", len(tester.ownHashes), len(hashes))
   812  	}
   813  }
   814  
   815  // Tests that a peer advertising an high TD doesn't get to stall the downloader
   816  // afterwards by not sending any useful hashes.
   817  func TestHighTDStarvationAttack61(t *testing.T) {
   818  	tester := newTester()
   819  	tester.newPeer("attack", eth61, []common.Hash{genesis.Hash()}, nil)
   820  	if err := tester.sync("attack", big.NewInt(1000000)); err != errStallingPeer {
   821  		t.Fatalf("synchronisation error mismatch: have %v, want %v", err, errStallingPeer)
   822  	}
   823  }
   824  
   825  // Tests that misbehaving peers are disconnected, whilst behaving ones are not.
   826  func TestHashAttackerDropping(t *testing.T) {
   827  	// Define the disconnection requirement for individual hash fetch errors
   828  	tests := []struct {
   829  		result error
   830  		drop   bool
   831  	}{
   832  		{nil, false},                 // Sync succeeded, all is well
   833  		{errBusy, false},             // Sync is already in progress, no problem
   834  		{errUnknownPeer, false},      // Peer is unknown, was already dropped, don't double drop
   835  		{errBadPeer, true},           // Peer was deemed bad for some reason, drop it
   836  		{errStallingPeer, true},      // Peer was detected to be stalling, drop it
   837  		{errBannedHead, true},        // Peer's head hash is a known bad hash, drop it
   838  		{errNoPeers, false},          // No peers to download from, soft race, no issue
   839  		{errPendingQueue, false},     // There are blocks still cached, wait to exhaust, no issue
   840  		{errTimeout, true},           // No hashes received in due time, drop the peer
   841  		{errEmptyHashSet, true},      // No hashes were returned as a response, drop as it's a dead end
   842  		{errPeersUnavailable, true},  // Nobody had the advertised blocks, drop the advertiser
   843  		{errInvalidChain, true},      // Hash chain was detected as invalid, definitely drop
   844  		{errCrossCheckFailed, true},  // Hash-origin failed to pass a block cross check, drop
   845  		{errCancelHashFetch, false},  // Synchronisation was canceled, origin may be innocent, don't drop
   846  		{errCancelBlockFetch, false}, // Synchronisation was canceled, origin may be innocent, don't drop
   847  	}
   848  	// Run the tests and check disconnection status
   849  	tester := newTester()
   850  	for i, tt := range tests {
   851  		// Register a new peer and ensure it's presence
   852  		id := fmt.Sprintf("test %d", i)
   853  		if err := tester.newPeer(id, eth60, []common.Hash{genesis.Hash()}, nil); err != nil {
   854  			t.Fatalf("test %d: failed to register new peer: %v", i, err)
   855  		}
   856  		if _, ok := tester.peerHashes[id]; !ok {
   857  			t.Fatalf("test %d: registered peer not found", i)
   858  		}
   859  		// Simulate a synchronisation and check the required result
   860  		tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result }
   861  
   862  		tester.downloader.Synchronise(id, genesis.Hash(), big.NewInt(1000))
   863  		if _, ok := tester.peerHashes[id]; !ok != tt.drop {
   864  			t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop)
   865  		}
   866  	}
   867  }
   868  
   869  // Tests that feeding bad blocks will result in a peer drop.
   870  func TestBlockAttackerDropping(t *testing.T) {
   871  	// Define the disconnection requirement for individual block import errors
   872  	tests := []struct {
   873  		failure bool
   874  		drop    bool
   875  	}{
   876  		{true, true},
   877  		{false, false},
   878  	}
   879  
   880  	// Run the tests and check disconnection status
   881  	tester := newTester()
   882  	for i, tt := range tests {
   883  		// Register a new peer and ensure it's presence
   884  		id := fmt.Sprintf("test %d", i)
   885  		if err := tester.newPeer(id, eth60, []common.Hash{common.Hash{}}, nil); err != nil {
   886  			t.Fatalf("test %d: failed to register new peer: %v", i, err)
   887  		}
   888  		if _, ok := tester.peerHashes[id]; !ok {
   889  			t.Fatalf("test %d: registered peer not found", i)
   890  		}
   891  		// Assemble a good or bad block, depending of the test
   892  		raw := core.GenerateChain(genesis, testdb, 1, nil)[0]
   893  		if tt.failure {
   894  			parent := types.NewBlock(&types.Header{}, nil, nil, nil)
   895  			raw = core.GenerateChain(parent, testdb, 1, nil)[0]
   896  		}
   897  		block := &Block{OriginPeer: id, RawBlock: raw}
   898  
   899  		// Simulate block processing and check the result
   900  		tester.downloader.queue.blockCache[0] = block
   901  		tester.downloader.process()
   902  		if _, ok := tester.peerHashes[id]; !ok != tt.drop {
   903  			t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.failure, !ok, tt.drop)
   904  		}
   905  	}
   906  }