github.com/m3shine/gochain@v2.2.26+incompatible/les/handler_test.go (about)

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