github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/les/handler_test.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  package les
    13  
    14  import (
    15  	"encoding/binary"
    16  	"math/big"
    17  	"math/rand"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/Sberex/go-sberex/common"
    22  	"github.com/Sberex/go-sberex/consensus/ethash"
    23  	"github.com/Sberex/go-sberex/core"
    24  	"github.com/Sberex/go-sberex/core/types"
    25  	"github.com/Sberex/go-sberex/crypto"
    26  	"github.com/Sberex/go-sberex/eth/downloader"
    27  	"github.com/Sberex/go-sberex/ethdb"
    28  	"github.com/Sberex/go-sberex/light"
    29  	"github.com/Sberex/go-sberex/p2p"
    30  	"github.com/Sberex/go-sberex/params"
    31  	"github.com/Sberex/go-sberex/rlp"
    32  	"github.com/Sberex/go-sberex/trie"
    33  )
    34  
    35  func expectResponse(r p2p.MsgReader, msgcode, reqID, bv uint64, data interface{}) error {
    36  	type resp struct {
    37  		ReqID, BV uint64
    38  		Data      interface{}
    39  	}
    40  	return p2p.ExpectMsg(r, msgcode, resp{reqID, bv, data})
    41  }
    42  
    43  // Tests that block headers can be retrieved from a remote chain based on user queries.
    44  func TestGetBlockHeadersLes1(t *testing.T) { testGetBlockHeaders(t, 1) }
    45  func TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) }
    46  
    47  func testGetBlockHeaders(t *testing.T, protocol int) {
    48  	db, _ := ethdb.NewMemDatabase()
    49  	pm := newTestProtocolManagerMust(t, false, downloader.MaxHashFetch+15, nil, nil, nil, db)
    50  	bc := pm.blockchain.(*core.BlockChain)
    51  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
    52  	defer peer.close()
    53  
    54  	// Create a "random" unknown hash for testing
    55  	var unknown common.Hash
    56  	for i := range unknown {
    57  		unknown[i] = byte(i)
    58  	}
    59  	// Create a batch of tests for various scenarios
    60  	limit := uint64(MaxHeaderFetch)
    61  	tests := []struct {
    62  		query  *getBlockHeadersData // The query to execute for header retrieval
    63  		expect []common.Hash        // The hashes of the block whose headers are expected
    64  	}{
    65  		// A single random block should be retrievable by hash and number too
    66  		{
    67  			&getBlockHeadersData{Origin: hashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    68  			[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
    69  		}, {
    70  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    71  			[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
    72  		},
    73  		// Multiple headers should be retrievable in both directions
    74  		{
    75  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    76  			[]common.Hash{
    77  				bc.GetBlockByNumber(limit / 2).Hash(),
    78  				bc.GetBlockByNumber(limit/2 + 1).Hash(),
    79  				bc.GetBlockByNumber(limit/2 + 2).Hash(),
    80  			},
    81  		}, {
    82  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
    83  			[]common.Hash{
    84  				bc.GetBlockByNumber(limit / 2).Hash(),
    85  				bc.GetBlockByNumber(limit/2 - 1).Hash(),
    86  				bc.GetBlockByNumber(limit/2 - 2).Hash(),
    87  			},
    88  		},
    89  		// Multiple headers with skip lists should be retrievable
    90  		{
    91  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
    92  			[]common.Hash{
    93  				bc.GetBlockByNumber(limit / 2).Hash(),
    94  				bc.GetBlockByNumber(limit/2 + 4).Hash(),
    95  				bc.GetBlockByNumber(limit/2 + 8).Hash(),
    96  			},
    97  		}, {
    98  			&getBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
    99  			[]common.Hash{
   100  				bc.GetBlockByNumber(limit / 2).Hash(),
   101  				bc.GetBlockByNumber(limit/2 - 4).Hash(),
   102  				bc.GetBlockByNumber(limit/2 - 8).Hash(),
   103  			},
   104  		},
   105  		// The chain endpoints should be retrievable
   106  		{
   107  			&getBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   108  			[]common.Hash{bc.GetBlockByNumber(0).Hash()},
   109  		}, {
   110  			&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64()}, Amount: 1},
   111  			[]common.Hash{bc.CurrentBlock().Hash()},
   112  		},
   113  		// Ensure protocol limits are honored
   114  		/*{
   115  			&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 1}, Amount: limit + 10, Reverse: true},
   116  			bc.GetBlockHashesFromHash(bc.CurrentBlock().Hash(), limit),
   117  		},*/
   118  		// Check that requesting more than available is handled gracefully
   119  		{
   120  			&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 3, Amount: 3},
   121  			[]common.Hash{
   122  				bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(),
   123  				bc.GetBlockByNumber(bc.CurrentBlock().NumberU64()).Hash(),
   124  			},
   125  		}, {
   126  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   127  			[]common.Hash{
   128  				bc.GetBlockByNumber(4).Hash(),
   129  				bc.GetBlockByNumber(0).Hash(),
   130  			},
   131  		},
   132  		// Check that requesting more than available is handled gracefully, even if mid skip
   133  		{
   134  			&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() - 4}, Skip: 2, Amount: 3},
   135  			[]common.Hash{
   136  				bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 4).Hash(),
   137  				bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1).Hash(),
   138  			},
   139  		}, {
   140  			&getBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   141  			[]common.Hash{
   142  				bc.GetBlockByNumber(4).Hash(),
   143  				bc.GetBlockByNumber(1).Hash(),
   144  			},
   145  		},
   146  		// Check that non existing headers aren't returned
   147  		{
   148  			&getBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   149  			[]common.Hash{},
   150  		}, {
   151  			&getBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().NumberU64() + 1}, Amount: 1},
   152  			[]common.Hash{},
   153  		},
   154  	}
   155  	// Run each of the tests and verify the results against the chain
   156  	var reqID uint64
   157  	for i, tt := range tests {
   158  		// Collect the headers to expect in the response
   159  		headers := []*types.Header{}
   160  		for _, hash := range tt.expect {
   161  			headers = append(headers, bc.GetHeaderByHash(hash))
   162  		}
   163  		// Send the hash request and verify the response
   164  		reqID++
   165  		cost := peer.GetRequestCost(GetBlockHeadersMsg, int(tt.query.Amount))
   166  		sendRequest(peer.app, GetBlockHeadersMsg, reqID, cost, tt.query)
   167  		if err := expectResponse(peer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil {
   168  			t.Errorf("test %d: headers mismatch: %v", i, err)
   169  		}
   170  	}
   171  }
   172  
   173  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   174  func TestGetBlockBodiesLes1(t *testing.T) { testGetBlockBodies(t, 1) }
   175  func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) }
   176  
   177  func testGetBlockBodies(t *testing.T, protocol int) {
   178  	db, _ := ethdb.NewMemDatabase()
   179  	pm := newTestProtocolManagerMust(t, false, downloader.MaxBlockFetch+15, nil, nil, nil, db)
   180  	bc := pm.blockchain.(*core.BlockChain)
   181  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
   182  	defer peer.close()
   183  
   184  	// Create a batch of tests for various scenarios
   185  	limit := MaxBodyFetch
   186  	tests := []struct {
   187  		random    int           // Number of blocks to fetch randomly from the chain
   188  		explicit  []common.Hash // Explicitly requested blocks
   189  		available []bool        // Availability of explicitly requested blocks
   190  		expected  int           // Total number of existing blocks to expect
   191  	}{
   192  		{1, nil, nil, 1},         // A single random block should be retrievable
   193  		{10, nil, nil, 10},       // Multiple random blocks should be retrievable
   194  		{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
   195  		//{limit + 1, nil, nil, limit},                                  // No more than the possible block count should be returned
   196  		{0, []common.Hash{bc.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   197  		{0, []common.Hash{bc.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   198  		{0, []common.Hash{{}}, []bool{false}, 0},                      // A non existent block should not be returned
   199  
   200  		// Existing and non-existing blocks interleaved should not cause problems
   201  		{0, []common.Hash{
   202  			{},
   203  			bc.GetBlockByNumber(1).Hash(),
   204  			{},
   205  			bc.GetBlockByNumber(10).Hash(),
   206  			{},
   207  			bc.GetBlockByNumber(100).Hash(),
   208  			{},
   209  		}, []bool{false, true, false, true, false, true, false}, 3},
   210  	}
   211  	// Run each of the tests and verify the results against the chain
   212  	var reqID uint64
   213  	for i, tt := range tests {
   214  		// Collect the hashes to request, and the response to expect
   215  		hashes, seen := []common.Hash{}, make(map[int64]bool)
   216  		bodies := []*types.Body{}
   217  
   218  		for j := 0; j < tt.random; j++ {
   219  			for {
   220  				num := rand.Int63n(int64(bc.CurrentBlock().NumberU64()))
   221  				if !seen[num] {
   222  					seen[num] = true
   223  
   224  					block := bc.GetBlockByNumber(uint64(num))
   225  					hashes = append(hashes, block.Hash())
   226  					if len(bodies) < tt.expected {
   227  						bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()})
   228  					}
   229  					break
   230  				}
   231  			}
   232  		}
   233  		for j, hash := range tt.explicit {
   234  			hashes = append(hashes, hash)
   235  			if tt.available[j] && len(bodies) < tt.expected {
   236  				block := bc.GetBlockByHash(hash)
   237  				bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()})
   238  			}
   239  		}
   240  		reqID++
   241  		// Send the hash request and verify the response
   242  		cost := peer.GetRequestCost(GetBlockBodiesMsg, len(hashes))
   243  		sendRequest(peer.app, GetBlockBodiesMsg, reqID, cost, hashes)
   244  		if err := expectResponse(peer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil {
   245  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   246  		}
   247  	}
   248  }
   249  
   250  // Tests that the contract codes can be retrieved based on account addresses.
   251  func TestGetCodeLes1(t *testing.T) { testGetCode(t, 1) }
   252  func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) }
   253  
   254  func testGetCode(t *testing.T, protocol int) {
   255  	// Assemble the test environment
   256  	db, _ := ethdb.NewMemDatabase()
   257  	pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
   258  	bc := pm.blockchain.(*core.BlockChain)
   259  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
   260  	defer peer.close()
   261  
   262  	var codereqs []*CodeReq
   263  	var codes [][]byte
   264  
   265  	for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ {
   266  		header := bc.GetHeaderByNumber(i)
   267  		req := &CodeReq{
   268  			BHash:  header.Hash(),
   269  			AccKey: crypto.Keccak256(testContractAddr[:]),
   270  		}
   271  		codereqs = append(codereqs, req)
   272  		if i >= testContractDeployed {
   273  			codes = append(codes, testContractCodeDeployed)
   274  		}
   275  	}
   276  
   277  	cost := peer.GetRequestCost(GetCodeMsg, len(codereqs))
   278  	sendRequest(peer.app, GetCodeMsg, 42, cost, codereqs)
   279  	if err := expectResponse(peer.app, CodeMsg, 42, testBufLimit, codes); err != nil {
   280  		t.Errorf("codes mismatch: %v", err)
   281  	}
   282  }
   283  
   284  // Tests that the transaction receipts can be retrieved based on hashes.
   285  func TestGetReceiptLes1(t *testing.T) { testGetReceipt(t, 1) }
   286  func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
   287  
   288  func testGetReceipt(t *testing.T, protocol int) {
   289  	// Assemble the test environment
   290  	db, _ := ethdb.NewMemDatabase()
   291  	pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
   292  	bc := pm.blockchain.(*core.BlockChain)
   293  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
   294  	defer peer.close()
   295  
   296  	// Collect the hashes to request, and the response to expect
   297  	hashes, receipts := []common.Hash{}, []types.Receipts{}
   298  	for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ {
   299  		block := bc.GetBlockByNumber(i)
   300  
   301  		hashes = append(hashes, block.Hash())
   302  		receipts = append(receipts, core.GetBlockReceipts(db, block.Hash(), block.NumberU64()))
   303  	}
   304  	// Send the hash request and verify the response
   305  	cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes))
   306  	sendRequest(peer.app, GetReceiptsMsg, 42, cost, hashes)
   307  	if err := expectResponse(peer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil {
   308  		t.Errorf("receipts mismatch: %v", err)
   309  	}
   310  }
   311  
   312  // Tests that trie merkle proofs can be retrieved
   313  func TestGetProofsLes1(t *testing.T) { testGetProofs(t, 1) }
   314  func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) }
   315  
   316  func testGetProofs(t *testing.T, protocol int) {
   317  	// Assemble the test environment
   318  	db, _ := ethdb.NewMemDatabase()
   319  	pm := newTestProtocolManagerMust(t, false, 4, testChainGen, nil, nil, db)
   320  	bc := pm.blockchain.(*core.BlockChain)
   321  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
   322  	defer peer.close()
   323  
   324  	var (
   325  		proofreqs []ProofReq
   326  		proofsV1  [][]rlp.RawValue
   327  	)
   328  	proofsV2 := light.NewNodeSet()
   329  
   330  	accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr, {}}
   331  	for i := uint64(0); i <= bc.CurrentBlock().NumberU64(); i++ {
   332  		header := bc.GetHeaderByNumber(i)
   333  		root := header.Root
   334  		trie, _ := trie.New(root, trie.NewDatabase(db))
   335  
   336  		for _, acc := range accounts {
   337  			req := ProofReq{
   338  				BHash: header.Hash(),
   339  				Key:   crypto.Keccak256(acc[:]),
   340  			}
   341  			proofreqs = append(proofreqs, req)
   342  
   343  			switch protocol {
   344  			case 1:
   345  				var proof light.NodeList
   346  				trie.Prove(crypto.Keccak256(acc[:]), 0, &proof)
   347  				proofsV1 = append(proofsV1, proof)
   348  			case 2:
   349  				trie.Prove(crypto.Keccak256(acc[:]), 0, proofsV2)
   350  			}
   351  		}
   352  	}
   353  	// Send the proof request and verify the response
   354  	switch protocol {
   355  	case 1:
   356  		cost := peer.GetRequestCost(GetProofsV1Msg, len(proofreqs))
   357  		sendRequest(peer.app, GetProofsV1Msg, 42, cost, proofreqs)
   358  		if err := expectResponse(peer.app, ProofsV1Msg, 42, testBufLimit, proofsV1); err != nil {
   359  			t.Errorf("proofs mismatch: %v", err)
   360  		}
   361  	case 2:
   362  		cost := peer.GetRequestCost(GetProofsV2Msg, len(proofreqs))
   363  		sendRequest(peer.app, GetProofsV2Msg, 42, cost, proofreqs)
   364  		if err := expectResponse(peer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil {
   365  			t.Errorf("proofs mismatch: %v", err)
   366  		}
   367  	}
   368  }
   369  
   370  // Tests that CHT proofs can be correctly retrieved.
   371  func TestGetCHTProofsLes1(t *testing.T) { testGetCHTProofs(t, 1) }
   372  func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) }
   373  
   374  func testGetCHTProofs(t *testing.T, protocol int) {
   375  	// Figure out the client's CHT frequency
   376  	frequency := uint64(light.CHTFrequencyClient)
   377  	if protocol == 1 {
   378  		frequency = uint64(light.CHTFrequencyServer)
   379  	}
   380  	// Assemble the test environment
   381  	db, _ := ethdb.NewMemDatabase()
   382  	pm := newTestProtocolManagerMust(t, false, int(frequency)+light.HelperTrieProcessConfirmations, testChainGen, nil, nil, db)
   383  	bc := pm.blockchain.(*core.BlockChain)
   384  	peer, _ := newTestPeer(t, "peer", protocol, pm, true)
   385  	defer peer.close()
   386  
   387  	// Wait a while for the CHT indexer to process the new headers
   388  	time.Sleep(100 * time.Millisecond * time.Duration(frequency/light.CHTFrequencyServer)) // Chain indexer throttling
   389  	time.Sleep(250 * time.Millisecond)                                                     // CI tester slack
   390  
   391  	// Assemble the proofs from the different protocols
   392  	header := bc.GetHeaderByNumber(frequency)
   393  	rlp, _ := rlp.EncodeToBytes(header)
   394  
   395  	key := make([]byte, 8)
   396  	binary.BigEndian.PutUint64(key, frequency)
   397  
   398  	proofsV1 := []ChtResp{{
   399  		Header: header,
   400  	}}
   401  	proofsV2 := HelperTrieResps{
   402  		AuxData: [][]byte{rlp},
   403  	}
   404  	switch protocol {
   405  	case 1:
   406  		root := light.GetChtRoot(db, 0, bc.GetHeaderByNumber(frequency-1).Hash())
   407  		trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(db, light.ChtTablePrefix)))
   408  
   409  		var proof light.NodeList
   410  		trie.Prove(key, 0, &proof)
   411  		proofsV1[0].Proof = proof
   412  
   413  	case 2:
   414  		root := light.GetChtV2Root(db, 0, bc.GetHeaderByNumber(frequency-1).Hash())
   415  		trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(db, light.ChtTablePrefix)))
   416  		trie.Prove(key, 0, &proofsV2.Proofs)
   417  	}
   418  	// Assemble the requests for the different protocols
   419  	requestsV1 := []ChtReq{{
   420  		ChtNum:   1,
   421  		BlockNum: frequency,
   422  	}}
   423  	requestsV2 := []HelperTrieReq{{
   424  		Type:    htCanonical,
   425  		TrieIdx: 0,
   426  		Key:     key,
   427  		AuxReq:  auxHeader,
   428  	}}
   429  	// Send the proof request and verify the response
   430  	switch protocol {
   431  	case 1:
   432  		cost := peer.GetRequestCost(GetHeaderProofsMsg, len(requestsV1))
   433  		sendRequest(peer.app, GetHeaderProofsMsg, 42, cost, requestsV1)
   434  		if err := expectResponse(peer.app, HeaderProofsMsg, 42, testBufLimit, proofsV1); err != nil {
   435  			t.Errorf("proofs mismatch: %v", err)
   436  		}
   437  	case 2:
   438  		cost := peer.GetRequestCost(GetHelperTrieProofsMsg, len(requestsV2))
   439  		sendRequest(peer.app, GetHelperTrieProofsMsg, 42, cost, requestsV2)
   440  		if err := expectResponse(peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil {
   441  			t.Errorf("proofs mismatch: %v", err)
   442  		}
   443  	}
   444  }
   445  
   446  // Tests that bloombits proofs can be correctly retrieved.
   447  func TestGetBloombitsProofs(t *testing.T) {
   448  	// Assemble the test environment
   449  	db, _ := ethdb.NewMemDatabase()
   450  	pm := newTestProtocolManagerMust(t, false, light.BloomTrieFrequency+256, testChainGen, nil, nil, db)
   451  	bc := pm.blockchain.(*core.BlockChain)
   452  	peer, _ := newTestPeer(t, "peer", 2, pm, true)
   453  	defer peer.close()
   454  
   455  	// Wait a while for the bloombits indexer to process the new headers
   456  	time.Sleep(100 * time.Millisecond * time.Duration(light.BloomTrieFrequency/4096)) // Chain indexer throttling
   457  	time.Sleep(250 * time.Millisecond)                                                // CI tester slack
   458  
   459  	// Request and verify each bit of the bloom bits proofs
   460  	for bit := 0; bit < 2048; bit++ {
   461  		// Assemble therequest and proofs for the bloombits
   462  		key := make([]byte, 10)
   463  
   464  		binary.BigEndian.PutUint16(key[:2], uint16(bit))
   465  		binary.BigEndian.PutUint64(key[2:], uint64(light.BloomTrieFrequency))
   466  
   467  		requests := []HelperTrieReq{{
   468  			Type:    htBloomBits,
   469  			TrieIdx: 0,
   470  			Key:     key,
   471  		}}
   472  		var proofs HelperTrieResps
   473  
   474  		root := light.GetBloomTrieRoot(db, 0, bc.GetHeaderByNumber(light.BloomTrieFrequency-1).Hash())
   475  		trie, _ := trie.New(root, trie.NewDatabase(ethdb.NewTable(db, light.BloomTrieTablePrefix)))
   476  		trie.Prove(key, 0, &proofs.Proofs)
   477  
   478  		// Send the proof request and verify the response
   479  		cost := peer.GetRequestCost(GetHelperTrieProofsMsg, len(requests))
   480  		sendRequest(peer.app, GetHelperTrieProofsMsg, 42, cost, requests)
   481  		if err := expectResponse(peer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil {
   482  			t.Errorf("bit %d: proofs mismatch: %v", bit, err)
   483  		}
   484  	}
   485  }
   486  
   487  func TestTransactionStatusLes2(t *testing.T) {
   488  	db, _ := ethdb.NewMemDatabase()
   489  	pm := newTestProtocolManagerMust(t, false, 0, nil, nil, nil, db)
   490  	chain := pm.blockchain.(*core.BlockChain)
   491  	config := core.DefaultTxPoolConfig
   492  	config.Journal = ""
   493  	txpool := core.NewTxPool(config, params.TestChainConfig, chain)
   494  	pm.txpool = txpool
   495  	peer, _ := newTestPeer(t, "peer", 2, pm, true)
   496  	defer peer.close()
   497  
   498  	var reqID uint64
   499  
   500  	test := func(tx *types.Transaction, send bool, expStatus txStatus) {
   501  		reqID++
   502  		if send {
   503  			cost := peer.GetRequestCost(SendTxV2Msg, 1)
   504  			sendRequest(peer.app, SendTxV2Msg, reqID, cost, types.Transactions{tx})
   505  		} else {
   506  			cost := peer.GetRequestCost(GetTxStatusMsg, 1)
   507  			sendRequest(peer.app, GetTxStatusMsg, reqID, cost, []common.Hash{tx.Hash()})
   508  		}
   509  		if err := expectResponse(peer.app, TxStatusMsg, reqID, testBufLimit, []txStatus{expStatus}); err != nil {
   510  			t.Errorf("transaction status mismatch")
   511  		}
   512  	}
   513  
   514  	signer := types.HomesteadSigner{}
   515  
   516  	// test error status by sending an underpriced transaction
   517  	tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey)
   518  	test(tx0, true, txStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced.Error()})
   519  
   520  	tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
   521  	test(tx1, false, txStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown
   522  	test(tx1, true, txStatus{Status: core.TxStatusPending})  // send valid processable tx, should return pending
   523  	test(tx1, true, txStatus{Status: core.TxStatusPending})  // adding it again should not return an error
   524  
   525  	tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
   526  	tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey)
   527  	// send transactions in the wrong order, tx3 should be queued
   528  	test(tx3, true, txStatus{Status: core.TxStatusQueued})
   529  	test(tx2, true, txStatus{Status: core.TxStatusPending})
   530  	// query again, now tx3 should be pending too
   531  	test(tx3, false, txStatus{Status: core.TxStatusPending})
   532  
   533  	// generate and add a block with tx1 and tx2 included
   534  	gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 1, func(i int, block *core.BlockGen) {
   535  		block.AddTx(tx1)
   536  		block.AddTx(tx2)
   537  	})
   538  	if _, err := chain.InsertChain(gchain); err != nil {
   539  		panic(err)
   540  	}
   541  	// wait until TxPool processes the inserted block
   542  	for i := 0; i < 10; i++ {
   543  		if pending, _ := txpool.Stats(); pending == 1 {
   544  			break
   545  		}
   546  		time.Sleep(100 * time.Millisecond)
   547  	}
   548  	if pending, _ := txpool.Stats(); pending != 1 {
   549  		t.Fatalf("pending count mismatch: have %d, want 1", pending)
   550  	}
   551  
   552  	// check if their status is included now
   553  	block1hash := core.GetCanonicalHash(db, 1)
   554  	test(tx1, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}})
   555  	test(tx2, false, txStatus{Status: core.TxStatusIncluded, Lookup: &core.TxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}})
   556  
   557  	// create a reorg that rolls them back
   558  	gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), db, 2, func(i int, block *core.BlockGen) {})
   559  	if _, err := chain.InsertChain(gchain); err != nil {
   560  		panic(err)
   561  	}
   562  	// wait until TxPool processes the reorg
   563  	for i := 0; i < 10; i++ {
   564  		if pending, _ := txpool.Stats(); pending == 3 {
   565  			break
   566  		}
   567  		time.Sleep(100 * time.Millisecond)
   568  	}
   569  	if pending, _ := txpool.Stats(); pending != 3 {
   570  		t.Fatalf("pending count mismatch: have %d, want 3", pending)
   571  	}
   572  	// check if their status is pending again
   573  	test(tx1, false, txStatus{Status: core.TxStatusPending})
   574  	test(tx2, false, txStatus{Status: core.TxStatusPending})
   575  }