github.com/ethereum/go-ethereum@v1.16.1/eth/handler_eth_test.go (about) 1 // Copyright 2020 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 package eth 18 19 import ( 20 "fmt" 21 "math/big" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/consensus/ethash" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/rawdb" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/eth/ethconfig" 31 "github.com/ethereum/go-ethereum/eth/protocols/eth" 32 "github.com/ethereum/go-ethereum/event" 33 "github.com/ethereum/go-ethereum/p2p" 34 "github.com/ethereum/go-ethereum/p2p/enode" 35 "github.com/ethereum/go-ethereum/params" 36 ) 37 38 // testEthHandler is a mock event handler to listen for inbound network requests 39 // on the `eth` protocol and convert them into a more easily testable form. 40 type testEthHandler struct { 41 blockBroadcasts event.Feed 42 txAnnounces event.Feed 43 txBroadcasts event.Feed 44 } 45 46 func (h *testEthHandler) Chain() *core.BlockChain { panic("no backing chain") } 47 func (h *testEthHandler) TxPool() eth.TxPool { panic("no backing tx pool") } 48 func (h *testEthHandler) AcceptTxs() bool { return true } 49 func (h *testEthHandler) RunPeer(*eth.Peer, eth.Handler) error { panic("not used in tests") } 50 func (h *testEthHandler) PeerInfo(enode.ID) interface{} { panic("not used in tests") } 51 52 func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error { 53 switch packet := packet.(type) { 54 case *eth.NewBlockPacket: 55 h.blockBroadcasts.Send(packet.Block) 56 return nil 57 58 case *eth.NewPooledTransactionHashesPacket: 59 h.txAnnounces.Send(packet.Hashes) 60 return nil 61 62 case *eth.TransactionsPacket: 63 h.txBroadcasts.Send(([]*types.Transaction)(*packet)) 64 return nil 65 66 case *eth.PooledTransactionsResponse: 67 h.txBroadcasts.Send(([]*types.Transaction)(*packet)) 68 return nil 69 70 default: 71 panic(fmt.Sprintf("unexpected eth packet type in tests: %T", packet)) 72 } 73 } 74 75 // Tests that peers are correctly accepted (or rejected) based on the advertised 76 // fork IDs in the protocol handshake. 77 func TestForkIDSplit68(t *testing.T) { testForkIDSplit(t, eth.ETH68) } 78 79 func testForkIDSplit(t *testing.T, protocol uint) { 80 t.Parallel() 81 82 var ( 83 engine = ethash.NewFaker() 84 85 configNoFork = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)} 86 configProFork = ¶ms.ChainConfig{ 87 HomesteadBlock: big.NewInt(1), 88 EIP150Block: big.NewInt(2), 89 EIP155Block: big.NewInt(2), 90 EIP158Block: big.NewInt(2), 91 ByzantiumBlock: big.NewInt(3), 92 } 93 dbNoFork = rawdb.NewMemoryDatabase() 94 dbProFork = rawdb.NewMemoryDatabase() 95 96 gspecNoFork = &core.Genesis{Config: configNoFork} 97 gspecProFork = &core.Genesis{Config: configProFork} 98 99 chainNoFork, _ = core.NewBlockChain(dbNoFork, gspecNoFork, engine, nil) 100 chainProFork, _ = core.NewBlockChain(dbProFork, gspecProFork, engine, nil) 101 102 _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) 103 _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) 104 105 ethNoFork, _ = newHandler(&handlerConfig{ 106 Database: dbNoFork, 107 Chain: chainNoFork, 108 TxPool: newTestTxPool(), 109 Network: 1, 110 Sync: ethconfig.FullSync, 111 BloomCache: 1, 112 }) 113 ethProFork, _ = newHandler(&handlerConfig{ 114 Database: dbProFork, 115 Chain: chainProFork, 116 TxPool: newTestTxPool(), 117 Network: 1, 118 Sync: ethconfig.FullSync, 119 BloomCache: 1, 120 }) 121 ) 122 ethNoFork.Start(1000) 123 ethProFork.Start(1000) 124 125 // Clean up everything after ourselves 126 defer chainNoFork.Stop() 127 defer chainProFork.Stop() 128 129 defer ethNoFork.Stop() 130 defer ethProFork.Stop() 131 132 // Both nodes should allow the other to connect (same genesis, next fork is the same) 133 p2pNoFork, p2pProFork := p2p.MsgPipe() 134 defer p2pNoFork.Close() 135 defer p2pProFork.Close() 136 137 peerNoFork := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pNoFork), p2pNoFork, nil) 138 peerProFork := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pProFork), p2pProFork, nil) 139 defer peerNoFork.Close() 140 defer peerProFork.Close() 141 142 errc := make(chan error, 2) 143 go func(errc chan error) { 144 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *eth.Peer) error { return nil }) 145 }(errc) 146 go func(errc chan error) { 147 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *eth.Peer) error { return nil }) 148 }(errc) 149 150 for i := 0; i < 2; i++ { 151 select { 152 case err := <-errc: 153 if err != nil { 154 t.Fatalf("frontier nofork <-> profork failed: %v", err) 155 } 156 case <-time.After(250 * time.Millisecond): 157 t.Fatalf("frontier nofork <-> profork handler timeout") 158 } 159 } 160 // Progress into Homestead. Fork's match, so we don't care what the future holds 161 chainNoFork.InsertChain(blocksNoFork[:1]) 162 chainProFork.InsertChain(blocksProFork[:1]) 163 164 p2pNoFork, p2pProFork = p2p.MsgPipe() 165 defer p2pNoFork.Close() 166 defer p2pProFork.Close() 167 168 peerNoFork = eth.NewPeer(protocol, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 169 peerProFork = eth.NewPeer(protocol, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 170 defer peerNoFork.Close() 171 defer peerProFork.Close() 172 173 errc = make(chan error, 2) 174 go func(errc chan error) { 175 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *eth.Peer) error { return nil }) 176 }(errc) 177 go func(errc chan error) { 178 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *eth.Peer) error { return nil }) 179 }(errc) 180 181 for i := 0; i < 2; i++ { 182 select { 183 case err := <-errc: 184 if err != nil { 185 t.Fatalf("homestead nofork <-> profork failed: %v", err) 186 } 187 case <-time.After(250 * time.Millisecond): 188 t.Fatalf("homestead nofork <-> profork handler timeout") 189 } 190 } 191 // Progress into Spurious. Forks mismatch, signalling differing chains, reject 192 chainNoFork.InsertChain(blocksNoFork[1:2]) 193 chainProFork.InsertChain(blocksProFork[1:2]) 194 195 p2pNoFork, p2pProFork = p2p.MsgPipe() 196 defer p2pNoFork.Close() 197 defer p2pProFork.Close() 198 199 peerNoFork = eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pNoFork), p2pNoFork, nil) 200 peerProFork = eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pProFork), p2pProFork, nil) 201 defer peerNoFork.Close() 202 defer peerProFork.Close() 203 204 errc = make(chan error, 2) 205 go func(errc chan error) { 206 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *eth.Peer) error { return nil }) 207 }(errc) 208 go func(errc chan error) { 209 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *eth.Peer) error { return nil }) 210 }(errc) 211 212 var successes int 213 for i := 0; i < 2; i++ { 214 select { 215 case err := <-errc: 216 if err == nil { 217 successes++ 218 if successes == 2 { // Only one side disconnects 219 t.Fatalf("fork ID rejection didn't happen") 220 } 221 } 222 case <-time.After(250 * time.Millisecond): 223 t.Fatalf("split peers not rejected") 224 } 225 } 226 } 227 228 // Tests that received transactions are added to the local pool. 229 func TestRecvTransactions68(t *testing.T) { testRecvTransactions(t, eth.ETH68) } 230 231 func testRecvTransactions(t *testing.T, protocol uint) { 232 t.Parallel() 233 234 // Create a message handler, configure it to accept transactions and watch them 235 handler := newTestHandler() 236 defer handler.close() 237 238 handler.handler.synced.Store(true) // mark synced to accept transactions 239 240 txs := make(chan core.NewTxsEvent) 241 sub := handler.txpool.SubscribeTransactions(txs, false) 242 defer sub.Unsubscribe() 243 244 // Create a source peer to send messages through and a sink handler to receive them 245 p2pSrc, p2pSink := p2p.MsgPipe() 246 defer p2pSrc.Close() 247 defer p2pSink.Close() 248 249 src := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, handler.txpool) 250 sink := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, handler.txpool) 251 defer src.Close() 252 defer sink.Close() 253 254 go handler.handler.runEthPeer(sink, func(peer *eth.Peer) error { 255 return eth.Handle((*ethHandler)(handler.handler), peer) 256 }) 257 // Run the handshake locally to avoid spinning up a source handler 258 if err := src.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{}); err != nil { 259 t.Fatalf("failed to run protocol handshake") 260 } 261 // Send the transaction to the sink and verify that it's added to the tx pool 262 tx := types.NewTransaction(0, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) 263 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 264 265 if err := src.SendTransactions([]*types.Transaction{tx}); err != nil { 266 t.Fatalf("failed to send transaction: %v", err) 267 } 268 select { 269 case event := <-txs: 270 if len(event.Txs) != 1 { 271 t.Errorf("wrong number of added transactions: got %d, want 1", len(event.Txs)) 272 } else if event.Txs[0].Hash() != tx.Hash() { 273 t.Errorf("added wrong tx hash: got %v, want %v", event.Txs[0].Hash(), tx.Hash()) 274 } 275 case <-time.After(2 * time.Second): 276 t.Errorf("no NewTxsEvent received within 2 seconds") 277 } 278 } 279 280 // This test checks that pending transactions are sent. 281 func TestSendTransactions68(t *testing.T) { testSendTransactions(t, eth.ETH68) } 282 283 func testSendTransactions(t *testing.T, protocol uint) { 284 t.Parallel() 285 286 // Create a message handler and fill the pool with big transactions 287 handler := newTestHandler() 288 defer handler.close() 289 290 insert := make([]*types.Transaction, 100) 291 for nonce := range insert { 292 tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, 10240)) 293 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 294 insert[nonce] = tx 295 } 296 go handler.txpool.Add(insert, false) // Need goroutine to not block on feed 297 time.Sleep(250 * time.Millisecond) // Wait until tx events get out of the system (can't use events, tx broadcaster races with peer join) 298 299 // Create a source handler to send messages through and a sink peer to receive them 300 p2pSrc, p2pSink := p2p.MsgPipe() 301 defer p2pSrc.Close() 302 defer p2pSink.Close() 303 304 src := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, handler.txpool) 305 sink := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, handler.txpool) 306 defer src.Close() 307 defer sink.Close() 308 309 go handler.handler.runEthPeer(src, func(peer *eth.Peer) error { 310 return eth.Handle((*ethHandler)(handler.handler), peer) 311 }) 312 // Run the handshake locally to avoid spinning up a source handler 313 if err := sink.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{}); err != nil { 314 t.Fatalf("failed to run protocol handshake") 315 } 316 // After the handshake completes, the source handler should stream the sink 317 // the transactions, subscribe to all inbound network events 318 backend := new(testEthHandler) 319 320 anns := make(chan []common.Hash) 321 annSub := backend.txAnnounces.Subscribe(anns) 322 defer annSub.Unsubscribe() 323 324 bcasts := make(chan []*types.Transaction) 325 bcastSub := backend.txBroadcasts.Subscribe(bcasts) 326 defer bcastSub.Unsubscribe() 327 328 go eth.Handle(backend, sink) 329 330 // Make sure we get all the transactions on the correct channels 331 seen := make(map[common.Hash]struct{}) 332 for len(seen) < len(insert) { 333 switch protocol { 334 case 68: 335 select { 336 case hashes := <-anns: 337 for _, hash := range hashes { 338 if _, ok := seen[hash]; ok { 339 t.Errorf("duplicate transaction announced: %x", hash) 340 } 341 seen[hash] = struct{}{} 342 } 343 case <-bcasts: 344 t.Errorf("initial tx broadcast received on post eth/66") 345 } 346 347 default: 348 panic("unsupported protocol, please extend test") 349 } 350 } 351 for _, tx := range insert { 352 if _, ok := seen[tx.Hash()]; !ok { 353 t.Errorf("missing transaction: %x", tx.Hash()) 354 } 355 } 356 } 357 358 // Tests that transactions get propagated to all attached peers, either via direct 359 // broadcasts or via announcements/retrievals. 360 func TestTransactionPropagation68(t *testing.T) { testTransactionPropagation(t, eth.ETH68) } 361 362 func testTransactionPropagation(t *testing.T, protocol uint) { 363 t.Parallel() 364 365 // Create a source handler to send transactions from and a number of sinks 366 // to receive them. We need multiple sinks since a one-to-one peering would 367 // broadcast all transactions without announcement. 368 source := newTestHandler() 369 source.handler.snapSync.Store(false) // Avoid requiring snap, otherwise some will be dropped below 370 defer source.close() 371 372 sinks := make([]*testHandler, 10) 373 for i := 0; i < len(sinks); i++ { 374 sinks[i] = newTestHandler() 375 defer sinks[i].close() 376 377 sinks[i].handler.synced.Store(true) // mark synced to accept transactions 378 } 379 // Interconnect all the sink handlers with the source handler 380 for i, sink := range sinks { 381 sourcePipe, sinkPipe := p2p.MsgPipe() 382 defer sourcePipe.Close() 383 defer sinkPipe.Close() 384 385 sourcePeer := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{byte(i + 1)}, "", nil, sourcePipe), sourcePipe, source.txpool) 386 sinkPeer := eth.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, sink.txpool) 387 defer sourcePeer.Close() 388 defer sinkPeer.Close() 389 390 go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { 391 return eth.Handle((*ethHandler)(source.handler), peer) 392 }) 393 go sink.handler.runEthPeer(sinkPeer, func(peer *eth.Peer) error { 394 return eth.Handle((*ethHandler)(sink.handler), peer) 395 }) 396 } 397 // Subscribe to all the transaction pools 398 txChs := make([]chan core.NewTxsEvent, len(sinks)) 399 for i := 0; i < len(sinks); i++ { 400 txChs[i] = make(chan core.NewTxsEvent, 1024) 401 402 sub := sinks[i].txpool.SubscribeTransactions(txChs[i], false) 403 defer sub.Unsubscribe() 404 } 405 // Fill the source pool with transactions and wait for them at the sinks 406 txs := make([]*types.Transaction, 1024) 407 for nonce := range txs { 408 tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) 409 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 410 txs[nonce] = tx 411 } 412 source.txpool.Add(txs, false) 413 414 // Iterate through all the sinks and ensure they all got the transactions 415 for i := range sinks { 416 for arrived, timeout := 0, false; arrived < len(txs) && !timeout; { 417 select { 418 case event := <-txChs[i]: 419 arrived += len(event.Txs) 420 case <-time.After(2 * time.Second): 421 t.Errorf("sink %d: transaction propagation timed out: have %d, want %d", i, arrived, len(txs)) 422 timeout = true 423 } 424 } 425 } 426 }