github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/eth/helper_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 // This file contains some shares testing functionality, common to multiple 18 // different files and modules being tested. 19 20 package eth 21 22 import ( 23 "crypto/ecdsa" 24 "crypto/rand" 25 "math/big" 26 "sort" 27 "sync" 28 "testing" 29 30 "github.com/ethereum/go-ethereum/consensus" 31 "github.com/ethereum/go-ethereum/consensus/clique" 32 "github.com/ethereum/go-ethereum/consensus/istanbul" 33 istanbulBackend "github.com/ethereum/go-ethereum/consensus/istanbul/backend" 34 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/consensus/ethash" 37 "github.com/ethereum/go-ethereum/core" 38 "github.com/ethereum/go-ethereum/core/types" 39 "github.com/ethereum/go-ethereum/core/vm" 40 "github.com/ethereum/go-ethereum/crypto" 41 "github.com/ethereum/go-ethereum/eth/downloader" 42 "github.com/ethereum/go-ethereum/ethdb" 43 "github.com/ethereum/go-ethereum/event" 44 "github.com/ethereum/go-ethereum/p2p" 45 "github.com/ethereum/go-ethereum/p2p/enode" 46 "github.com/ethereum/go-ethereum/params" 47 ) 48 49 var ( 50 testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 51 testBank = crypto.PubkeyToAddress(testBankKey.PublicKey) 52 ) 53 54 // newTestProtocolManager creates a new protocol manager for testing purposes, 55 // with the given number of blocks already known, and potential notification 56 // channels for different events. 57 func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) { 58 var ( 59 evmux = new(event.TypeMux) 60 engine = ethash.NewFaker() 61 db = ethdb.NewMemDatabase() 62 gspec = &core.Genesis{ 63 Config: params.TestChainConfig, 64 Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}}, 65 } 66 genesis = gspec.MustCommit(db) 67 blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil) 68 ) 69 chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator) 70 if _, err := blockchain.InsertChain(chain); err != nil { 71 panic(err) 72 } 73 74 pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db, false) 75 if err != nil { 76 return nil, nil, err 77 } 78 pm.Start(1000) 79 return pm, db, nil 80 } 81 82 // newTestProtocolManagerConsensus creates a new protocol manager for testing purposes, 83 // that uses the specified consensus mechanism. 84 func newTestProtocolManagerConsensus(consensusAlgo string, cliqueConfig *params.CliqueConfig, istanbulConfig *params.IstanbulConfig, raftMode bool) (*ProtocolManager, *ethdb.MemDatabase, error) { 85 86 config := params.QuorumTestChainConfig 87 config.Clique = cliqueConfig 88 config.Istanbul = istanbulConfig 89 90 var ( 91 blocks = 0 92 evmux = new(event.TypeMux) 93 engine consensus.Engine = ethash.NewFaker() 94 db = ethdb.NewMemDatabase() 95 gspec = &core.Genesis{ 96 Config: params.TestChainConfig, 97 Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}}, 98 } 99 genesis = gspec.MustCommit(db) 100 blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil) 101 ) 102 chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, nil) 103 if _, err := blockchain.InsertChain(chain); err != nil { 104 panic(err) 105 } 106 107 switch consensusAlgo { 108 case "raft": 109 engine = ethash.NewFaker() //raft doesn't use engine, but just mirroring what runtime code does 110 111 case "istanbul": 112 var istanbul istanbul.Config 113 config.Istanbul.Epoch = istanbulConfig.Epoch 114 config.Istanbul.ProposerPolicy = istanbulConfig.ProposerPolicy 115 116 nodeKey, _ := crypto.GenerateKey() 117 engine = istanbulBackend.New(&istanbul, nodeKey, db) 118 119 case "clique": 120 engine = clique.New(config.Clique, db) 121 122 default: 123 engine = ethash.NewFaker() 124 } 125 126 pm, err := NewProtocolManager(config, 61, DefaultConfig.NetworkId, evmux, &testTxPool{added: nil}, engine, blockchain, db, raftMode) 127 if err != nil { 128 return nil, nil, err 129 } 130 pm.Start(1000) 131 return pm, db, nil 132 } 133 134 // newTestProtocolManagerMust creates a new protocol manager for testing purposes, 135 // with the given number of blocks already known, and potential notification 136 // channels for different events. In case of an error, the constructor force- 137 // fails the test. 138 func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) { 139 pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx) 140 if err != nil { 141 t.Fatalf("Failed to create protocol manager: %v", err) 142 } 143 return pm, db 144 } 145 146 // testTxPool is a fake, helper transaction pool for testing purposes 147 type testTxPool struct { 148 txFeed event.Feed 149 pool []*types.Transaction // Collection of all transactions 150 added chan<- []*types.Transaction // Notification channel for new transactions 151 152 lock sync.RWMutex // Protects the transaction pool 153 } 154 155 // AddRemotes appends a batch of transactions to the pool, and notifies any 156 // listeners if the addition channel is non nil 157 func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { 158 p.lock.Lock() 159 defer p.lock.Unlock() 160 161 p.pool = append(p.pool, txs...) 162 if p.added != nil { 163 p.added <- txs 164 } 165 return make([]error, len(txs)) 166 } 167 168 // Pending returns all the transactions known to the pool 169 func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { 170 p.lock.RLock() 171 defer p.lock.RUnlock() 172 173 batches := make(map[common.Address]types.Transactions) 174 for _, tx := range p.pool { 175 from, _ := types.Sender(types.HomesteadSigner{}, tx) 176 batches[from] = append(batches[from], tx) 177 } 178 for _, batch := range batches { 179 sort.Sort(types.TxByNonce(batch)) 180 } 181 return batches, nil 182 } 183 184 func (p *testTxPool) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 185 return p.txFeed.Subscribe(ch) 186 } 187 188 // newTestTransaction create a new dummy transaction. 189 func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { 190 tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, datasize)) 191 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) 192 return tx 193 } 194 195 // testPeer is a simulated peer to allow testing direct network calls. 196 type testPeer struct { 197 net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging 198 app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side 199 *peer 200 } 201 202 // newTestPeer creates a new peer registered at the given protocol manager. 203 func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*testPeer, <-chan error) { 204 // Create a message pipe to communicate through 205 app, net := p2p.MsgPipe() 206 207 // Generate a random id and create the peer 208 var id enode.ID 209 rand.Read(id[:]) 210 211 peer := pm.newPeer(version, p2p.NewPeer(id, name, nil), net) 212 213 // Start the peer on a new thread 214 errc := make(chan error, 1) 215 go func() { 216 select { 217 case pm.newPeerCh <- peer: 218 errc <- pm.handle(peer) 219 case <-pm.quitSync: 220 errc <- p2p.DiscQuitting 221 } 222 }() 223 tp := &testPeer{app: app, net: net, peer: peer} 224 // Execute any implicitly requested handshakes and return 225 if shake { 226 var ( 227 genesis = pm.blockchain.Genesis() 228 head = pm.blockchain.CurrentHeader() 229 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 230 ) 231 tp.handshake(nil, td, head.Hash(), genesis.Hash()) 232 } 233 return tp, errc 234 } 235 236 // handshake simulates a trivial handshake that expects the same state from the 237 // remote side as we are simulating locally. 238 func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, genesis common.Hash) { 239 msg := &statusData{ 240 ProtocolVersion: uint32(p.version), 241 NetworkId: DefaultConfig.NetworkId, 242 TD: td, 243 CurrentBlock: head, 244 GenesisBlock: genesis, 245 } 246 if err := p2p.ExpectMsg(p.app, StatusMsg, msg); err != nil { 247 t.Fatalf("status recv: %v", err) 248 } 249 if err := p2p.Send(p.app, StatusMsg, msg); err != nil { 250 t.Fatalf("status send: %v", err) 251 } 252 } 253 254 // close terminates the local side of the peer, notifying the remote protocol 255 // manager of termination. 256 func (p *testPeer) close() { 257 p.app.Close() 258 }