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