github.com/ethereumproject/go-ethereum@v5.5.2+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 "sync" 27 "testing" 28 29 "github.com/ethereumproject/go-ethereum/common" 30 "github.com/ethereumproject/go-ethereum/core" 31 "github.com/ethereumproject/go-ethereum/core/types" 32 "github.com/ethereumproject/go-ethereum/crypto" 33 "github.com/ethereumproject/go-ethereum/eth/downloader" 34 "github.com/ethereumproject/go-ethereum/ethdb" 35 "github.com/ethereumproject/go-ethereum/event" 36 "github.com/ethereumproject/go-ethereum/p2p" 37 "github.com/ethereumproject/go-ethereum/p2p/discover" 38 ) 39 40 var ( 41 testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 42 testBank = core.GenesisAccount{ 43 Address: crypto.PubkeyToAddress(testBankKey.PublicKey), 44 Balance: big.NewInt(1000000), 45 } 46 ) 47 48 // newTestProtocolManager creates a new protocol manager for testing purposes, 49 // with the given number of blocks already known, and potential notification 50 // channels for different events. 51 func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) { 52 var ( 53 evmux = new(event.TypeMux) 54 pow = new(core.FakePow) 55 db, _ = ethdb.NewMemDatabase() 56 genesis = core.WriteGenesisBlockForTesting(db, testBank) 57 chainConfig = &core.ChainConfig{ 58 Forks: []*core.Fork{ 59 { 60 Name: "Homestead", 61 Block: big.NewInt(0), 62 }, 63 }, 64 } 65 blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux) 66 ) 67 68 chain, _ := core.GenerateChain(core.DefaultConfigMorden.ChainConfig, genesis, db, blocks, generator) 69 if res := blockchain.InsertChain(chain); res.Error != nil { 70 panic(res.Error) 71 } 72 73 pm, err := NewProtocolManager(chainConfig, mode, NetworkId, evmux, &testTxPool{added: newtx}, pow, blockchain, db) 74 if err != nil { 75 return nil, nil, err 76 } 77 pm.Start(1000) 78 return pm, db, nil 79 } 80 81 // newTestProtocolManagerMust creates a new protocol manager for testing purposes, 82 // with the given number of blocks already known, and potential notification 83 // channels for different events. In case of an error, the constructor force- 84 // fails the test. 85 func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) { 86 pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx) 87 if err != nil { 88 t.Fatalf("Failed to create protocol manager: %v", err) 89 } 90 return pm, db 91 } 92 93 // testTxPool is a fake, helper transaction pool for testing purposes 94 type testTxPool struct { 95 txFeed event.Feed 96 pool []*types.Transaction // Collection of all transactions 97 added chan<- []*types.Transaction // Notification channel for new transactions 98 99 lock sync.RWMutex // Protects the transaction pool 100 } 101 102 // AddTransactions appends a batch of transactions to the pool, and notifies any 103 // listeners if the addition channel is non nil 104 func (p *testTxPool) AddTransactions(txs []*types.Transaction) { 105 p.lock.Lock() 106 defer p.lock.Unlock() 107 108 p.pool = append(p.pool, txs...) 109 if p.added != nil { 110 p.added <- txs 111 } 112 } 113 114 // GetTransactions returns all the transactions known to the pool 115 func (p *testTxPool) GetTransactions() types.Transactions { 116 p.lock.RLock() 117 defer p.lock.RUnlock() 118 119 txs := make([]*types.Transaction, len(p.pool)) 120 copy(txs, p.pool) 121 122 return txs 123 } 124 125 // newTestTransaction create a new dummy transaction. 126 func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { 127 tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) 128 tx, _ = tx.SignECDSA(from) 129 return tx 130 } 131 132 // testPeer is a simulated peer to allow testing direct network calls. 133 type testPeer struct { 134 net p2p.MsgReadWriter // Network layer reader/writer to simulate remote messaging 135 app *p2p.MsgPipeRW // Application layer reader/writer to simulate the local side 136 *peer 137 } 138 139 // newTestPeer creates a new peer registered at the given protocol manager. 140 func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*testPeer, <-chan error) { 141 // Create a message pipe to communicate through 142 app, net := p2p.MsgPipe() 143 144 // Generate a random id and create the peer 145 var id discover.NodeID 146 rand.Read(id[:]) 147 148 peer := pm.newPeer(version, p2p.NewPeer(id, name, nil), net) 149 150 // Start the peer on a new thread 151 errc := make(chan error, 1) 152 go func() { 153 select { 154 case pm.newPeerCh <- peer: 155 errc <- pm.handle(peer) 156 case <-pm.quitSync: 157 errc <- p2p.DiscQuitting 158 } 159 }() 160 tp := &testPeer{app: app, net: net, peer: peer} 161 // Execute any implicitly requested handshakes and return 162 if shake { 163 td, head, genesis := pm.blockchain.Status() 164 tp.handshake(nil, td, head, genesis) 165 } 166 return tp, errc 167 } 168 169 // handshake simulates a trivial handshake that expects the same state from the 170 // remote side as we are simulating locally. 171 func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, genesis common.Hash) { 172 msg := &statusData{ 173 ProtocolVersion: uint32(p.version), 174 NetworkId: uint32(NetworkId), 175 TD: td, 176 CurrentBlock: head, 177 GenesisBlock: genesis, 178 } 179 if err := p2p.ExpectMsg(p.app, StatusMsg, msg); err != nil { 180 t.Fatalf("status recv: %v", err) 181 } 182 if s, err := p2p.Send(p.app, StatusMsg, msg); err != nil { 183 t.Fatalf("status send: %v", err) 184 } else if s <= 0 { 185 t.Errorf("got: %v, want: >0", s) 186 } 187 } 188 189 // close terminates the local side of the peer, notifying the remote protocol 190 // manager of termination. 191 func (p *testPeer) close() { 192 p.app.Close() 193 }