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