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