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