github.com/carter-ya/go-ethereum@v0.0.0-20230628080049-d2309be3983b/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"
    26  	"github.com/ethereum/go-ethereum/consensus/ethash"
    27  	"github.com/ethereum/go-ethereum/core"
    28  	"github.com/ethereum/go-ethereum/core/rawdb"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/core/vm"
    31  	"github.com/ethereum/go-ethereum/crypto"
    32  	"github.com/ethereum/go-ethereum/eth/downloader"
    33  	"github.com/ethereum/go-ethereum/ethdb"
    34  	"github.com/ethereum/go-ethereum/event"
    35  	"github.com/ethereum/go-ethereum/params"
    36  )
    37  
    38  var (
    39  	// testKey is a private key to use for funding a tester account.
    40  	testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    41  
    42  	// testAddr is the Ethereum address of the tester account.
    43  	testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
    44  )
    45  
    46  // testTxPool is a mock transaction pool that blindly accepts all transactions.
    47  // Its goal is to get around setting up a valid statedb for the balance and nonce
    48  // checks.
    49  type testTxPool struct {
    50  	pool map[common.Hash]*types.Transaction // Hash map of collected transactions
    51  
    52  	txFeed event.Feed   // Notification feed to allow waiting for inclusion
    53  	lock   sync.RWMutex // Protects the transaction pool
    54  }
    55  
    56  // newTestTxPool creates a mock transaction pool.
    57  func newTestTxPool() *testTxPool {
    58  	return &testTxPool{
    59  		pool: make(map[common.Hash]*types.Transaction),
    60  	}
    61  }
    62  
    63  // Has returns an indicator whether txpool has a transaction
    64  // cached with the given hash.
    65  func (p *testTxPool) Has(hash common.Hash) bool {
    66  	p.lock.Lock()
    67  	defer p.lock.Unlock()
    68  
    69  	return p.pool[hash] != nil
    70  }
    71  
    72  // Get retrieves the transaction from local txpool with given
    73  // tx hash.
    74  func (p *testTxPool) Get(hash common.Hash) *types.Transaction {
    75  	p.lock.Lock()
    76  	defer p.lock.Unlock()
    77  
    78  	return p.pool[hash]
    79  }
    80  
    81  // AddRemotes appends a batch of transactions to the pool, and notifies any
    82  // listeners if the addition channel is non nil
    83  func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error {
    84  	p.lock.Lock()
    85  	defer p.lock.Unlock()
    86  
    87  	for _, tx := range txs {
    88  		p.pool[tx.Hash()] = tx
    89  	}
    90  	p.txFeed.Send(core.NewTxsEvent{Txs: txs})
    91  	return make([]error, len(txs))
    92  }
    93  
    94  // Pending returns all the transactions known to the pool
    95  func (p *testTxPool) Pending(enforceTips bool) map[common.Address]types.Transactions {
    96  	p.lock.RLock()
    97  	defer p.lock.RUnlock()
    98  
    99  	batches := make(map[common.Address]types.Transactions)
   100  	for _, tx := range p.pool {
   101  		from, _ := types.Sender(types.HomesteadSigner{}, tx)
   102  		batches[from] = append(batches[from], tx)
   103  	}
   104  	for _, batch := range batches {
   105  		sort.Sort(types.TxByNonce(batch))
   106  	}
   107  	return batches
   108  }
   109  
   110  // SubscribeNewTxsEvent should return an event subscription of NewTxsEvent and
   111  // send events to the given channel.
   112  func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
   113  	return p.txFeed.Subscribe(ch)
   114  }
   115  
   116  // testHandler is a live implementation of the Ethereum protocol handler, just
   117  // preinitialized with some sane testing defaults and the transaction pool mocked
   118  // out.
   119  type testHandler struct {
   120  	db      ethdb.Database
   121  	chain   *core.BlockChain
   122  	txpool  *testTxPool
   123  	handler *handler
   124  }
   125  
   126  // newTestHandler creates a new handler for testing purposes with no blocks.
   127  func newTestHandler() *testHandler {
   128  	return newTestHandlerWithBlocks(0)
   129  }
   130  
   131  // newTestHandlerWithBlocks creates a new handler for testing purposes, with a
   132  // given number of initial blocks.
   133  func newTestHandlerWithBlocks(blocks int) *testHandler {
   134  	// Create a database pre-initialize with a genesis block
   135  	db := rawdb.NewMemoryDatabase()
   136  	gspec := &core.Genesis{
   137  		Config: params.TestChainConfig,
   138  		Alloc:  core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
   139  	}
   140  	chain, _ := core.NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
   141  
   142  	_, bs, _ := core.GenerateChainWithGenesis(gspec, ethash.NewFaker(), blocks, nil)
   143  	if _, err := chain.InsertChain(bs); err != nil {
   144  		panic(err)
   145  	}
   146  	txpool := newTestTxPool()
   147  
   148  	handler, _ := newHandler(&handlerConfig{
   149  		Database:   db,
   150  		Chain:      chain,
   151  		TxPool:     txpool,
   152  		Merger:     consensus.NewMerger(rawdb.NewMemoryDatabase()),
   153  		Network:    1,
   154  		Sync:       downloader.SnapSync,
   155  		BloomCache: 1,
   156  	})
   157  	handler.Start(1000)
   158  
   159  	return &testHandler{
   160  		db:      db,
   161  		chain:   chain,
   162  		txpool:  txpool,
   163  		handler: handler,
   164  	}
   165  }
   166  
   167  // close tears down the handler and all its internal constructs.
   168  func (b *testHandler) close() {
   169  	b.handler.Stop()
   170  	b.chain.Stop()
   171  }