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 }