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