github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/eth/handler_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 eth
    18  
    19  import (
    20  	"fmt"
    21  	"math"
    22  	"math/big"
    23  	"math/rand"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/consensus"
    29  	"github.com/ethereum/go-ethereum/consensus/ethash"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/state"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/core/vm"
    34  	"github.com/ethereum/go-ethereum/crypto"
    35  	"github.com/ethereum/go-ethereum/eth/downloader"
    36  	"github.com/ethereum/go-ethereum/ethdb"
    37  	"github.com/ethereum/go-ethereum/event"
    38  	"github.com/ethereum/go-ethereum/p2p"
    39  	"github.com/ethereum/go-ethereum/params"
    40  )
    41  
    42  var bigTxGas = new(big.Int).SetUint64(params.TxGas)
    43  
    44  // Tests that protocol versions and modes of operations are matched up properly.
    45  func TestProtocolCompatibility(t *testing.T) {
    46  	// Define the compatibility chart
    47  	tests := []struct {
    48  		version    uint
    49  		mode       downloader.SyncMode
    50  		compatible bool
    51  	}{
    52  		{61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true},
    53  		{61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true},
    54  	}
    55  	// Make sure anything we screw up is restored
    56  	backup := consensus.EthProtocol.Versions
    57  	defer func() { consensus.EthProtocol.Versions = backup }()
    58  
    59  	// Try all available compatibility configs and check for errors
    60  	for i, tt := range tests {
    61  		consensus.EthProtocol.Versions = []uint{tt.version}
    62  
    63  		pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil)
    64  		if pm != nil {
    65  			defer pm.Stop()
    66  		}
    67  		if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
    68  			t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
    69  		}
    70  	}
    71  }
    72  
    73  // Tests that correct consensus mechanism details are returned in NodeInfo.
    74  func TestNodeInfo(t *testing.T) {
    75  
    76  	// Define the tests to be run
    77  	tests := []struct {
    78  		consensus      string
    79  		cliqueConfig   *params.CliqueConfig
    80  		istanbulConfig *params.IstanbulConfig
    81  		raftMode       bool
    82  	}{
    83  		{"ethash", nil, nil, false},
    84  		{"raft", nil, nil, true},
    85  		{"istanbul", nil, &params.IstanbulConfig{1, 1, big.NewInt(0)}, false},
    86  		{"clique", &params.CliqueConfig{1, 1}, nil, false},
    87  	}
    88  
    89  	// Make sure anything we screw up is restored
    90  	backup := consensus.EthProtocol.Versions
    91  	defer func() { consensus.EthProtocol.Versions = backup }()
    92  
    93  	// Try all available consensus mechanisms and check for errors
    94  	for i, tt := range tests {
    95  
    96  		pm, _, err := newTestProtocolManagerConsensus(tt.consensus, tt.cliqueConfig, tt.istanbulConfig, tt.raftMode)
    97  
    98  		if pm != nil {
    99  			defer pm.Stop()
   100  		}
   101  		if err == nil {
   102  			pmConsensus := pm.getConsensusAlgorithm()
   103  			if tt.consensus != pmConsensus {
   104  				t.Errorf("test %d: consensus type error, wanted %v but got %v", i, tt.consensus, pmConsensus)
   105  			}
   106  		} else {
   107  			t.Errorf("test %d: consensus type error %v", i, err)
   108  		}
   109  	}
   110  }
   111  
   112  // Tests that block headers can be retrieved from a remote chain based on user queries.
   113  func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
   114  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
   115  
   116  func testGetBlockHeaders(t *testing.T, protocol int) {
   117  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
   118  	peer, _ := newTestPeer("peer", protocol, pm, true)
   119  	defer peer.close()
   120  
   121  	// Create a "random" unknown hash for testing
   122  	var unknown common.Hash
   123  	for i := range unknown {
   124  		unknown[i] = byte(i)
   125  	}
   126  	// Create a batch of tests for various scenarios
   127  	limit := uint64(downloader.MaxHeaderFetch)
   128  	tests := []struct {
   129  		query  *getBlockHeadersData // The query to execute for header retrieval
   130  		expect []common.Hash        // The hashes of the block whose headers are expected
   131  	}{
   132  		// A single random block should be retrievable by hash and number too
   133  		{
   134  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
   135  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
   136  		}, {
   137  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
   138  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
   139  		},
   140  		// Multiple headers should be retrievable in both directions
   141  		{
   142  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
   143  			[]common.Hash{
   144  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   145  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
   146  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
   147  			},
   148  		}, {
   149  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
   150  			[]common.Hash{
   151  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   152  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
   153  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
   154  			},
   155  		},
   156  		// Multiple headers with skip lists should be retrievable
   157  		{
   158  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   159  			[]common.Hash{
   160  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   161  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
   162  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
   163  			},
   164  		}, {
   165  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   166  			[]common.Hash{
   167  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   168  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   169  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   170  			},
   171  		},
   172  		// The chain endpoints should be retrievable
   173  		{
   174  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   175  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   176  		}, {
   177  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   178  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   179  		},
   180  		// Ensure protocol limits are honored
   181  		{
   182  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   183  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   184  		},
   185  		// Check that requesting more than available is handled gracefully
   186  		{
   187  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   188  			[]common.Hash{
   189  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   190  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   191  			},
   192  		}, {
   193  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   194  			[]common.Hash{
   195  				pm.blockchain.GetBlockByNumber(4).Hash(),
   196  				pm.blockchain.GetBlockByNumber(0).Hash(),
   197  			},
   198  		},
   199  		// Check that requesting more than available is handled gracefully, even if mid skip
   200  		{
   201  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   202  			[]common.Hash{
   203  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   204  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   205  			},
   206  		}, {
   207  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   208  			[]common.Hash{
   209  				pm.blockchain.GetBlockByNumber(4).Hash(),
   210  				pm.blockchain.GetBlockByNumber(1).Hash(),
   211  			},
   212  		},
   213  		// Check a corner case where requesting more can iterate past the endpoints
   214  		{
   215  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   216  			[]common.Hash{
   217  				pm.blockchain.GetBlockByNumber(2).Hash(),
   218  				pm.blockchain.GetBlockByNumber(1).Hash(),
   219  				pm.blockchain.GetBlockByNumber(0).Hash(),
   220  			},
   221  		},
   222  		// Check a corner case where skipping overflow loops back into the chain start
   223  		{
   224  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   225  			[]common.Hash{
   226  				pm.blockchain.GetBlockByNumber(3).Hash(),
   227  			},
   228  		},
   229  		// Check a corner case where skipping overflow loops back to the same header
   230  		{
   231  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   232  			[]common.Hash{
   233  				pm.blockchain.GetBlockByNumber(1).Hash(),
   234  			},
   235  		},
   236  		// Check that non existing headers aren't returned
   237  		{
   238  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   239  			[]common.Hash{},
   240  		}, {
   241  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   242  			[]common.Hash{},
   243  		},
   244  	}
   245  	// Run each of the tests and verify the results against the chain
   246  	for i, tt := range tests {
   247  		// Collect the headers to expect in the response
   248  		headers := []*types.Header{}
   249  		for _, hash := range tt.expect {
   250  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   251  		}
   252  		// Send the hash request and verify the response
   253  		p2p.Send(peer.app, 0x03, tt.query)
   254  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   255  			t.Errorf("test %d: headers mismatch: %v", i, err)
   256  		}
   257  		// If the test used number origins, repeat with hashes as the too
   258  		if tt.query.Origin.Hash == (common.Hash{}) {
   259  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   260  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   261  
   262  				p2p.Send(peer.app, 0x03, tt.query)
   263  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   264  					t.Errorf("test %d: headers mismatch: %v", i, err)
   265  				}
   266  			}
   267  		}
   268  	}
   269  }
   270  
   271  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   272  func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) }
   273  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   274  
   275  func testGetBlockBodies(t *testing.T, protocol int) {
   276  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   277  	peer, _ := newTestPeer("peer", protocol, pm, true)
   278  	defer peer.close()
   279  
   280  	// Create a batch of tests for various scenarios
   281  	limit := downloader.MaxBlockFetch
   282  	tests := []struct {
   283  		random    int           // Number of blocks to fetch randomly from the chain
   284  		explicit  []common.Hash // Explicitly requested blocks
   285  		available []bool        // Availability of explicitly requested blocks
   286  		expected  int           // Total number of existing blocks to expect
   287  	}{
   288  		{1, nil, nil, 1},             // A single random block should be retrievable
   289  		{10, nil, nil, 10},           // Multiple random blocks should be retrievable
   290  		{limit, nil, nil, limit},     // The maximum possible blocks should be retrievable
   291  		{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
   292  		{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   293  		{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   294  		{0, []common.Hash{{}}, []bool{false}, 0},                                 // A non existent block should not be returned
   295  
   296  		// Existing and non-existing blocks interleaved should not cause problems
   297  		{0, []common.Hash{
   298  			{},
   299  			pm.blockchain.GetBlockByNumber(1).Hash(),
   300  			{},
   301  			pm.blockchain.GetBlockByNumber(10).Hash(),
   302  			{},
   303  			pm.blockchain.GetBlockByNumber(100).Hash(),
   304  			{},
   305  		}, []bool{false, true, false, true, false, true, false}, 3},
   306  	}
   307  	// Run each of the tests and verify the results against the chain
   308  	for i, tt := range tests {
   309  		// Collect the hashes to request, and the response to expect
   310  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   311  		bodies := []*blockBody{}
   312  
   313  		for j := 0; j < tt.random; j++ {
   314  			for {
   315  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   316  				if !seen[num] {
   317  					seen[num] = true
   318  
   319  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   320  					hashes = append(hashes, block.Hash())
   321  					if len(bodies) < tt.expected {
   322  						bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   323  					}
   324  					break
   325  				}
   326  			}
   327  		}
   328  		for j, hash := range tt.explicit {
   329  			hashes = append(hashes, hash)
   330  			if tt.available[j] && len(bodies) < tt.expected {
   331  				block := pm.blockchain.GetBlockByHash(hash)
   332  				bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   333  			}
   334  		}
   335  		// Send the hash request and verify the response
   336  		p2p.Send(peer.app, 0x05, hashes)
   337  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   338  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   339  		}
   340  	}
   341  }
   342  
   343  // Tests that the node state database can be retrieved based on hashes.
   344  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   345  
   346  func testGetNodeData(t *testing.T, protocol int) {
   347  	// Define three accounts to simulate transactions with
   348  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   349  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   350  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   351  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   352  
   353  	signer := types.HomesteadSigner{}
   354  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   355  	generator := func(i int, block *core.BlockGen) {
   356  		switch i {
   357  		case 0:
   358  			// In block 1, the test bank sends account #1 some ether.
   359  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   360  			block.AddTx(tx)
   361  		case 1:
   362  			// In block 2, the test bank sends some more ether to account #1.
   363  			// acc1Addr passes it on to account #2.
   364  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   365  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   366  			block.AddTx(tx1)
   367  			block.AddTx(tx2)
   368  		case 2:
   369  			// Block 3 is empty but was mined by account #2.
   370  			block.SetCoinbase(acc2Addr)
   371  			block.SetExtra([]byte("yeehaw"))
   372  		case 3:
   373  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   374  			b2 := block.PrevBlock(1).Header()
   375  			b2.Extra = []byte("foo")
   376  			block.AddUncle(b2)
   377  			b3 := block.PrevBlock(2).Header()
   378  			b3.Extra = []byte("foo")
   379  			block.AddUncle(b3)
   380  		}
   381  	}
   382  	// Assemble the test environment
   383  	pm, db := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   384  	peer, _ := newTestPeer("peer", protocol, pm, true)
   385  	defer peer.close()
   386  
   387  	// Fetch for now the entire chain db
   388  	hashes := []common.Hash{}
   389  	for _, key := range db.Keys() {
   390  		if len(key) == len(common.Hash{}) {
   391  			hashes = append(hashes, common.BytesToHash(key))
   392  		}
   393  	}
   394  	p2p.Send(peer.app, 0x0d, hashes)
   395  	msg, err := peer.app.ReadMsg()
   396  	if err != nil {
   397  		t.Fatalf("failed to read node data response: %v", err)
   398  	}
   399  	if msg.Code != 0x0e {
   400  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   401  	}
   402  	var data [][]byte
   403  	if err := msg.Decode(&data); err != nil {
   404  		t.Fatalf("failed to decode response node data: %v", err)
   405  	}
   406  	// Verify that all hashes correspond to the requested data, and reconstruct a state tree
   407  	for i, want := range hashes {
   408  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   409  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   410  		}
   411  	}
   412  	statedb := ethdb.NewMemDatabase()
   413  	for i := 0; i < len(data); i++ {
   414  		statedb.Put(hashes[i].Bytes(), data[i])
   415  	}
   416  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   417  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   418  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb))
   419  
   420  		for j, acc := range accounts {
   421  			state, _, _ := pm.blockchain.State()
   422  			bw := state.GetBalance(acc)
   423  			bh := trie.GetBalance(acc)
   424  
   425  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   426  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   427  			}
   428  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   429  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   430  			}
   431  		}
   432  	}
   433  }
   434  
   435  // Tests that the transaction receipts can be retrieved based on hashes.
   436  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   437  
   438  func testGetReceipt(t *testing.T, protocol int) {
   439  	// Define three accounts to simulate transactions with
   440  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   441  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   442  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   443  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   444  
   445  	signer := types.HomesteadSigner{}
   446  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   447  	generator := func(i int, block *core.BlockGen) {
   448  		switch i {
   449  		case 0:
   450  			// In block 1, the test bank sends account #1 some ether.
   451  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   452  			block.AddTx(tx)
   453  		case 1:
   454  			// In block 2, the test bank sends some more ether to account #1.
   455  			// acc1Addr passes it on to account #2.
   456  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   457  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   458  			block.AddTx(tx1)
   459  			block.AddTx(tx2)
   460  		case 2:
   461  			// Block 3 is empty but was mined by account #2.
   462  			block.SetCoinbase(acc2Addr)
   463  			block.SetExtra([]byte("yeehaw"))
   464  		case 3:
   465  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   466  			b2 := block.PrevBlock(1).Header()
   467  			b2.Extra = []byte("foo")
   468  			block.AddUncle(b2)
   469  			b3 := block.PrevBlock(2).Header()
   470  			b3.Extra = []byte("foo")
   471  			block.AddUncle(b3)
   472  		}
   473  	}
   474  	// Assemble the test environment
   475  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   476  	peer, _ := newTestPeer("peer", protocol, pm, true)
   477  	defer peer.close()
   478  
   479  	// Collect the hashes to request, and the response to expect
   480  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   481  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   482  		block := pm.blockchain.GetBlockByNumber(i)
   483  
   484  		hashes = append(hashes, block.Hash())
   485  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   486  	}
   487  	// Send the hash request and verify the response
   488  	p2p.Send(peer.app, 0x0f, hashes)
   489  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   490  		t.Errorf("receipts mismatch: %v", err)
   491  	}
   492  }
   493  
   494  // Tests that post eth protocol handshake, DAO fork-enabled clients also execute
   495  // a DAO "challenge" verifying each others' DAO fork headers to ensure they're on
   496  // compatible chains.
   497  func TestDAOChallengeNoVsNo(t *testing.T)       { testDAOChallenge(t, false, false, false) }
   498  func TestDAOChallengeNoVsPro(t *testing.T)      { testDAOChallenge(t, false, true, false) }
   499  func TestDAOChallengeProVsNo(t *testing.T)      { testDAOChallenge(t, true, false, false) }
   500  func TestDAOChallengeProVsPro(t *testing.T)     { testDAOChallenge(t, true, true, false) }
   501  func TestDAOChallengeNoVsTimeout(t *testing.T)  { testDAOChallenge(t, false, false, true) }
   502  func TestDAOChallengeProVsTimeout(t *testing.T) { testDAOChallenge(t, true, true, true) }
   503  
   504  func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool) {
   505  	// Reduce the DAO handshake challenge timeout
   506  	if timeout {
   507  		defer func(old time.Duration) { daoChallengeTimeout = old }(daoChallengeTimeout)
   508  		daoChallengeTimeout = 500 * time.Millisecond
   509  	}
   510  	// Create a DAO aware protocol manager
   511  	var (
   512  		evmux   = new(event.TypeMux)
   513  		pow     = ethash.NewFaker()
   514  		db      = ethdb.NewMemDatabase()
   515  		config  = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
   516  		gspec   = &core.Genesis{Config: config}
   517  		genesis = gspec.MustCommit(db)
   518  	)
   519  	blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
   520  	if err != nil {
   521  		t.Fatalf("failed to create new blockchain: %v", err)
   522  	}
   523  	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, false)
   524  	if err != nil {
   525  		t.Fatalf("failed to start test protocol manager: %v", err)
   526  	}
   527  	pm.Start(1000)
   528  	defer pm.Stop()
   529  
   530  	// Connect a new peer and check that we receive the DAO challenge
   531  	peer, _ := newTestPeer("peer", consensus.Eth63, pm, true)
   532  	defer peer.close()
   533  
   534  	challenge := &getBlockHeadersData{
   535  		Origin:  hashOrNumber{Number: config.DAOForkBlock.Uint64()},
   536  		Amount:  1,
   537  		Skip:    0,
   538  		Reverse: false,
   539  	}
   540  	if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil {
   541  		t.Fatalf("challenge mismatch: %v", err)
   542  	}
   543  	// Create a block to reply to the challenge if no timeout is simulated
   544  	if !timeout {
   545  		blocks, _ := core.GenerateChain(&params.ChainConfig{}, genesis, ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) {
   546  			if remoteForked {
   547  				block.SetExtra(params.DAOForkBlockExtra)
   548  			}
   549  		})
   550  		if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{blocks[0].Header()}); err != nil {
   551  			t.Fatalf("failed to answer challenge: %v", err)
   552  		}
   553  		time.Sleep(100 * time.Millisecond) // Sleep to avoid the verification racing with the drops
   554  	} else {
   555  		// Otherwise wait until the test timeout passes
   556  		time.Sleep(daoChallengeTimeout + 500*time.Millisecond)
   557  	}
   558  	// Verify that depending on fork side, the remote peer is maintained or dropped
   559  	if localForked == remoteForked && !timeout {
   560  		if peers := pm.peers.Len(); peers != 1 {
   561  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
   562  		}
   563  	} else {
   564  		if peers := pm.peers.Len(); peers != 0 {
   565  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
   566  		}
   567  	}
   568  }
   569  
   570  func TestBroadcastBlock(t *testing.T) {
   571  	var tests = []struct {
   572  		totalPeers        int
   573  		broadcastExpected int
   574  	}{
   575  		{1, 1},
   576  		{2, 2},
   577  		{3, 3},
   578  		{4, 4},
   579  		{5, 4},
   580  		{9, 4},
   581  		{12, 4},
   582  		{16, 4},
   583  		{26, 5},
   584  		{100, 10},
   585  	}
   586  	for _, test := range tests {
   587  		testBroadcastBlock(t, test.totalPeers, test.broadcastExpected)
   588  	}
   589  }
   590  
   591  func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
   592  	var (
   593  		evmux   = new(event.TypeMux)
   594  		pow     = ethash.NewFaker()
   595  		db      = ethdb.NewMemDatabase()
   596  		config  = &params.ChainConfig{}
   597  		gspec   = &core.Genesis{Config: config}
   598  		genesis = gspec.MustCommit(db)
   599  	)
   600  	blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
   601  	if err != nil {
   602  		t.Fatalf("failed to create new blockchain: %v", err)
   603  	}
   604  	pm, err := NewProtocolManager(config, downloader.FullSync, DefaultConfig.NetworkId, evmux, new(testTxPool), pow, blockchain, db, false)
   605  	if err != nil {
   606  		t.Fatalf("failed to start test protocol manager: %v", err)
   607  	}
   608  	pm.Start(1000)
   609  	defer pm.Stop()
   610  	var peers []*testPeer
   611  	for i := 0; i < totalPeers; i++ {
   612  		peer, _ := newTestPeer(fmt.Sprintf("peer %d", i), eth63, pm, true)
   613  		defer peer.close()
   614  		peers = append(peers, peer)
   615  	}
   616  	chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {})
   617  	pm.BroadcastBlock(chain[0], true /*propagate*/)
   618  
   619  	errCh := make(chan error, totalPeers)
   620  	doneCh := make(chan struct{}, totalPeers)
   621  	for _, peer := range peers {
   622  		go func(p *testPeer) {
   623  			if err := p2p.ExpectMsg(p.app, NewBlockMsg, &newBlockData{Block: chain[0], TD: big.NewInt(131136)}); err != nil {
   624  				errCh <- err
   625  			} else {
   626  				doneCh <- struct{}{}
   627  			}
   628  		}(peer)
   629  	}
   630  	timeoutCh := time.NewTimer(time.Millisecond * 100).C
   631  	var receivedCount int
   632  outer:
   633  	for {
   634  		select {
   635  		case err = <-errCh:
   636  			break outer
   637  		case <-doneCh:
   638  			receivedCount++
   639  			if receivedCount == totalPeers {
   640  				break outer
   641  			}
   642  		case <-timeoutCh:
   643  			break outer
   644  		}
   645  	}
   646  	for _, peer := range peers {
   647  		peer.app.Close()
   648  	}
   649  	if err != nil {
   650  		t.Errorf("error matching block by peer: %v", err)
   651  	}
   652  	if receivedCount != broadcastExpected {
   653  		t.Errorf("block broadcast to %d peers, expected %d", receivedCount, broadcastExpected)
   654  	}
   655  }