github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/les/handler_test.go (about)

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