github.com/ethereum/go-ethereum@v1.16.1/eth/handler_test.go (about)

     1  // Copyright 2015 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 eth
    18  
    19  import (
    20  	"math/big"
    21  	"sort"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/consensus/ethash"
    26  	"github.com/ethereum/go-ethereum/core"
    27  	"github.com/ethereum/go-ethereum/core/rawdb"
    28  	"github.com/ethereum/go-ethereum/core/txpool"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/eth/ethconfig"
    32  	"github.com/ethereum/go-ethereum/ethdb"
    33  	"github.com/ethereum/go-ethereum/event"
    34  	"github.com/ethereum/go-ethereum/params"
    35  	"github.com/ethereum/go-ethereum/rlp"
    36  	"github.com/holiman/uint256"
    37  )
    38  
    39  var (
    40  	// testKey is a private key to use for funding a tester account.
    41  	testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    42  
    43  	// testAddr is the Ethereum address of the tester account.
    44  	testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
    45  )
    46  
    47  // testTxPool is a mock transaction pool that blindly accepts all transactions.
    48  // Its goal is to get around setting up a valid statedb for the balance and nonce
    49  // checks.
    50  type testTxPool struct {
    51  	pool map[common.Hash]*types.Transaction // Hash map of collected transactions
    52  
    53  	txFeed event.Feed   // Notification feed to allow waiting for inclusion
    54  	lock   sync.RWMutex // Protects the transaction pool
    55  }
    56  
    57  // newTestTxPool creates a mock transaction pool.
    58  func newTestTxPool() *testTxPool {
    59  	return &testTxPool{
    60  		pool: make(map[common.Hash]*types.Transaction),
    61  	}
    62  }
    63  
    64  // Has returns an indicator whether txpool has a transaction
    65  // cached with the given hash.
    66  func (p *testTxPool) Has(hash common.Hash) bool {
    67  	p.lock.Lock()
    68  	defer p.lock.Unlock()
    69  
    70  	return p.pool[hash] != nil
    71  }
    72  
    73  // Get retrieves the transaction from local txpool with given
    74  // tx hash.
    75  func (p *testTxPool) Get(hash common.Hash) *types.Transaction {
    76  	p.lock.Lock()
    77  	defer p.lock.Unlock()
    78  	return p.pool[hash]
    79  }
    80  
    81  // Get retrieves the transaction from local txpool with given
    82  // tx hash.
    83  func (p *testTxPool) GetRLP(hash common.Hash) []byte {
    84  	p.lock.Lock()
    85  	defer p.lock.Unlock()
    86  
    87  	tx := p.pool[hash]
    88  	if tx != nil {
    89  		blob, _ := rlp.EncodeToBytes(tx)
    90  		return blob
    91  	}
    92  	return nil
    93  }
    94  
    95  // GetMetadata returns the transaction type and transaction size with the given
    96  // hash.
    97  func (p *testTxPool) GetMetadata(hash common.Hash) *txpool.TxMetadata {
    98  	p.lock.Lock()
    99  	defer p.lock.Unlock()
   100  
   101  	tx := p.pool[hash]
   102  	if tx != nil {
   103  		return &txpool.TxMetadata{
   104  			Type: tx.Type(),
   105  			Size: tx.Size(),
   106  		}
   107  	}
   108  	return nil
   109  }
   110  
   111  // Add appends a batch of transactions to the pool, and notifies any
   112  // listeners if the addition channel is non nil
   113  func (p *testTxPool) Add(txs []*types.Transaction, sync bool) []error {
   114  	p.lock.Lock()
   115  	defer p.lock.Unlock()
   116  
   117  	for _, tx := range txs {
   118  		p.pool[tx.Hash()] = tx
   119  	}
   120  	p.txFeed.Send(core.NewTxsEvent{Txs: txs})
   121  	return make([]error, len(txs))
   122  }
   123  
   124  // Pending returns all the transactions known to the pool
   125  func (p *testTxPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
   126  	p.lock.RLock()
   127  	defer p.lock.RUnlock()
   128  
   129  	batches := make(map[common.Address][]*types.Transaction)
   130  	for _, tx := range p.pool {
   131  		from, _ := types.Sender(types.HomesteadSigner{}, tx)
   132  		batches[from] = append(batches[from], tx)
   133  	}
   134  	for _, batch := range batches {
   135  		sort.Sort(types.TxByNonce(batch))
   136  	}
   137  	pending := make(map[common.Address][]*txpool.LazyTransaction)
   138  	for addr, batch := range batches {
   139  		for _, tx := range batch {
   140  			pending[addr] = append(pending[addr], &txpool.LazyTransaction{
   141  				Hash:      tx.Hash(),
   142  				Tx:        tx,
   143  				Time:      tx.Time(),
   144  				GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
   145  				GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
   146  				Gas:       tx.Gas(),
   147  				BlobGas:   tx.BlobGas(),
   148  			})
   149  		}
   150  	}
   151  	return pending
   152  }
   153  
   154  // SubscribeTransactions should return an event subscription of NewTxsEvent and
   155  // send events to the given channel.
   156  func (p *testTxPool) SubscribeTransactions(ch chan<- core.NewTxsEvent, reorgs bool) event.Subscription {
   157  	return p.txFeed.Subscribe(ch)
   158  }
   159  
   160  // testHandler is a live implementation of the Ethereum protocol handler, just
   161  // preinitialized with some sane testing defaults and the transaction pool mocked
   162  // out.
   163  type testHandler struct {
   164  	db      ethdb.Database
   165  	chain   *core.BlockChain
   166  	txpool  *testTxPool
   167  	handler *handler
   168  }
   169  
   170  // newTestHandler creates a new handler for testing purposes with no blocks.
   171  func newTestHandler() *testHandler {
   172  	return newTestHandlerWithBlocks(0)
   173  }
   174  
   175  // newTestHandlerWithBlocks creates a new handler for testing purposes, with a
   176  // given number of initial blocks.
   177  func newTestHandlerWithBlocks(blocks int) *testHandler {
   178  	// Create a database pre-initialize with a genesis block
   179  	db := rawdb.NewMemoryDatabase()
   180  	gspec := &core.Genesis{
   181  		Config: params.TestChainConfig,
   182  		Alloc:  types.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
   183  	}
   184  	chain, _ := core.NewBlockChain(db, gspec, ethash.NewFaker(), nil)
   185  
   186  	_, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil)
   187  	if _, err := chain.InsertChain(bs); err != nil {
   188  		panic(err)
   189  	}
   190  	txpool := newTestTxPool()
   191  
   192  	handler, _ := newHandler(&handlerConfig{
   193  		Database:   db,
   194  		Chain:      chain,
   195  		TxPool:     txpool,
   196  		Network:    1,
   197  		Sync:       ethconfig.SnapSync,
   198  		BloomCache: 1,
   199  	})
   200  	handler.Start(1000)
   201  
   202  	return &testHandler{
   203  		db:      db,
   204  		chain:   chain,
   205  		txpool:  txpool,
   206  		handler: handler,
   207  	}
   208  }
   209  
   210  // close tears down the handler and all its internal constructs.
   211  func (b *testHandler) close() {
   212  	b.handler.Stop()
   213  	b.chain.Stop()
   214  }