github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/les/handler_test.go (about)

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