github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/eth/helper_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 // This file contains some shares testing functionality, common to multiple 13 // different files and modules being tested. 14 15 package eth 16 17 import ( 18 "crypto/ecdsa" 19 "crypto/rand" 20 "math/big" 21 "sort" 22 "sync" 23 "testing" 24 25 "github.com/Sberex/go-sberex/common" 26 "github.com/Sberex/go-sberex/consensus/ethash" 27 "github.com/Sberex/go-sberex/core" 28 "github.com/Sberex/go-sberex/core/types" 29 "github.com/Sberex/go-sberex/core/vm" 30 "github.com/Sberex/go-sberex/crypto" 31 "github.com/Sberex/go-sberex/eth/downloader" 32 "github.com/Sberex/go-sberex/ethdb" 33 "github.com/Sberex/go-sberex/event" 34 "github.com/Sberex/go-sberex/p2p" 35 "github.com/Sberex/go-sberex/p2p/discover" 36 "github.com/Sberex/go-sberex/params" 37 ) 38 39 var ( 40 testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 41 testBank = crypto.PubkeyToAddress(testBankKey.PublicKey) 42 ) 43 44 // newTestProtocolManager creates a new protocol manager for testing purposes, 45 // with the given number of blocks already known, and potential notification 46 // channels for different events. 47 func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase, error) { 48 var ( 49 evmux = new(event.TypeMux) 50 engine = ethash.NewFaker() 51 db, _ = ethdb.NewMemDatabase() 52 gspec = &core.Genesis{ 53 Config: params.TestChainConfig, 54 Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}}, 55 } 56 genesis = gspec.MustCommit(db) 57 blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}) 58 ) 59 chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator) 60 if _, err := blockchain.InsertChain(chain); err != nil { 61 panic(err) 62 } 63 64 pm, err := NewProtocolManager(gspec.Config, mode, DefaultConfig.NetworkId, evmux, &testTxPool{added: newtx}, engine, blockchain, db) 65 if err != nil { 66 return nil, nil, err 67 } 68 pm.Start(1000) 69 return pm, db, nil 70 } 71 72 // newTestProtocolManagerMust creates a new protocol manager for testing purposes, 73 // with the given number of blocks already known, and potential notification 74 // channels for different events. In case of an error, the constructor force- 75 // fails the test. 76 func newTestProtocolManagerMust(t *testing.T, mode downloader.SyncMode, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, *ethdb.MemDatabase) { 77 pm, db, err := newTestProtocolManager(mode, blocks, generator, newtx) 78 if err != nil { 79 t.Fatalf("Failed to create protocol manager: %v", err) 80 } 81 return pm, db 82 } 83 84 // testTxPool is a fake, helper transaction pool for testing purposes 85 type testTxPool struct { 86 txFeed event.Feed 87 pool []*types.Transaction // Collection of all transactions 88 added chan<- []*types.Transaction // Notification channel for new transactions 89 90 lock sync.RWMutex // Protects the transaction pool 91 } 92 93 // AddRemotes appends a batch of transactions to the pool, and notifies any 94 // listeners if the addition channel is non nil 95 func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { 96 p.lock.Lock() 97 defer p.lock.Unlock() 98 99 p.pool = append(p.pool, txs...) 100 if p.added != nil { 101 p.added <- txs 102 } 103 return make([]error, len(txs)) 104 } 105 106 // Pending returns all the transactions known to the pool 107 func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { 108 p.lock.RLock() 109 defer p.lock.RUnlock() 110 111 batches := make(map[common.Address]types.Transactions) 112 for _, tx := range p.pool { 113 from, _ := types.Sender(types.HomesteadSigner{}, tx) 114 batches[from] = append(batches[from], tx) 115 } 116 for _, batch := range batches { 117 sort.Sort(types.TxByNonce(batch)) 118 } 119 return batches, nil 120 } 121 122 func (p *testTxPool) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription { 123 return p.txFeed.Subscribe(ch) 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), 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 var ( 165 genesis = pm.blockchain.Genesis() 166 head = pm.blockchain.CurrentHeader() 167 td = pm.blockchain.GetTd(head.Hash(), head.Number.Uint64()) 168 ) 169 tp.handshake(nil, td, head.Hash(), genesis.Hash()) 170 } 171 return tp, errc 172 } 173 174 // handshake simulates a trivial handshake that expects the same state from the 175 // remote side as we are simulating locally. 176 func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, genesis common.Hash) { 177 msg := &statusData{ 178 ProtocolVersion: uint32(p.version), 179 NetworkId: DefaultConfig.NetworkId, 180 TD: td, 181 CurrentBlock: head, 182 GenesisBlock: genesis, 183 } 184 if err := p2p.ExpectMsg(p.app, StatusMsg, msg); err != nil { 185 t.Fatalf("status recv: %v", err) 186 } 187 if err := p2p.Send(p.app, StatusMsg, msg); err != nil { 188 t.Fatalf("status send: %v", err) 189 } 190 } 191 192 // close terminates the local side of the peer, notifying the remote protocol 193 // manager of termination. 194 func (p *testPeer) close() { 195 p.app.Close() 196 }