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