github.com/theQRL/go-zond@v0.1.1/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/theQRL/go-zond/common"
    27  	"github.com/theQRL/go-zond/common/mclock"
    28  	"github.com/theQRL/go-zond/consensus/ethash"
    29  	"github.com/theQRL/go-zond/core"
    30  	"github.com/theQRL/go-zond/core/rawdb"
    31  	"github.com/theQRL/go-zond/core/txpool"
    32  	"github.com/theQRL/go-zond/core/types"
    33  	"github.com/theQRL/go-zond/crypto"
    34  	"github.com/theQRL/go-zond/light"
    35  	"github.com/theQRL/go-zond/p2p"
    36  	"github.com/theQRL/go-zond/params"
    37  	"github.com/theQRL/go-zond/rlp"
    38  	"github.com/theQRL/go-zond/trie"
    39  	"github.com/theQRL/go-zond/zond/downloader"
    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 TestGetBlockHeadersLes2(t *testing.T) { testGetBlockHeaders(t, 2) }
    52  func TestGetBlockHeadersLes3(t *testing.T) { testGetBlockHeaders(t, 3) }
    53  func TestGetBlockHeadersLes4(t *testing.T) { testGetBlockHeaders(t, 4) }
    54  
    55  func testGetBlockHeaders(t *testing.T, protocol int) {
    56  	netconfig := testnetConfig{
    57  		blocks:    downloader.MaxHeaderFetch + 15,
    58  		protocol:  protocol,
    59  		nopruning: true,
    60  	}
    61  	server, _, tearDown := newClientServerEnv(t, netconfig)
    62  	defer tearDown()
    63  
    64  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
    65  	defer closePeer()
    66  	bc := server.handler.blockchain
    67  
    68  	// Create a "random" unknown hash for testing
    69  	var unknown common.Hash
    70  	for i := range unknown {
    71  		unknown[i] = byte(i)
    72  	}
    73  	// Create a batch of tests for various scenarios
    74  	limit := uint64(MaxHeaderFetch)
    75  	tests := []struct {
    76  		query  *GetBlockHeadersData // The query to execute for header retrieval
    77  		expect []common.Hash        // The hashes of the block whose headers are expected
    78  	}{
    79  		// A single random block should be retrievable by hash and number too
    80  		{
    81  			&GetBlockHeadersData{Origin: hashOrNumber{Hash: bc.GetBlockByNumber(limit / 2).Hash()}, Amount: 1},
    82  			[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
    83  		}, {
    84  			&GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 1},
    85  			[]common.Hash{bc.GetBlockByNumber(limit / 2).Hash()},
    86  		},
    87  		// Multiple headers should be retrievable in both directions
    88  		{
    89  			&GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3},
    90  			[]common.Hash{
    91  				bc.GetBlockByNumber(limit / 2).Hash(),
    92  				bc.GetBlockByNumber(limit/2 + 1).Hash(),
    93  				bc.GetBlockByNumber(limit/2 + 2).Hash(),
    94  			},
    95  		}, {
    96  			&GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Amount: 3, Reverse: true},
    97  			[]common.Hash{
    98  				bc.GetBlockByNumber(limit / 2).Hash(),
    99  				bc.GetBlockByNumber(limit/2 - 1).Hash(),
   100  				bc.GetBlockByNumber(limit/2 - 2).Hash(),
   101  			},
   102  		},
   103  		// Multiple headers with skip lists should be retrievable
   104  		{
   105  			&GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3},
   106  			[]common.Hash{
   107  				bc.GetBlockByNumber(limit / 2).Hash(),
   108  				bc.GetBlockByNumber(limit/2 + 4).Hash(),
   109  				bc.GetBlockByNumber(limit/2 + 8).Hash(),
   110  			},
   111  		}, {
   112  			&GetBlockHeadersData{Origin: hashOrNumber{Number: limit / 2}, Skip: 3, Amount: 3, Reverse: true},
   113  			[]common.Hash{
   114  				bc.GetBlockByNumber(limit / 2).Hash(),
   115  				bc.GetBlockByNumber(limit/2 - 4).Hash(),
   116  				bc.GetBlockByNumber(limit/2 - 8).Hash(),
   117  			},
   118  		},
   119  		// The chain endpoints should be retrievable
   120  		{
   121  			&GetBlockHeadersData{Origin: hashOrNumber{Number: 0}, Amount: 1},
   122  			[]common.Hash{bc.GetBlockByNumber(0).Hash()},
   123  		}, {
   124  			&GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()}, Amount: 1},
   125  			[]common.Hash{bc.CurrentBlock().Hash()},
   126  		},
   127  		// Ensure protocol limits are honored
   128  		//{
   129  		//	&GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64()() - 1}, Amount: limit + 10, Reverse: true},
   130  		//	[]common.Hash{},
   131  		//},
   132  		// Check that requesting more than available is handled gracefully
   133  		{
   134  			&GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 3, Amount: 3},
   135  			[]common.Hash{
   136  				bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(),
   137  				bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64()).Hash(),
   138  			},
   139  		}, {
   140  			&GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 3, Amount: 3, Reverse: true},
   141  			[]common.Hash{
   142  				bc.GetBlockByNumber(4).Hash(),
   143  				bc.GetBlockByNumber(0).Hash(),
   144  			},
   145  		},
   146  		// Check that requesting more than available is handled gracefully, even if mid skip
   147  		{
   148  			&GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() - 4}, Skip: 2, Amount: 3},
   149  			[]common.Hash{
   150  				bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 4).Hash(),
   151  				bc.GetBlockByNumber(bc.CurrentBlock().Number.Uint64() - 1).Hash(),
   152  			},
   153  		}, {
   154  			&GetBlockHeadersData{Origin: hashOrNumber{Number: 4}, Skip: 2, Amount: 3, Reverse: true},
   155  			[]common.Hash{
   156  				bc.GetBlockByNumber(4).Hash(),
   157  				bc.GetBlockByNumber(1).Hash(),
   158  			},
   159  		},
   160  		// Check that non existing headers aren't returned
   161  		{
   162  			&GetBlockHeadersData{Origin: hashOrNumber{Hash: unknown}, Amount: 1},
   163  			[]common.Hash{},
   164  		}, {
   165  			&GetBlockHeadersData{Origin: hashOrNumber{Number: bc.CurrentBlock().Number.Uint64() + 1}, Amount: 1},
   166  			[]common.Hash{},
   167  		},
   168  	}
   169  	// Run each of the tests and verify the results against the chain
   170  	var reqID uint64
   171  	for i, tt := range tests {
   172  		// Collect the headers to expect in the response
   173  		var headers []*types.Header
   174  		for _, hash := range tt.expect {
   175  			headers = append(headers, bc.GetHeaderByHash(hash))
   176  		}
   177  		// Send the hash request and verify the response
   178  		reqID++
   179  
   180  		sendRequest(rawPeer.app, GetBlockHeadersMsg, reqID, tt.query)
   181  		if err := expectResponse(rawPeer.app, BlockHeadersMsg, reqID, testBufLimit, headers); err != nil {
   182  			t.Errorf("test %d: headers mismatch: %v", i, err)
   183  		}
   184  	}
   185  }
   186  
   187  // Tests that block contents can be retrieved from a remote chain based on their hashes.
   188  func TestGetBlockBodiesLes2(t *testing.T) { testGetBlockBodies(t, 2) }
   189  func TestGetBlockBodiesLes3(t *testing.T) { testGetBlockBodies(t, 3) }
   190  func TestGetBlockBodiesLes4(t *testing.T) { testGetBlockBodies(t, 4) }
   191  
   192  func testGetBlockBodies(t *testing.T, protocol int) {
   193  	netconfig := testnetConfig{
   194  		blocks:    downloader.MaxHeaderFetch + 15,
   195  		protocol:  protocol,
   196  		nopruning: true,
   197  	}
   198  	server, _, tearDown := newClientServerEnv(t, netconfig)
   199  	defer tearDown()
   200  
   201  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   202  	defer closePeer()
   203  
   204  	bc := server.handler.blockchain
   205  
   206  	// Create a batch of tests for various scenarios
   207  	limit := MaxBodyFetch
   208  	tests := []struct {
   209  		random    int           // Number of blocks to fetch randomly from the chain
   210  		explicit  []common.Hash // Explicitly requested blocks
   211  		available []bool        // Availability of explicitly requested blocks
   212  		expected  int           // Total number of existing blocks to expect
   213  	}{
   214  		{1, nil, nil, 1},         // A single random block should be retrievable
   215  		{10, nil, nil, 10},       // Multiple random blocks should be retrievable
   216  		{limit, nil, nil, limit}, // The maximum possible blocks should be retrievable
   217  		//{limit + 1, nil, nil, limit},                                  // No more than the possible block count should be returned
   218  		{0, []common.Hash{bc.Genesis().Hash()}, []bool{true}, 1},      // The genesis block should be retrievable
   219  		{0, []common.Hash{bc.CurrentBlock().Hash()}, []bool{true}, 1}, // The chains head block should be retrievable
   220  		{0, []common.Hash{{}}, []bool{false}, 0},                      // A non existent block should not be returned
   221  
   222  		// Existing and non-existing blocks interleaved should not cause problems
   223  		{0, []common.Hash{
   224  			{},
   225  			bc.GetBlockByNumber(1).Hash(),
   226  			{},
   227  			bc.GetBlockByNumber(10).Hash(),
   228  			{},
   229  			bc.GetBlockByNumber(100).Hash(),
   230  			{},
   231  		}, []bool{false, true, false, true, false, true, false}, 3},
   232  	}
   233  	// Run each of the tests and verify the results against the chain
   234  	var reqID uint64
   235  	for i, tt := range tests {
   236  		// Collect the hashes to request, and the response to expect
   237  		var hashes []common.Hash
   238  		seen := make(map[int64]bool)
   239  		var bodies []*types.Body
   240  
   241  		for j := 0; j < tt.random; j++ {
   242  			for {
   243  				num := rand.Int63n(int64(bc.CurrentBlock().Number.Uint64()))
   244  				if !seen[num] {
   245  					seen[num] = true
   246  
   247  					block := bc.GetBlockByNumber(uint64(num))
   248  					hashes = append(hashes, block.Hash())
   249  					if len(bodies) < tt.expected {
   250  						bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()})
   251  					}
   252  					break
   253  				}
   254  			}
   255  		}
   256  		for j, hash := range tt.explicit {
   257  			hashes = append(hashes, hash)
   258  			if tt.available[j] && len(bodies) < tt.expected {
   259  				block := bc.GetBlockByHash(hash)
   260  				bodies = append(bodies, &types.Body{Transactions: block.Transactions(), Uncles: block.Uncles()})
   261  			}
   262  		}
   263  		reqID++
   264  
   265  		// Send the hash request and verify the response
   266  		sendRequest(rawPeer.app, GetBlockBodiesMsg, reqID, hashes)
   267  		if err := expectResponse(rawPeer.app, BlockBodiesMsg, reqID, testBufLimit, bodies); err != nil {
   268  			t.Errorf("test %d: bodies mismatch: %v", i, err)
   269  		}
   270  	}
   271  }
   272  
   273  // Tests that the contract codes can be retrieved based on account addresses.
   274  func TestGetCodeLes2(t *testing.T) { testGetCode(t, 2) }
   275  func TestGetCodeLes3(t *testing.T) { testGetCode(t, 3) }
   276  func TestGetCodeLes4(t *testing.T) { testGetCode(t, 4) }
   277  
   278  func testGetCode(t *testing.T, protocol int) {
   279  	// Assemble the test environment
   280  	netconfig := testnetConfig{
   281  		blocks:    4,
   282  		protocol:  protocol,
   283  		nopruning: true,
   284  	}
   285  	server, _, tearDown := newClientServerEnv(t, netconfig)
   286  	defer tearDown()
   287  
   288  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   289  	defer closePeer()
   290  
   291  	bc := server.handler.blockchain
   292  
   293  	var codereqs []*CodeReq
   294  	var codes [][]byte
   295  	for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ {
   296  		header := bc.GetHeaderByNumber(i)
   297  		req := &CodeReq{
   298  			BHash:          header.Hash(),
   299  			AccountAddress: testContractAddr[:],
   300  		}
   301  		codereqs = append(codereqs, req)
   302  		if i >= testContractDeployed {
   303  			codes = append(codes, testContractCodeDeployed)
   304  		}
   305  	}
   306  
   307  	sendRequest(rawPeer.app, GetCodeMsg, 42, codereqs)
   308  	if err := expectResponse(rawPeer.app, CodeMsg, 42, testBufLimit, codes); err != nil {
   309  		t.Errorf("codes mismatch: %v", err)
   310  	}
   311  }
   312  
   313  // Tests that the stale contract codes can't be retrieved based on account addresses.
   314  func TestGetStaleCodeLes2(t *testing.T) { testGetStaleCode(t, 2) }
   315  func TestGetStaleCodeLes3(t *testing.T) { testGetStaleCode(t, 3) }
   316  func TestGetStaleCodeLes4(t *testing.T) { testGetStaleCode(t, 4) }
   317  
   318  func testGetStaleCode(t *testing.T, protocol int) {
   319  	netconfig := testnetConfig{
   320  		blocks:    core.TriesInMemory + 4,
   321  		protocol:  protocol,
   322  		nopruning: true,
   323  	}
   324  	server, _, tearDown := newClientServerEnv(t, netconfig)
   325  	defer tearDown()
   326  
   327  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   328  	defer closePeer()
   329  
   330  	bc := server.handler.blockchain
   331  
   332  	check := func(number uint64, expected [][]byte) {
   333  		req := &CodeReq{
   334  			BHash:          bc.GetHeaderByNumber(number).Hash(),
   335  			AccountAddress: testContractAddr[:],
   336  		}
   337  		sendRequest(rawPeer.app, GetCodeMsg, 42, []*CodeReq{req})
   338  		if err := expectResponse(rawPeer.app, CodeMsg, 42, testBufLimit, expected); err != nil {
   339  			t.Errorf("codes mismatch: %v", err)
   340  		}
   341  	}
   342  	check(0, [][]byte{})                                                          // Non-exist contract
   343  	check(testContractDeployed, [][]byte{})                                       // Stale contract
   344  	check(bc.CurrentHeader().Number.Uint64(), [][]byte{testContractCodeDeployed}) // Fresh contract
   345  }
   346  
   347  // Tests that the transaction receipts can be retrieved based on hashes.
   348  func TestGetReceiptLes2(t *testing.T) { testGetReceipt(t, 2) }
   349  func TestGetReceiptLes3(t *testing.T) { testGetReceipt(t, 3) }
   350  func TestGetReceiptLes4(t *testing.T) { testGetReceipt(t, 4) }
   351  
   352  func testGetReceipt(t *testing.T, protocol int) {
   353  	// Assemble the test environment
   354  	netconfig := testnetConfig{
   355  		blocks:    4,
   356  		protocol:  protocol,
   357  		nopruning: true,
   358  	}
   359  	server, _, tearDown := newClientServerEnv(t, netconfig)
   360  	defer tearDown()
   361  
   362  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   363  	defer closePeer()
   364  
   365  	bc := server.handler.blockchain
   366  
   367  	// Collect the hashes to request, and the response to expect
   368  	var receipts []types.Receipts
   369  	var hashes []common.Hash
   370  	for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ {
   371  		block := bc.GetBlockByNumber(i)
   372  
   373  		hashes = append(hashes, block.Hash())
   374  		receipts = append(receipts, rawdb.ReadReceipts(server.db, block.Hash(), block.NumberU64(), block.Time(), bc.Config()))
   375  	}
   376  	// Send the hash request and verify the response
   377  	sendRequest(rawPeer.app, GetReceiptsMsg, 42, hashes)
   378  	if err := expectResponse(rawPeer.app, ReceiptsMsg, 42, testBufLimit, receipts); err != nil {
   379  		t.Errorf("receipts mismatch: %v", err)
   380  	}
   381  }
   382  
   383  // Tests that trie merkle proofs can be retrieved
   384  func TestGetProofsLes2(t *testing.T) { testGetProofs(t, 2) }
   385  func TestGetProofsLes3(t *testing.T) { testGetProofs(t, 3) }
   386  func TestGetProofsLes4(t *testing.T) { testGetProofs(t, 4) }
   387  
   388  func testGetProofs(t *testing.T, protocol int) {
   389  	// Assemble the test environment
   390  	netconfig := testnetConfig{
   391  		blocks:    4,
   392  		protocol:  protocol,
   393  		nopruning: true,
   394  	}
   395  	server, _, tearDown := newClientServerEnv(t, netconfig)
   396  	defer tearDown()
   397  
   398  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   399  	defer closePeer()
   400  
   401  	bc := server.handler.blockchain
   402  
   403  	var proofreqs []ProofReq
   404  	proofsV2 := light.NewNodeSet()
   405  
   406  	accounts := []common.Address{bankAddr, userAddr1, userAddr2, signerAddr, {}}
   407  	for i := uint64(0); i <= bc.CurrentBlock().Number.Uint64(); i++ {
   408  		header := bc.GetHeaderByNumber(i)
   409  		trie, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB())
   410  
   411  		for _, acc := range accounts {
   412  			req := ProofReq{
   413  				BHash: header.Hash(),
   414  				Key:   crypto.Keccak256(acc[:]),
   415  			}
   416  			proofreqs = append(proofreqs, req)
   417  			trie.Prove(crypto.Keccak256(acc[:]), proofsV2)
   418  		}
   419  	}
   420  	// Send the proof request and verify the response
   421  	sendRequest(rawPeer.app, GetProofsV2Msg, 42, proofreqs)
   422  	if err := expectResponse(rawPeer.app, ProofsV2Msg, 42, testBufLimit, proofsV2.NodeList()); err != nil {
   423  		t.Errorf("proofs mismatch: %v", err)
   424  	}
   425  }
   426  
   427  // Tests that the stale contract codes can't be retrieved based on account addresses.
   428  func TestGetStaleProofLes2(t *testing.T) { testGetStaleProof(t, 2) }
   429  func TestGetStaleProofLes3(t *testing.T) { testGetStaleProof(t, 3) }
   430  func TestGetStaleProofLes4(t *testing.T) { testGetStaleProof(t, 4) }
   431  
   432  func testGetStaleProof(t *testing.T, protocol int) {
   433  	netconfig := testnetConfig{
   434  		blocks:    core.TriesInMemory + 4,
   435  		protocol:  protocol,
   436  		nopruning: true,
   437  	}
   438  	server, _, tearDown := newClientServerEnv(t, netconfig)
   439  	defer tearDown()
   440  
   441  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   442  	defer closePeer()
   443  
   444  	bc := server.handler.blockchain
   445  
   446  	check := func(number uint64, wantOK bool) {
   447  		var (
   448  			header  = bc.GetHeaderByNumber(number)
   449  			account = crypto.Keccak256(userAddr1.Bytes())
   450  		)
   451  		req := &ProofReq{
   452  			BHash: header.Hash(),
   453  			Key:   account,
   454  		}
   455  		sendRequest(rawPeer.app, GetProofsV2Msg, 42, []*ProofReq{req})
   456  
   457  		var expected []rlp.RawValue
   458  		if wantOK {
   459  			proofsV2 := light.NewNodeSet()
   460  			t, _ := trie.New(trie.StateTrieID(header.Root), server.backend.Blockchain().TrieDB())
   461  			t.Prove(account, proofsV2)
   462  			expected = proofsV2.NodeList()
   463  		}
   464  		if err := expectResponse(rawPeer.app, ProofsV2Msg, 42, testBufLimit, expected); err != nil {
   465  			t.Errorf("codes mismatch: %v", err)
   466  		}
   467  	}
   468  	check(0, false)                                 // Non-exist proof
   469  	check(2, false)                                 // Stale proof
   470  	check(bc.CurrentHeader().Number.Uint64(), true) // Fresh proof
   471  }
   472  
   473  // Tests that CHT proofs can be correctly retrieved.
   474  func TestGetCHTProofsLes2(t *testing.T) { testGetCHTProofs(t, 2) }
   475  func TestGetCHTProofsLes3(t *testing.T) { testGetCHTProofs(t, 3) }
   476  func TestGetCHTProofsLes4(t *testing.T) { testGetCHTProofs(t, 4) }
   477  
   478  func testGetCHTProofs(t *testing.T, protocol int) {
   479  	var (
   480  		config       = light.TestServerIndexerConfig
   481  		waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
   482  			for {
   483  				cs, _, _ := cIndexer.Sections()
   484  				if cs >= 1 {
   485  					break
   486  				}
   487  				time.Sleep(10 * time.Millisecond)
   488  			}
   489  		}
   490  		netconfig = testnetConfig{
   491  			blocks:    int(config.ChtSize + config.ChtConfirms),
   492  			protocol:  protocol,
   493  			indexFn:   waitIndexers,
   494  			nopruning: true,
   495  		}
   496  	)
   497  	server, _, tearDown := newClientServerEnv(t, netconfig)
   498  	defer tearDown()
   499  
   500  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   501  	defer closePeer()
   502  
   503  	bc := server.handler.blockchain
   504  
   505  	// Assemble the proofs from the different protocols
   506  	header := bc.GetHeaderByNumber(config.ChtSize - 1)
   507  	rlp, _ := rlp.EncodeToBytes(header)
   508  
   509  	key := make([]byte, 8)
   510  	binary.BigEndian.PutUint64(key, config.ChtSize-1)
   511  
   512  	proofsV2 := HelperTrieResps{
   513  		AuxData: [][]byte{rlp},
   514  	}
   515  	root := light.GetChtRoot(server.db, 0, bc.GetHeaderByNumber(config.ChtSize-1).Hash())
   516  	trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.ChtTablePrefix)), trie.HashDefaults))
   517  	trie.Prove(key, &proofsV2.Proofs)
   518  	// Assemble the requests for the different protocols
   519  	requestsV2 := []HelperTrieReq{{
   520  		Type:    htCanonical,
   521  		TrieIdx: 0,
   522  		Key:     key,
   523  		AuxReq:  htAuxHeader,
   524  	}}
   525  	// Send the proof request and verify the response
   526  	sendRequest(rawPeer.app, GetHelperTrieProofsMsg, 42, requestsV2)
   527  	if err := expectResponse(rawPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofsV2); err != nil {
   528  		t.Errorf("proofs mismatch: %v", err)
   529  	}
   530  }
   531  
   532  func TestGetBloombitsProofsLes2(t *testing.T) { testGetBloombitsProofs(t, 2) }
   533  func TestGetBloombitsProofsLes3(t *testing.T) { testGetBloombitsProofs(t, 3) }
   534  func TestGetBloombitsProofsLes4(t *testing.T) { testGetBloombitsProofs(t, 4) }
   535  
   536  // Tests that bloombits proofs can be correctly retrieved.
   537  func testGetBloombitsProofs(t *testing.T, protocol int) {
   538  	var (
   539  		config       = light.TestServerIndexerConfig
   540  		waitIndexers = func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
   541  			for {
   542  				bts, _, _ := btIndexer.Sections()
   543  				if bts >= 1 {
   544  					break
   545  				}
   546  				time.Sleep(10 * time.Millisecond)
   547  			}
   548  		}
   549  		netconfig = testnetConfig{
   550  			blocks:    int(config.BloomTrieSize + config.BloomTrieConfirms),
   551  			protocol:  protocol,
   552  			indexFn:   waitIndexers,
   553  			nopruning: true,
   554  		}
   555  	)
   556  	server, _, tearDown := newClientServerEnv(t, netconfig)
   557  	defer tearDown()
   558  
   559  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   560  	defer closePeer()
   561  
   562  	bc := server.handler.blockchain
   563  
   564  	// Request and verify each bit of the bloom bits proofs
   565  	for bit := 0; bit < 2048; bit++ {
   566  		// Assemble the request and proofs for the bloombits
   567  		key := make([]byte, 10)
   568  
   569  		binary.BigEndian.PutUint16(key[:2], uint16(bit))
   570  		// Only the first bloom section has data.
   571  		binary.BigEndian.PutUint64(key[2:], 0)
   572  
   573  		requests := []HelperTrieReq{{
   574  			Type:    htBloomBits,
   575  			TrieIdx: 0,
   576  			Key:     key,
   577  		}}
   578  		var proofs HelperTrieResps
   579  
   580  		root := light.GetBloomTrieRoot(server.db, 0, bc.GetHeaderByNumber(config.BloomTrieSize-1).Hash())
   581  		trie, _ := trie.New(trie.TrieID(root), trie.NewDatabase(rawdb.NewTable(server.db, string(rawdb.BloomTrieTablePrefix)), trie.HashDefaults))
   582  		trie.Prove(key, &proofs.Proofs)
   583  
   584  		// Send the proof request and verify the response
   585  		sendRequest(rawPeer.app, GetHelperTrieProofsMsg, 42, requests)
   586  		if err := expectResponse(rawPeer.app, HelperTrieProofsMsg, 42, testBufLimit, proofs); err != nil {
   587  			t.Errorf("bit %d: proofs mismatch: %v", bit, err)
   588  		}
   589  	}
   590  }
   591  
   592  func TestTransactionStatusLes2(t *testing.T) { testTransactionStatus(t, lpv2) }
   593  func TestTransactionStatusLes3(t *testing.T) { testTransactionStatus(t, lpv3) }
   594  func TestTransactionStatusLes4(t *testing.T) { testTransactionStatus(t, lpv4) }
   595  
   596  func testTransactionStatus(t *testing.T, protocol int) {
   597  	netconfig := testnetConfig{
   598  		protocol:  protocol,
   599  		nopruning: true,
   600  	}
   601  	server, _, tearDown := newClientServerEnv(t, netconfig)
   602  	defer tearDown()
   603  
   604  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   605  	defer closePeer()
   606  
   607  	server.handler.addTxsSync = true
   608  
   609  	chain := server.handler.blockchain
   610  
   611  	var reqID uint64
   612  
   613  	test := func(tx *types.Transaction, send bool, expStatus light.TxStatus) {
   614  		t.Helper()
   615  
   616  		reqID++
   617  		if send {
   618  			sendRequest(rawPeer.app, SendTxV2Msg, reqID, types.Transactions{tx})
   619  		} else {
   620  			sendRequest(rawPeer.app, GetTxStatusMsg, reqID, []common.Hash{tx.Hash()})
   621  		}
   622  		if err := expectResponse(rawPeer.app, TxStatusMsg, reqID, testBufLimit, []light.TxStatus{expStatus}); err != nil {
   623  			t.Errorf("transaction status mismatch: %v", err)
   624  		}
   625  	}
   626  	signer := types.HomesteadSigner{}
   627  
   628  	// test error status by sending an underpriced transaction
   629  	tx0, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, nil, nil), signer, bankKey)
   630  	test(tx0, true, light.TxStatus{Status: txpool.TxStatusUnknown, Error: "transaction underpriced: tip needed 1, tip permitted 0"})
   631  
   632  	tx1, _ := types.SignTx(types.NewTransaction(0, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey)
   633  	test(tx1, false, light.TxStatus{Status: txpool.TxStatusUnknown}) // query before sending, should be unknown
   634  	test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending})  // send valid processable tx, should return pending
   635  	test(tx1, true, light.TxStatus{Status: txpool.TxStatusPending})  // adding it again should not return an error
   636  
   637  	tx2, _ := types.SignTx(types.NewTransaction(1, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey)
   638  	tx3, _ := types.SignTx(types.NewTransaction(2, userAddr1, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, bankKey)
   639  	// send transactions in the wrong order, tx3 should be queued
   640  	test(tx3, true, light.TxStatus{Status: txpool.TxStatusQueued})
   641  	test(tx2, true, light.TxStatus{Status: txpool.TxStatusPending})
   642  	// query again, now tx3 should be pending too
   643  	test(tx3, false, light.TxStatus{Status: txpool.TxStatusPending})
   644  
   645  	// generate and add a block with tx1 and tx2 included
   646  	gchain, _ := core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 1, func(i int, block *core.BlockGen) {
   647  		block.AddTx(tx1)
   648  		block.AddTx(tx2)
   649  	})
   650  	if _, err := chain.InsertChain(gchain); err != nil {
   651  		panic(err)
   652  	}
   653  	// wait until TxPool processes the inserted block
   654  	for i := 0; i < 10; i++ {
   655  		if pending, _ := server.handler.txpool.Stats(); pending == 1 {
   656  			break
   657  		}
   658  		time.Sleep(100 * time.Millisecond)
   659  	}
   660  	if pending, _ := server.handler.txpool.Stats(); pending != 1 {
   661  		t.Fatalf("pending count mismatch: have %d, want 1", pending)
   662  	}
   663  	// Discard new block announcement
   664  	msg, _ := rawPeer.app.ReadMsg()
   665  	msg.Discard()
   666  
   667  	// check if their status is included now
   668  	block1hash := rawdb.ReadCanonicalHash(server.db, 1)
   669  	test(tx1, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 0}})
   670  
   671  	test(tx2, false, light.TxStatus{Status: txpool.TxStatusIncluded, Lookup: &rawdb.LegacyTxLookupEntry{BlockHash: block1hash, BlockIndex: 1, Index: 1}})
   672  
   673  	// create a reorg that rolls them back
   674  	gchain, _ = core.GenerateChain(params.TestChainConfig, chain.GetBlockByNumber(0), ethash.NewFaker(), server.db, 2, func(i int, block *core.BlockGen) {})
   675  	if _, err := chain.InsertChain(gchain); err != nil {
   676  		panic(err)
   677  	}
   678  	// wait until TxPool processes the reorg
   679  	for i := 0; i < 10; i++ {
   680  		if pending, _ := server.handler.txpool.Stats(); pending == 3 {
   681  			break
   682  		}
   683  		time.Sleep(100 * time.Millisecond)
   684  	}
   685  	if pending, _ := server.handler.txpool.Stats(); pending != 3 {
   686  		t.Fatalf("pending count mismatch: have %d, want 3", pending)
   687  	}
   688  	// Discard new block announcement
   689  	msg, _ = rawPeer.app.ReadMsg()
   690  	msg.Discard()
   691  
   692  	// check if their status is pending again
   693  	test(tx1, false, light.TxStatus{Status: txpool.TxStatusPending})
   694  	test(tx2, false, light.TxStatus{Status: txpool.TxStatusPending})
   695  }
   696  
   697  func TestStopResumeLES3(t *testing.T) { testStopResume(t, lpv3) }
   698  func TestStopResumeLES4(t *testing.T) { testStopResume(t, lpv4) }
   699  
   700  func testStopResume(t *testing.T, protocol int) {
   701  	netconfig := testnetConfig{
   702  		protocol:  protocol,
   703  		simClock:  true,
   704  		nopruning: true,
   705  	}
   706  	server, _, tearDown := newClientServerEnv(t, netconfig)
   707  	defer tearDown()
   708  
   709  	server.handler.server.costTracker.testing = true
   710  	server.handler.server.costTracker.testCostList = testCostList(testBufLimit / 10)
   711  
   712  	rawPeer, closePeer, _ := server.newRawPeer(t, "peer", protocol)
   713  	defer closePeer()
   714  
   715  	var (
   716  		reqID    uint64
   717  		expBuf   = testBufLimit
   718  		testCost = testBufLimit / 10
   719  	)
   720  	header := server.handler.blockchain.CurrentHeader()
   721  	req := func() {
   722  		reqID++
   723  		sendRequest(rawPeer.app, GetBlockHeadersMsg, reqID, &GetBlockHeadersData{Origin: hashOrNumber{Hash: header.Hash()}, Amount: 1})
   724  	}
   725  	for i := 1; i <= 5; i++ {
   726  		// send requests while we still have enough buffer and expect a response
   727  		for expBuf >= testCost {
   728  			req()
   729  			expBuf -= testCost
   730  			if err := expectResponse(rawPeer.app, BlockHeadersMsg, reqID, expBuf, []*types.Header{header}); err != nil {
   731  				t.Errorf("expected response and failed: %v", err)
   732  			}
   733  		}
   734  		// send some more requests in excess and expect a single StopMsg
   735  		c := i
   736  		for c > 0 {
   737  			req()
   738  			c--
   739  		}
   740  		if err := p2p.ExpectMsg(rawPeer.app, StopMsg, nil); err != nil {
   741  			t.Errorf("expected StopMsg and failed: %v", err)
   742  		}
   743  		// wait until the buffer is recharged by half of the limit
   744  		wait := testBufLimit / testBufRecharge / 2
   745  		server.clock.(*mclock.Simulated).Run(time.Millisecond * time.Duration(wait))
   746  
   747  		// expect a ResumeMsg with the partially recharged buffer value
   748  		expBuf += testBufRecharge * wait
   749  		if err := p2p.ExpectMsg(rawPeer.app, ResumeMsg, expBuf); err != nil {
   750  			t.Errorf("expected ResumeMsg and failed: %v", err)
   751  		}
   752  	}
   753  }