github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/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  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/kisexp/xdchain/common"
    29  	"github.com/kisexp/xdchain/consensus"
    30  	"github.com/kisexp/xdchain/consensus/ethash"
    31  	"github.com/kisexp/xdchain/core"
    32  	"github.com/kisexp/xdchain/core/rawdb"
    33  	"github.com/kisexp/xdchain/core/state"
    34  	"github.com/kisexp/xdchain/core/types"
    35  	"github.com/kisexp/xdchain/core/vm"
    36  	"github.com/kisexp/xdchain/crypto"
    37  	"github.com/kisexp/xdchain/eth/downloader"
    38  	"github.com/kisexp/xdchain/event"
    39  	"github.com/kisexp/xdchain/p2p"
    40  	"github.com/kisexp/xdchain/params"
    41  )
    42  
    43  // Tests that correct consensus mechanism details are returned in NodeInfo.
    44  func TestNodeInfo(t *testing.T) {
    45  
    46  	// Define the tests to be run
    47  	tests := []struct {
    48  		consensus      string
    49  		cliqueConfig   *params.CliqueConfig
    50  		istanbulConfig *params.IstanbulConfig
    51  		raftMode       bool
    52  	}{
    53  		{"ethash", nil, nil, false},
    54  		{"raft", nil, nil, true},
    55  		{"istanbul", nil, &params.IstanbulConfig{Epoch: 1, ProposerPolicy: 1, Ceil2Nby3Block: big.NewInt(0), TestQBFTBlock: big.NewInt(0)}, false},
    56  		{"clique", &params.CliqueConfig{Period: 1, Epoch: 1}, nil, false},
    57  	}
    58  
    59  	// Make sure anything we screw up is restored
    60  	backup := consensus.EthProtocol.Versions
    61  	defer func() { consensus.EthProtocol.Versions = backup }()
    62  
    63  	// Try all available consensus mechanisms and check for errors
    64  	for i, tt := range tests {
    65  
    66  		pm, _, err := newTestProtocolManagerConsensus(tt.consensus, tt.cliqueConfig, tt.istanbulConfig, tt.raftMode)
    67  
    68  		if pm != nil {
    69  			defer pm.Stop()
    70  		}
    71  		if err == nil {
    72  			pmConsensus := pm.getConsensusAlgorithm()
    73  			if tt.consensus != pmConsensus {
    74  				t.Errorf("test %d: consensus type error, wanted %v but got %v", i, tt.consensus, pmConsensus)
    75  			}
    76  		} else {
    77  			t.Errorf("test %d: consensus type error %v", i, err)
    78  		}
    79  	}
    80  }
    81  
    82  // Tests that block headers can be retrieved from a remote chain based on user queries.
    83  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
    84  func TestGetBlockHeaders64(t *testing.T) { testGetBlockHeaders(t, 64) }
    85  
    86  func testGetBlockHeaders(t *testing.T, protocol int) {
    87  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
    88  	peer, _ := newTestPeer("peer", protocol, pm, true)
    89  	defer peer.close()
    90  
    91  	// Create a "random" unknown hash for testing
    92  	var unknown common.Hash
    93  	for i := range unknown {
    94  		unknown[i] = byte(i)
    95  	}
    96  	// Create a batch of tests for various scenarios
    97  	limit := uint64(downloader.MaxHeaderFetch)
    98  	tests := []struct {
    99  		query  *getBlockHeadersData // The query to execute for header retrieval
   100  		expect []common.Hash        // The hashes of the block whose headers are expected
   101  	}{
   102  		// A single random block should be retrievable by hash and number too
   103  		{
   104  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
   105  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
   106  		}, {
   107  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
   108  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
   109  		},
   110  		// Multiple headers should be retrievable in both directions
   111  		{
   112  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
   113  			[]common.Hash{
   114  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   115  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
   116  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
   117  			},
   118  		}, {
   119  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
   120  			[]common.Hash{
   121  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   122  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
   123  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
   124  			},
   125  		},
   126  		// Multiple headers with skip lists should be retrievable
   127  		{
   128  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   129  			[]common.Hash{
   130  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   131  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
   132  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
   133  			},
   134  		}, {
   135  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   136  			[]common.Hash{
   137  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   138  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   139  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   140  			},
   141  		},
   142  		// The chain endpoints should be retrievable
   143  		{
   144  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   145  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   146  		}, {
   147  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   148  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   149  		},
   150  		// Ensure protocol limits are honored
   151  		{
   152  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   153  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   154  		},
   155  		// Check that requesting more than available is handled gracefully
   156  		{
   157  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   158  			[]common.Hash{
   159  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   160  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   161  			},
   162  		}, {
   163  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   164  			[]common.Hash{
   165  				pm.blockchain.GetBlockByNumber(4).Hash(),
   166  				pm.blockchain.GetBlockByNumber(0).Hash(),
   167  			},
   168  		},
   169  		// Check that requesting more than available is handled gracefully, even if mid skip
   170  		{
   171  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   172  			[]common.Hash{
   173  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   174  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   175  			},
   176  		}, {
   177  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   178  			[]common.Hash{
   179  				pm.blockchain.GetBlockByNumber(4).Hash(),
   180  				pm.blockchain.GetBlockByNumber(1).Hash(),
   181  			},
   182  		},
   183  		// Check a corner case where requesting more can iterate past the endpoints
   184  		{
   185  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   186  			[]common.Hash{
   187  				pm.blockchain.GetBlockByNumber(2).Hash(),
   188  				pm.blockchain.GetBlockByNumber(1).Hash(),
   189  				pm.blockchain.GetBlockByNumber(0).Hash(),
   190  			},
   191  		},
   192  		// Check a corner case where skipping overflow loops back into the chain start
   193  		{
   194  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   195  			[]common.Hash{
   196  				pm.blockchain.GetBlockByNumber(3).Hash(),
   197  			},
   198  		},
   199  		// Check a corner case where skipping overflow loops back to the same header
   200  		{
   201  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   202  			[]common.Hash{
   203  				pm.blockchain.GetBlockByNumber(1).Hash(),
   204  			},
   205  		},
   206  		// Check that non existing headers aren't returned
   207  		{
   208  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   209  			[]common.Hash{},
   210  		}, {
   211  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   212  			[]common.Hash{},
   213  		},
   214  	}
   215  	// Run each of the tests and verify the results against the chain
   216  	for i, tt := range tests {
   217  		// Collect the headers to expect in the response
   218  		headers := []*types.Header{}
   219  		for _, hash := range tt.expect {
   220  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   221  		}
   222  		// Send the hash request and verify the response
   223  		p2p.Send(peer.app, 0x03, tt.query)
   224  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   225  			t.Errorf("test %d: headers mismatch: %v", i, err)
   226  		}
   227  		// If the test used number origins, repeat with hashes as the too
   228  		if tt.query.Origin.Hash == (common.Hash{}) {
   229  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   230  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   231  
   232  				p2p.Send(peer.app, 0x03, tt.query)
   233  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   234  					t.Errorf("test %d: headers mismatch: %v", i, err)
   235  				}
   236  			}
   237  		}
   238  	}
   239  }
   240  
   241  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   242  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   243  func TestGetBlockBodies64(t *testing.T) { testGetBlockBodies(t, 64) }
   244  
   245  func testGetBlockBodies(t *testing.T, protocol int) {
   246  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   247  	peer, _ := newTestPeer("peer", protocol, pm, true)
   248  	defer peer.close()
   249  
   250  	// Create a batch of tests for various scenarios
   251  	limit := downloader.MaxBlockFetch
   252  	tests := []struct {
   253  		random    int           // Number of blocks to fetch randomly from the chain
   254  		explicit  []common.Hash // Explicitly requested blocks
   255  		available []bool        // Availability of explicitly requested blocks
   256  		expected  int           // Total number of existing blocks to expect
   257  	}{
   258  		{1, nil, nil, 1},             // A single random block should be retrievable
   259  		{10, nil, nil, 10},           // Multiple random blocks should be retrievable
   260  		{limit, nil, nil, limit},     // The maximum possible blocks should be retrievable
   261  		{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
   262  		{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   263  		{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   264  		{0, []common.Hash{{}}, []bool{false}, 0},                                 // A non existent block should not be returned
   265  
   266  		// Existing and non-existing blocks interleaved should not cause problems
   267  		{0, []common.Hash{
   268  			{},
   269  			pm.blockchain.GetBlockByNumber(1).Hash(),
   270  			{},
   271  			pm.blockchain.GetBlockByNumber(10).Hash(),
   272  			{},
   273  			pm.blockchain.GetBlockByNumber(100).Hash(),
   274  			{},
   275  		}, []bool{false, true, false, true, false, true, false}, 3},
   276  	}
   277  	// Run each of the tests and verify the results against the chain
   278  	for i, tt := range tests {
   279  		// Collect the hashes to request, and the response to expect
   280  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   281  		bodies := []*blockBody{}
   282  
   283  		for j := 0; j < tt.random; j++ {
   284  			for {
   285  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   286  				if !seen[num] {
   287  					seen[num] = true
   288  
   289  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   290  					hashes = append(hashes, block.Hash())
   291  					if len(bodies) < tt.expected {
   292  						bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   293  					}
   294  					break
   295  				}
   296  			}
   297  		}
   298  		for j, hash := range tt.explicit {
   299  			hashes = append(hashes, hash)
   300  			if tt.available[j] && len(bodies) < tt.expected {
   301  				block := pm.blockchain.GetBlockByHash(hash)
   302  				bodies = append(bodies, &blockBody{Transactions: block.Transactions(), Uncles: block.Uncles()})
   303  			}
   304  		}
   305  		// Send the hash request and verify the response
   306  		p2p.Send(peer.app, 0x05, hashes)
   307  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   308  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   309  		}
   310  	}
   311  }
   312  
   313  // Tests that the node state database can be retrieved based on hashes.
   314  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   315  func TestGetNodeData64(t *testing.T) { testGetNodeData(t, 64) }
   316  
   317  func testGetNodeData(t *testing.T, protocol int) {
   318  	// Define three accounts to simulate transactions with
   319  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   320  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   321  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   322  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   323  
   324  	signer := types.HomesteadSigner{}
   325  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   326  	generator := func(i int, block *core.BlockGen) {
   327  		switch i {
   328  		case 0:
   329  			// In block 1, the test bank sends account #1 some ether.
   330  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   331  			block.AddTx(tx)
   332  		case 1:
   333  			// In block 2, the test bank sends some more ether to account #1.
   334  			// acc1Addr passes it on to account #2.
   335  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   336  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   337  			block.AddTx(tx1)
   338  			block.AddTx(tx2)
   339  		case 2:
   340  			// Block 3 is empty but was mined by account #2.
   341  			block.SetCoinbase(acc2Addr)
   342  			block.SetExtra([]byte("yeehaw"))
   343  		case 3:
   344  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   345  			b2 := block.PrevBlock(1).Header()
   346  			b2.Extra = []byte("foo")
   347  			block.AddUncle(b2)
   348  			b3 := block.PrevBlock(2).Header()
   349  			b3.Extra = []byte("foo")
   350  			block.AddUncle(b3)
   351  		}
   352  	}
   353  	// Assemble the test environment
   354  	pm, db := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   355  	peer, _ := newTestPeer("peer", protocol, pm, true)
   356  	defer peer.close()
   357  
   358  	// Fetch for now the entire chain db
   359  	hashes := []common.Hash{}
   360  
   361  	it := db.NewIterator(nil, nil)
   362  	for it.Next() {
   363  		if key := it.Key(); len(key) == common.HashLength {
   364  			hashes = append(hashes, common.BytesToHash(key))
   365  		}
   366  	}
   367  	it.Release()
   368  
   369  	p2p.Send(peer.app, 0x0d, hashes)
   370  	msg, err := peer.app.ReadMsg()
   371  	if err != nil {
   372  		t.Fatalf("failed to read node data response: %v", err)
   373  	}
   374  	if msg.Code != 0x0e {
   375  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   376  	}
   377  	var data [][]byte
   378  	if err := msg.Decode(&data); err != nil {
   379  		t.Fatalf("failed to decode response node data: %v", err)
   380  	}
   381  	// Verify that all hashes correspond to the requested data, and reconstruct a state tree
   382  	for i, want := range hashes {
   383  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   384  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   385  		}
   386  	}
   387  	statedb := rawdb.NewMemoryDatabase()
   388  	for i := 0; i < len(data); i++ {
   389  		statedb.Put(hashes[i].Bytes(), data[i])
   390  	}
   391  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   392  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   393  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb), nil)
   394  
   395  		for j, acc := range accounts {
   396  			state, _, _ := pm.blockchain.State()
   397  			bw := state.GetBalance(acc)
   398  			bh := trie.GetBalance(acc)
   399  
   400  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   401  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   402  			}
   403  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   404  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   405  			}
   406  		}
   407  	}
   408  }
   409  
   410  // Tests that the transaction receipts can be retrieved based on hashes.
   411  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   412  func TestGetReceipt64(t *testing.T) { testGetReceipt(t, 64) }
   413  
   414  func testGetReceipt(t *testing.T, protocol int) {
   415  	// Define three accounts to simulate transactions with
   416  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   417  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   418  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   419  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   420  
   421  	signer := types.HomesteadSigner{}
   422  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   423  	generator := func(i int, block *core.BlockGen) {
   424  		switch i {
   425  		case 0:
   426  			// In block 1, the test bank sends account #1 some ether.
   427  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   428  			block.AddTx(tx)
   429  		case 1:
   430  			// In block 2, the test bank sends some more ether to account #1.
   431  			// acc1Addr passes it on to account #2.
   432  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   433  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   434  			block.AddTx(tx1)
   435  			block.AddTx(tx2)
   436  		case 2:
   437  			// Block 3 is empty but was mined by account #2.
   438  			block.SetCoinbase(acc2Addr)
   439  			block.SetExtra([]byte("yeehaw"))
   440  		case 3:
   441  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   442  			b2 := block.PrevBlock(1).Header()
   443  			b2.Extra = []byte("foo")
   444  			block.AddUncle(b2)
   445  			b3 := block.PrevBlock(2).Header()
   446  			b3.Extra = []byte("foo")
   447  			block.AddUncle(b3)
   448  		}
   449  	}
   450  	// Assemble the test environment
   451  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   452  	peer, _ := newTestPeer("peer", protocol, pm, true)
   453  	defer peer.close()
   454  
   455  	// Collect the hashes to request, and the response to expect
   456  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   457  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   458  		block := pm.blockchain.GetBlockByNumber(i)
   459  
   460  		hashes = append(hashes, block.Hash())
   461  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   462  	}
   463  	// Send the hash request and verify the response
   464  	p2p.Send(peer.app, 0x0f, hashes)
   465  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   466  		t.Errorf("receipts mismatch: %v", err)
   467  	}
   468  }
   469  
   470  // Tests that post eth protocol handshake, clients perform a mutual checkpoint
   471  // challenge to validate each other's chains. Hash mismatches, or missing ones
   472  // during a fast sync should lead to the peer getting dropped.
   473  func TestCheckpointChallenge(t *testing.T) {
   474  	tests := []struct {
   475  		syncmode   downloader.SyncMode
   476  		checkpoint bool
   477  		timeout    bool
   478  		empty      bool
   479  		match      bool
   480  		drop       bool
   481  	}{
   482  		// If checkpointing is not enabled locally, don't challenge and don't drop
   483  		{downloader.FullSync, false, false, false, false, false},
   484  		{downloader.FastSync, false, false, false, false, false},
   485  
   486  		// If checkpointing is enabled locally and remote response is empty, only drop during fast sync
   487  		{downloader.FullSync, true, false, true, false, false},
   488  		{downloader.FastSync, true, false, true, false, true}, // Special case, fast sync, unsynced peer
   489  
   490  		// If checkpointing is enabled locally and remote response mismatches, always drop
   491  		{downloader.FullSync, true, false, false, false, true},
   492  		{downloader.FastSync, true, false, false, false, true},
   493  
   494  		// If checkpointing is enabled locally and remote response matches, never drop
   495  		{downloader.FullSync, true, false, false, true, false},
   496  		{downloader.FastSync, true, false, false, true, false},
   497  
   498  		// If checkpointing is enabled locally and remote times out, always drop
   499  		{downloader.FullSync, true, true, false, true, true},
   500  		{downloader.FastSync, true, true, false, true, true},
   501  	}
   502  	for _, tt := range tests {
   503  		t.Run(fmt.Sprintf("sync %v checkpoint %v timeout %v empty %v match %v", tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match), func(t *testing.T) {
   504  			testCheckpointChallenge(t, tt.syncmode, tt.checkpoint, tt.timeout, tt.empty, tt.match, tt.drop)
   505  		})
   506  	}
   507  }
   508  
   509  func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpoint bool, timeout bool, empty bool, match bool, drop bool) {
   510  	// Reduce the checkpoint handshake challenge timeout
   511  	defer func(old time.Duration) { syncChallengeTimeout = old }(syncChallengeTimeout)
   512  	syncChallengeTimeout = 250 * time.Millisecond
   513  
   514  	// Initialize a chain and generate a fake CHT if checkpointing is enabled
   515  	var (
   516  		db     = rawdb.NewMemoryDatabase()
   517  		config = new(params.ChainConfig)
   518  	)
   519  	(&core.Genesis{Config: config}).MustCommit(db) // Commit genesis block
   520  	// If checkpointing is enabled, create and inject a fake CHT and the corresponding
   521  	// chllenge response.
   522  	var response *types.Header
   523  	var cht *params.TrustedCheckpoint
   524  	if checkpoint {
   525  		index := uint64(rand.Intn(500))
   526  		number := (index+1)*params.CHTFrequency - 1
   527  		response = &types.Header{Number: big.NewInt(int64(number)), Extra: []byte("valid")}
   528  
   529  		cht = &params.TrustedCheckpoint{
   530  			SectionIndex: index,
   531  			SectionHead:  response.Hash(),
   532  		}
   533  	}
   534  	// Create a checkpoint aware protocol manager
   535  	blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil, nil, nil)
   536  	if err != nil {
   537  		t.Fatalf("failed to create new blockchain: %v", err)
   538  	}
   539  	pm, err := NewProtocolManager(config, cht, syncmode, DefaultConfig.NetworkId, new(event.TypeMux), &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, ethash.NewFaker(), blockchain, db, 1, nil, false)
   540  	if err != nil {
   541  		t.Fatalf("failed to start test protocol manager: %v", err)
   542  	}
   543  	pm.Start(1000)
   544  	defer pm.Stop()
   545  
   546  	// Connect a new peer and check that we receive the checkpoint challenge
   547  	peer, _ := newTestPeer("peer", eth63, pm, true)
   548  	defer peer.close()
   549  
   550  	if checkpoint {
   551  		challenge := &getBlockHeadersData{
   552  			Origin:  hashOrNumber{Number: response.Number.Uint64()},
   553  			Amount:  1,
   554  			Skip:    0,
   555  			Reverse: false,
   556  		}
   557  		if err := p2p.ExpectMsg(peer.app, GetBlockHeadersMsg, challenge); err != nil {
   558  			t.Fatalf("challenge mismatch: %v", err)
   559  		}
   560  		// Create a block to reply to the challenge if no timeout is simulated
   561  		if !timeout {
   562  			if empty {
   563  				if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{}); err != nil {
   564  					t.Fatalf("failed to answer challenge: %v", err)
   565  				}
   566  			} else if match {
   567  				if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{response}); err != nil {
   568  					t.Fatalf("failed to answer challenge: %v", err)
   569  				}
   570  			} else {
   571  				if err := p2p.Send(peer.app, BlockHeadersMsg, []*types.Header{{Number: response.Number}}); err != nil {
   572  					t.Fatalf("failed to answer challenge: %v", err)
   573  				}
   574  			}
   575  		}
   576  	}
   577  	// Wait until the test timeout passes to ensure proper cleanup
   578  	time.Sleep(syncChallengeTimeout + 300*time.Millisecond)
   579  
   580  	// Verify that the remote peer is maintained or dropped
   581  	if drop {
   582  		if peers := pm.peers.Len(); peers != 0 {
   583  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 0)
   584  		}
   585  	} else {
   586  		if peers := pm.peers.Len(); peers != 1 {
   587  			t.Fatalf("peer count mismatch: have %d, want %d", peers, 1)
   588  		}
   589  	}
   590  }
   591  
   592  func TestBroadcastBlock(t *testing.T) {
   593  	var tests = []struct {
   594  		totalPeers        int
   595  		broadcastExpected int
   596  	}{
   597  		{1, 1},
   598  		{2, 1},
   599  		{3, 1},
   600  		{4, 2},
   601  		{5, 2},
   602  		{9, 3},
   603  		{12, 3},
   604  		{16, 4},
   605  		{26, 5},
   606  		{100, 10},
   607  	}
   608  	for _, test := range tests {
   609  		testBroadcastBlock(t, test.totalPeers, test.broadcastExpected)
   610  	}
   611  }
   612  
   613  func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
   614  	var (
   615  		evmux   = new(event.TypeMux)
   616  		pow     = ethash.NewFaker()
   617  		db      = rawdb.NewMemoryDatabase()
   618  		config  = &params.ChainConfig{}
   619  		gspec   = &core.Genesis{Config: config}
   620  		genesis = gspec.MustCommit(db)
   621  	)
   622  	blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil, nil, nil)
   623  	if err != nil {
   624  		t.Fatalf("failed to create new blockchain: %v", err)
   625  	}
   626  	pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, evmux, &testTxPool{pool: make(map[common.Hash]*types.Transaction)}, pow, blockchain, db, 1, nil, false)
   627  	if err != nil {
   628  		t.Fatalf("failed to start test protocol manager: %v", err)
   629  	}
   630  	pm.Start(1000)
   631  	defer pm.Stop()
   632  	var peers []*testPeer
   633  	for i := 0; i < totalPeers; i++ {
   634  		peer, _ := newTestPeer(fmt.Sprintf("peer %d", i), eth63, pm, true)
   635  		defer peer.close()
   636  
   637  		peers = append(peers, peer)
   638  	}
   639  	chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {})
   640  	pm.BroadcastBlock(chain[0], true /*propagate*/)
   641  
   642  	errCh := make(chan error, totalPeers)
   643  	doneCh := make(chan struct{}, totalPeers)
   644  	for _, peer := range peers {
   645  		go func(p *testPeer) {
   646  			if err := p2p.ExpectMsg(p.app, NewBlockMsg, &newBlockData{Block: chain[0], TD: big.NewInt(131136)}); err != nil {
   647  				errCh <- err
   648  			} else {
   649  				doneCh <- struct{}{}
   650  			}
   651  		}(peer)
   652  	}
   653  	var received int
   654  	for {
   655  		select {
   656  		case <-doneCh:
   657  			received++
   658  			if received > broadcastExpected {
   659  				// We can bail early here
   660  				t.Errorf("broadcast count mismatch: have %d > want %d", received, broadcastExpected)
   661  				return
   662  			}
   663  		case <-time.After(2 * time.Second):
   664  			if received != broadcastExpected {
   665  				t.Errorf("broadcast count mismatch: have %d, want %d", received, broadcastExpected)
   666  			}
   667  			return
   668  		case err = <-errCh:
   669  			t.Fatalf("broadcast failed: %v", err)
   670  		}
   671  	}
   672  
   673  }
   674  
   675  // Tests that a propagated malformed block (uncles or transactions don't match
   676  // with the hashes in the header) gets discarded and not broadcast forward.
   677  func TestBroadcastMalformedBlock(t *testing.T) {
   678  	// Create a live node to test propagation with
   679  	var (
   680  		engine  = ethash.NewFaker()
   681  		db      = rawdb.NewMemoryDatabase()
   682  		config  = &params.ChainConfig{}
   683  		gspec   = &core.Genesis{Config: config}
   684  		genesis = gspec.MustCommit(db)
   685  	)
   686  	blockchain, err := core.NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, nil)
   687  	if err != nil {
   688  		t.Fatalf("failed to create new blockchain: %v", err)
   689  	}
   690  	pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, new(event.TypeMux), new(testTxPool), engine, blockchain, db, 1, nil, false)
   691  	if err != nil {
   692  		t.Fatalf("failed to start test protocol manager: %v", err)
   693  	}
   694  	pm.Start(2)
   695  	defer pm.Stop()
   696  
   697  	// Create two peers, one to send the malformed block with and one to check
   698  	// propagation
   699  	source, _ := newTestPeer("source", eth63, pm, true)
   700  	defer source.close()
   701  
   702  	sink, _ := newTestPeer("sink", eth63, pm, true)
   703  	defer sink.close()
   704  
   705  	// Create various combinations of malformed blocks
   706  	chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) {})
   707  
   708  	malformedUncles := chain[0].Header()
   709  	malformedUncles.UncleHash[0]++
   710  	malformedTransactions := chain[0].Header()
   711  	malformedTransactions.TxHash[0]++
   712  	malformedEverything := chain[0].Header()
   713  	malformedEverything.UncleHash[0]++
   714  	malformedEverything.TxHash[0]++
   715  
   716  	// Keep listening to broadcasts and notify if any arrives
   717  	notify := make(chan struct{}, 1)
   718  	go func() {
   719  		if _, err := sink.app.ReadMsg(); err == nil {
   720  			notify <- struct{}{}
   721  		}
   722  	}()
   723  	// Try to broadcast all malformations and ensure they all get discarded
   724  	for _, header := range []*types.Header{malformedUncles, malformedTransactions, malformedEverything} {
   725  		block := types.NewBlockWithHeader(header).WithBody(chain[0].Transactions(), chain[0].Uncles())
   726  		if err := p2p.Send(source.app, NewBlockMsg, []interface{}{block, big.NewInt(131136)}); err != nil {
   727  			t.Fatalf("failed to broadcast block: %v", err)
   728  		}
   729  		select {
   730  		case <-notify:
   731  			t.Fatalf("malformed block forwarded")
   732  		case <-time.After(100 * time.Millisecond):
   733  		}
   734  	}
   735  }
   736  
   737  // Quorum
   738  // Tests that when broadcasting transactions, it sends the full transactions to all peers instead of Announcing (aka sending only hashes)
   739  func TestBroadcastTransactionsOnQuorum(t *testing.T) {
   740  	var (
   741  		evmux             = new(event.TypeMux)
   742  		pow               = ethash.NewFaker()
   743  		db                = rawdb.NewMemoryDatabase()
   744  		config            = &params.ChainConfig{}
   745  		gspec             = &core.Genesis{Config: config}
   746  		destinationKey, _ = crypto.GenerateKey()
   747  		totalPeers        = 100
   748  	)
   749  	gspec.MustCommit(db)
   750  	blockchain, _ := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil, nil, nil)
   751  	txPool := &testTxPool{pool: make(map[common.Hash]*types.Transaction)}
   752  
   753  	pm, err := NewProtocolManager(config, nil, downloader.FullSync, DefaultConfig.NetworkId, evmux, txPool, pow, blockchain, db, 1, nil, false)
   754  	if err != nil {
   755  		t.Fatalf("failed to start test protocol manager: %v", err)
   756  	}
   757  	pm.Start(totalPeers)
   758  	defer pm.Stop()
   759  
   760  	var peers []*testPeer
   761  	wgPeers := sync.WaitGroup{}
   762  	wgPeers.Add(totalPeers)
   763  	for i := 0; i < totalPeers; i++ {
   764  		peer, _ := newTestPeer(fmt.Sprintf("peer %d", i), eth65, pm, true)
   765  		go func() {
   766  			<-peer.EthPeerRegistered
   767  			wgPeers.Done()
   768  		}()
   769  		defer peer.close()
   770  
   771  		peers = append(peers, peer)
   772  	}
   773  	wgPeers.Wait() // wait until all peers are synced before pushing tx to the pool
   774  
   775  	transaction := types.NewTransaction(0, crypto.PubkeyToAddress(destinationKey.PublicKey), common.Big0, uint64(3000000), common.Big0, nil)
   776  	transactions := types.Transactions{transaction}
   777  
   778  	txPool.AddRemotes(transactions) // this will trigger the transaction broadcast/announce
   779  
   780  	doneCh := make(chan error, totalPeers)
   781  
   782  	wgPeers.Add(totalPeers)
   783  	defer func() {
   784  		wgPeers.Wait()
   785  		close(doneCh)
   786  	}()
   787  
   788  	for _, peer := range peers {
   789  		go func(p *testPeer) {
   790  			doneCh <- p2p.ExpectMsg(p.app, TransactionMsg, transactions)
   791  			wgPeers.Done()
   792  		}(peer)
   793  	}
   794  	var received int
   795  	for {
   796  		select {
   797  		case err := <-doneCh:
   798  			if err != nil {
   799  				t.Fatalf("broadcast failed: %v", err)
   800  				return
   801  			}
   802  			received++
   803  			if received == totalPeers {
   804  				// We found the right number
   805  				return
   806  			}
   807  		case <-time.After(2 * time.Second):
   808  			t.Errorf("timeout: broadcast count mismatch: have %d, want %d", received, totalPeers)
   809  			return
   810  		}
   811  	}
   812  }