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