github.com/platonnetwork/platon-go@v0.7.6/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  	"encoding/binary"
    21  	"math"
    22  	"math/big"
    23  	"math/rand"
    24  	"testing"
    25  
    26  	"github.com/PlatONnetwork/PlatON-Go/common"
    27  	"github.com/PlatONnetwork/PlatON-Go/core"
    28  	"github.com/PlatONnetwork/PlatON-Go/core/snapshotdb"
    29  	"github.com/PlatONnetwork/PlatON-Go/core/state"
    30  	"github.com/PlatONnetwork/PlatON-Go/core/types"
    31  	"github.com/PlatONnetwork/PlatON-Go/crypto"
    32  	"github.com/PlatONnetwork/PlatON-Go/eth/downloader"
    33  	"github.com/PlatONnetwork/PlatON-Go/ethdb"
    34  	"github.com/PlatONnetwork/PlatON-Go/p2p"
    35  	"github.com/PlatONnetwork/PlatON-Go/params"
    36  )
    37  
    38  // Tests that protocol versions and modes of operations are matched up properly.
    39  func TestProtocolCompatibility(t *testing.T) {
    40  	// Define the compatibility chart
    41  	tests := []struct {
    42  		version    uint
    43  		mode       downloader.SyncMode
    44  		compatible bool
    45  	}{
    46  		{61, downloader.FullSync, true}, {62, downloader.FullSync, true}, {63, downloader.FullSync, true},
    47  		{61, downloader.FastSync, false}, {62, downloader.FastSync, false}, {63, downloader.FastSync, true},
    48  	}
    49  	// Make sure anything we screw up is restored
    50  	backup := ProtocolVersions
    51  	defer func() { ProtocolVersions = backup }()
    52  	// Try all available compatibility configs and check for errors
    53  	for i, tt := range tests {
    54  		ProtocolVersions = []uint{tt.version}
    55  		//db := ethdb.NewMemDatabase()
    56  		pm, _, err := newTestProtocolManager(tt.mode, 0, nil, nil)
    57  		if pm != nil {
    58  			defer pm.Stop()
    59  		}
    60  		if (err == nil && !tt.compatible) || (err != nil && tt.compatible) {
    61  			t.Errorf("test %d: compatibility mismatch: have error %v, want compatibility %v", i, err, tt.compatible)
    62  		}
    63  	}
    64  }
    65  
    66  // Tests that block headers can be retrieved from a remote chain based on user queries.
    67  func TestGetBlockHeaders62(t *testing.T) { testGetBlockHeaders(t, 62) }
    68  
    69  func TestGetBlockHeaders63(t *testing.T) { testGetBlockHeaders(t, 63) }
    70  
    71  func testGetBlockHeaders(t *testing.T, protocol int) {
    72  	//db := ethdb.NewMemDatabase()
    73  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxHashFetch+15, nil, nil)
    74  	peer, _ := newTestPeer("peer", protocol, pm, true)
    75  	defer peer.close()
    76  
    77  	// Create a "random" unknown hash for testing
    78  	var unknown common.Hash
    79  	for i := range unknown {
    80  		unknown[i] = byte(i)
    81  	}
    82  	// Create a batch of tests for various scenarios
    83  	limit := uint64(downloader.MaxHeaderFetch)
    84  	tests := []struct {
    85  		query  *getBlockHeadersData // The query to execute for header retrieval
    86  		expect []common.Hash        // The hashes of the block whose headers are expected
    87  	}{
    88  		// A single random block should be retrievable by hash and number too
    89  		{
    90  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    91  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    92  		}, {
    93  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    94  			[]common.Hash{pm.blockchain.GetBlockByNumber(limit / 2).Hash()},
    95  		},
    96  		// Multiple headers should be retrievable in both directions
    97  		{
    98  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    99  			[]common.Hash{
   100  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   101  				pm.blockchain.GetBlockByNumber(limit/2 + 1).Hash(),
   102  				pm.blockchain.GetBlockByNumber(limit/2 + 2).Hash(),
   103  			},
   104  		}, {
   105  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
   106  			[]common.Hash{
   107  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   108  				pm.blockchain.GetBlockByNumber(limit/2 - 1).Hash(),
   109  				pm.blockchain.GetBlockByNumber(limit/2 - 2).Hash(),
   110  			},
   111  		},
   112  		// Multiple headers with skip lists should be retrievable
   113  		{
   114  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   115  			[]common.Hash{
   116  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   117  				pm.blockchain.GetBlockByNumber(limit/2 + 4).Hash(),
   118  				pm.blockchain.GetBlockByNumber(limit/2 + 8).Hash(),
   119  			},
   120  		}, {
   121  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   122  			[]common.Hash{
   123  				pm.blockchain.GetBlockByNumber(limit / 2).Hash(),
   124  				pm.blockchain.GetBlockByNumber(limit/2 - 4).Hash(),
   125  				pm.blockchain.GetBlockByNumber(limit/2 - 8).Hash(),
   126  			},
   127  		},
   128  		// The chain endpoints should be retrievable
   129  		{
   130  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   131  			[]common.Hash{pm.blockchain.GetBlockByNumber(0).Hash()},
   132  		}, {
   133  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64()}, Amount: 1},
   134  			[]common.Hash{pm.blockchain.CurrentBlock().Hash()},
   135  		},
   136  		// Ensure protocol limits are honored
   137  		{
   138  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   139  			pm.blockchain.GetBlockHashesFromHash(pm.blockchain.CurrentBlock().Hash(), limit),
   140  		},
   141  		// Check that requesting more than available is handled gracefully
   142  		{
   143  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   144  			[]common.Hash{
   145  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   146  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64()).Hash(),
   147  			},
   148  		}, {
   149  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   150  			[]common.Hash{
   151  				pm.blockchain.GetBlockByNumber(4).Hash(),
   152  				pm.blockchain.GetBlockByNumber(0).Hash(),
   153  			},
   154  		},
   155  		// Check that requesting more than available is handled gracefully, even if mid skip
   156  		{
   157  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   158  			[]common.Hash{
   159  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 4).Hash(),
   160  				pm.blockchain.GetBlockByNumber(pm.blockchain.CurrentBlock().NumberU64() - 1).Hash(),
   161  			},
   162  		}, {
   163  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   164  			[]common.Hash{
   165  				pm.blockchain.GetBlockByNumber(4).Hash(),
   166  				pm.blockchain.GetBlockByNumber(1).Hash(),
   167  			},
   168  		},
   169  		// Check a corner case where requesting more can iterate past the endpoints
   170  		{
   171  			&getBlockHeadersData{Origin: hashOrNumber{Number: 2}, Amount: 5, Reverse: true},
   172  			[]common.Hash{
   173  				pm.blockchain.GetBlockByNumber(2).Hash(),
   174  				pm.blockchain.GetBlockByNumber(1).Hash(),
   175  				pm.blockchain.GetBlockByNumber(0).Hash(),
   176  			},
   177  		},
   178  		// Check a corner case where skipping overflow loops back into the chain start
   179  		{
   180  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(3).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64 - 1},
   181  			[]common.Hash{
   182  				pm.blockchain.GetBlockByNumber(3).Hash(),
   183  			},
   184  		},
   185  		// Check a corner case where skipping overflow loops back to the same header
   186  		{
   187  			&getBlockHeadersData{Origin: hashOrNumber{Hash: pm.blockchain.GetBlockByNumber(1).Hash()}, Amount: 2, Reverse: false, Skip: math.MaxUint64},
   188  			[]common.Hash{
   189  				pm.blockchain.GetBlockByNumber(1).Hash(),
   190  			},
   191  		},
   192  		// Check that non existing headers aren't returned
   193  		{
   194  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   195  			[]common.Hash{},
   196  		}, {
   197  			&getBlockHeadersData{Origin: hashOrNumber{Number: pm.blockchain.CurrentBlock().NumberU64() + 1}, Amount: 1},
   198  			[]common.Hash{},
   199  		},
   200  	}
   201  	// Run each of the tests and verify the results against the chain
   202  	for i, tt := range tests {
   203  		// Collect the headers to expect in the response
   204  		headers := []*types.Header{}
   205  		for _, hash := range tt.expect {
   206  			headers = append(headers, pm.blockchain.GetBlockByHash(hash).Header())
   207  		}
   208  		// Send the hash request and verify the response
   209  		p2p.Send(peer.app, 0x03, tt.query)
   210  		if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   211  			t.Errorf("test %d: headers mismatch: %v", i, err)
   212  		}
   213  		// If the test used number origins, repeat with hashes as the too
   214  		if tt.query.Origin.Hash == (common.Hash{}) {
   215  			if origin := pm.blockchain.GetBlockByNumber(tt.query.Origin.Number); origin != nil {
   216  				tt.query.Origin.Hash, tt.query.Origin.Number = origin.Hash(), 0
   217  
   218  				p2p.Send(peer.app, 0x03, tt.query)
   219  				if err := p2p.ExpectMsg(peer.app, 0x04, headers); err != nil {
   220  					t.Errorf("test %d: headers mismatch: %v", i, err)
   221  				}
   222  			}
   223  		}
   224  	}
   225  }
   226  
   227  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   228  func TestGetBlockBodies62(t *testing.T) { testGetBlockBodies(t, 62) }
   229  
   230  func TestGetBlockBodies63(t *testing.T) { testGetBlockBodies(t, 63) }
   231  
   232  func testGetBlockBodies(t *testing.T, protocol int) {
   233  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   234  	peer, _ := newTestPeer("peer", protocol, pm, true)
   235  	defer peer.close()
   236  
   237  	// Create a batch of tests for various scenarios
   238  	limit := downloader.MaxBlockFetch
   239  	tests := []struct {
   240  		random    int           // Number of blocks to fetch randomly from the chain
   241  		explicit  []common.Hash // Explicitly requested blocks
   242  		available []bool        // Availability of explicitly requested blocks
   243  		expected  int           // Total number of existing blocks to expect
   244  	}{
   245  		{1, nil, nil, 1},             // A single random block should be retrievable
   246  		{10, nil, nil, 10},           // Multiple random blocks should be retrievable
   247  		{limit, nil, nil, limit},     // The maximum possible blocks should be retrievable
   248  		{limit + 1, nil, nil, limit}, // No more than the possible block count should be returned
   249  		{0, []common.Hash{pm.blockchain.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   250  		{0, []common.Hash{pm.blockchain.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   251  		{0, []common.Hash{{}}, []bool{false}, 0},                                 // A non existent block should not be returned
   252  
   253  		// Existing and non-existing blocks interleaved should not cause problems
   254  		{0, []common.Hash{
   255  			{},
   256  			pm.blockchain.GetBlockByNumber(1).Hash(),
   257  			{},
   258  			pm.blockchain.GetBlockByNumber(10).Hash(),
   259  			{},
   260  			pm.blockchain.GetBlockByNumber(100).Hash(),
   261  			{},
   262  		}, []bool{false, true, false, true, false, true, false}, 3},
   263  	}
   264  	// Run each of the tests and verify the results against the chain
   265  	for i, tt := range tests {
   266  		// Collect the hashes to request, and the response to expect
   267  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   268  		bodies := []*blockBody{}
   269  
   270  		for j := 0; j < tt.random; j++ {
   271  			for {
   272  				num := rand.Int63n(int64(pm.blockchain.CurrentBlock().NumberU64()))
   273  				if !seen[num] {
   274  					seen[num] = true
   275  
   276  					block := pm.blockchain.GetBlockByNumber(uint64(num))
   277  					hashes = append(hashes, block.Hash())
   278  					if len(bodies) < tt.expected {
   279  						bodies = append(bodies, &blockBody{Transactions: block.Transactions()})
   280  					}
   281  					break
   282  				}
   283  			}
   284  		}
   285  		for j, hash := range tt.explicit {
   286  			hashes = append(hashes, hash)
   287  			if tt.available[j] && len(bodies) < tt.expected {
   288  				block := pm.blockchain.GetBlockByHash(hash)
   289  				bodies = append(bodies, &blockBody{Transactions: block.Transactions()})
   290  			}
   291  		}
   292  		// Send the hash request and verify the response
   293  		p2p.Send(peer.app, 0x05, hashes)
   294  		if err := p2p.ExpectMsg(peer.app, 0x06, bodies); err != nil {
   295  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   296  		}
   297  	}
   298  }
   299  
   300  func newSnapshotdb() (snapshotdb.DB, error) {
   301  	db := snapshotdb.Instance()
   302  	highth := big.NewInt(100)
   303  	if err := db.SetCurrent(common.ZeroHash, *highth, *highth); err != nil {
   304  		return nil, err
   305  	}
   306  	var m [][2][]byte
   307  	for i := 0; i < 1028; i++ {
   308  		b := make([]byte, 8)
   309  		binary.LittleEndian.PutUint64(b, rand.Uint64())
   310  		m = append(m, [2][]byte{b, b})
   311  	}
   312  	if err := db.WriteBaseDB(m); err != nil {
   313  		return nil, err
   314  	}
   315  	return db, nil
   316  }
   317  
   318  func TestGetOriginAndPivotMsg(t *testing.T) {
   319  	//	log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(3), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
   320  
   321  	pm, _ := newTestProtocolManagerMust(t, downloader.FastSync, downloader.MaxBlockFetch+15, nil, nil)
   322  	peer, _ := newTestPeer("peer", 63, pm, true)
   323  	db, err := newSnapshotdb()
   324  	if err != nil {
   325  		t.Error(err)
   326  		return
   327  	}
   328  	defer func() {
   329  		peer.close()
   330  		db.Clear()
   331  	}()
   332  
   333  	if err := p2p.Send(peer.app, GetOriginAndPivotMsg, pm.blockchain.CurrentBlock().Header().Number.Uint64()); err != nil {
   334  		t.Error(err)
   335  		return
   336  	}
   337  	data := make([]*types.Header, 0)
   338  
   339  	oHead := pm.blockchain.GetHeaderByNumber(pm.blockchain.CurrentBlock().Header().Number.Uint64())
   340  	pivot, err := db.BaseNum()
   341  	if err != nil {
   342  		t.Error(err)
   343  		return
   344  	}
   345  	pHead := pm.blockchain.GetHeaderByNumber(pivot.Uint64())
   346  	data = append(data, oHead, pHead)
   347  	if err := p2p.ExpectMsg(peer.app, OriginAndPivotMsg, &data); err != nil {
   348  		t.Errorf("TestGetOriginAndPivotMsg : data mismatch: %v", err)
   349  	}
   350  }
   351  
   352  func TestGetPPOSStorageMsg(t *testing.T) {
   353  	//	log.Root().SetHandler(log.CallerFileHandler(log.LvlFilterHandler(log.Lvl(4), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))))
   354  
   355  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, downloader.MaxBlockFetch+15, nil, nil)
   356  	peer, _ := newTestPeer("peer", 63, pm, true)
   357  	db, err := newSnapshotdb()
   358  	if err != nil {
   359  		t.Error(err)
   360  		return
   361  	}
   362  	defer func() {
   363  		peer.close()
   364  		db.Clear()
   365  	}()
   366  	if err := p2p.Send(peer.app, GetPPOSStorageMsg, []interface{}{}); err != nil {
   367  		t.Error(err)
   368  		return
   369  	}
   370  	var data PPOSInfo
   371  	msg, err := peer.app.ReadMsg()
   372  	if err != nil {
   373  		t.Error(err)
   374  		return
   375  	}
   376  	if err := msg.Decode(&data); err != nil {
   377  		t.Error(err)
   378  		return
   379  	}
   380  	if data.Pivot.Number.Int64() != 100 {
   381  		t.Error("Pivot num is wrong")
   382  	}
   383  	if data.Latest.Number.Int64() != int64(downloader.MaxBlockFetch+15) {
   384  		t.Error("latest num is wrong")
   385  	}
   386  	var data2 PPOSStorage
   387  
   388  	for {
   389  		msg, err := peer.app.ReadMsg()
   390  		if err != nil {
   391  			t.Error(err)
   392  			return
   393  		}
   394  		if err := msg.Decode(&data2); err != nil {
   395  			t.Error(err)
   396  			return
   397  		}
   398  		if data2.Last {
   399  			break
   400  		}
   401  	}
   402  }
   403  
   404  // Tests that the node state database can be retrieved based on hashes.
   405  func TestGetNodeData63(t *testing.T) { testGetNodeData(t, 63) }
   406  
   407  func testGetNodeData(t *testing.T, protocol int) {
   408  	// Define three accounts to simulate transactions with
   409  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   410  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   411  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   412  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   413  	//chanid := new(big.Int)
   414  	signer := types.NewEIP155Signer(big.NewInt(1))
   415  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   416  	generator := func(i int, block *core.BlockGen) {
   417  		switch i {
   418  		case 0:
   419  			// In block 1, the test bank sends account #1 some ether.
   420  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   421  			block.AddTx(tx)
   422  		case 1:
   423  			// In block 2, the test bank sends some more ether to account #1.
   424  			// acc1Addr passes it on to account #2.
   425  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   426  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   427  			block.AddTx(tx1)
   428  			block.AddTx(tx2)
   429  		case 2:
   430  			// Block 3 is empty but was mined by account #2.
   431  			block.SetCoinbase(acc2Addr)
   432  			block.SetExtra([]byte("yeehaw"))
   433  		case 3:
   434  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   435  			b2 := block.PrevBlock(1).Header()
   436  			b2.Extra = []byte("foo")
   437  			b3 := block.PrevBlock(2).Header()
   438  			b3.Extra = []byte("foo")
   439  		}
   440  	}
   441  	// Assemble the test environment
   442  	pm, db := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   443  	peer, _ := newTestPeer("peer", protocol, pm, true)
   444  	defer peer.close()
   445  
   446  	// Fetch for now the entire chain db
   447  	hashes := []common.Hash{}
   448  	for _, key := range db.Keys() {
   449  		if len(key) == len(common.Hash{}) {
   450  			hashes = append(hashes, common.BytesToHash(key))
   451  		}
   452  	}
   453  	p2p.Send(peer.app, 0x0d, hashes)
   454  	msg, err := peer.app.ReadMsg()
   455  	if err != nil {
   456  		t.Fatalf("failed to read node data response: %v", err)
   457  	}
   458  	if msg.Code != 0x0e {
   459  		t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c)
   460  	}
   461  	var data [][]byte
   462  	if err := msg.Decode(&data); err != nil {
   463  		t.Fatalf("failed to decode response node data: %v", err)
   464  	}
   465  	// Verify that all hashes correspond to the requested data, and reconstruct a state tree
   466  	for i, want := range hashes {
   467  		if hash := crypto.Keccak256Hash(data[i]); hash != want {
   468  			t.Errorf("data hash mismatch: have %x, want %x", hash, want)
   469  		}
   470  	}
   471  	statedb := ethdb.NewMemDatabase()
   472  	for i := 0; i < len(data); i++ {
   473  		statedb.Put(hashes[i].Bytes(), data[i])
   474  	}
   475  	accounts := []common.Address{testBank, acc1Addr, acc2Addr}
   476  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   477  		trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), state.NewDatabase(statedb))
   478  
   479  		for j, acc := range accounts {
   480  			state, _ := pm.blockchain.State()
   481  			bw := state.GetBalance(acc)
   482  			bh := trie.GetBalance(acc)
   483  
   484  			if (bw != nil && bh == nil) || (bw == nil && bh != nil) {
   485  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   486  			}
   487  			if bw != nil && bh != nil && bw.Cmp(bw) != 0 {
   488  				t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw)
   489  			}
   490  		}
   491  	}
   492  }
   493  
   494  // Tests that the transaction receipts can be retrieved based on hashes.
   495  func TestGetReceipt63(t *testing.T) { testGetReceipt(t, 63) }
   496  
   497  func testGetReceipt(t *testing.T, protocol int) {
   498  	// Define three accounts to simulate transactions with
   499  	acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   500  	acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   501  	acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
   502  	acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
   503  
   504  	signer := types.NewEIP155Signer(big.NewInt(1))
   505  	// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
   506  	generator := func(i int, block *core.BlockGen) {
   507  		switch i {
   508  		case 0:
   509  			// In block 1, the test bank sends account #1 some ether.
   510  			tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   511  			block.AddTx(tx)
   512  		case 1:
   513  			// In block 2, the test bank sends some more ether to account #1.
   514  			// acc1Addr passes it on to account #2.
   515  			tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey)
   516  			tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key)
   517  			block.AddTx(tx1)
   518  			block.AddTx(tx2)
   519  		case 2:
   520  			// Block 3 is empty but was mined by account #2.
   521  			block.SetCoinbase(acc2Addr)
   522  			block.SetExtra([]byte("yeehaw"))
   523  		case 3:
   524  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   525  			b2 := block.PrevBlock(1).Header()
   526  			b2.Extra = []byte("foo")
   527  			b3 := block.PrevBlock(2).Header()
   528  			b3.Extra = []byte("foo")
   529  		}
   530  	}
   531  	// Assemble the test environment
   532  	pm, _ := newTestProtocolManagerMust(t, downloader.FullSync, 4, generator, nil)
   533  	peer, _ := newTestPeer("peer", protocol, pm, true)
   534  	defer peer.close()
   535  
   536  	// Collect the hashes to request, and the response to expect
   537  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   538  	for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
   539  		block := pm.blockchain.GetBlockByNumber(i)
   540  
   541  		hashes = append(hashes, block.Hash())
   542  		receipts = append(receipts, pm.blockchain.GetReceiptsByHash(block.Hash()))
   543  	}
   544  	// Send the hash request and verify the response
   545  	p2p.Send(peer.app, 0x0f, hashes)
   546  	if err := p2p.ExpectMsg(peer.app, 0x10, receipts); err != nil {
   547  		t.Errorf("receipts mismatch: %v", err)
   548  	}
   549  }