github.com/theQRL/go-zond@v0.1.1/zond/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 zond 18 19 import ( 20 "fmt" 21 "math/big" 22 "testing" 23 "time" 24 25 "github.com/theQRL/go-zond/common" 26 "github.com/theQRL/go-zond/consensus" 27 "github.com/theQRL/go-zond/consensus/ethash" 28 "github.com/theQRL/go-zond/core" 29 "github.com/theQRL/go-zond/core/forkid" 30 "github.com/theQRL/go-zond/core/rawdb" 31 "github.com/theQRL/go-zond/core/types" 32 "github.com/theQRL/go-zond/core/vm" 33 "github.com/theQRL/go-zond/event" 34 "github.com/theQRL/go-zond/p2p" 35 "github.com/theQRL/go-zond/p2p/enode" 36 "github.com/theQRL/go-zond/params" 37 "github.com/theQRL/go-zond/zond/downloader" 38 "github.com/theQRL/go-zond/zond/protocols/zond" 39 ) 40 41 // testEthHandler is a mock event handler to listen for inbound network requests 42 // on the `zond` protocol and convert them into a more easily testable form. 43 type testEthHandler struct { 44 blockBroadcasts event.Feed 45 txAnnounces event.Feed 46 txBroadcasts event.Feed 47 } 48 49 func (h *testEthHandler) Chain() *core.BlockChain { panic("no backing chain") } 50 func (h *testEthHandler) TxPool() zond.TxPool { panic("no backing tx pool") } 51 func (h *testEthHandler) AcceptTxs() bool { return true } 52 func (h *testEthHandler) RunPeer(*zond.Peer, zond.Handler) error { panic("not used in tests") } 53 func (h *testEthHandler) PeerInfo(enode.ID) interface{} { panic("not used in tests") } 54 55 func (h *testEthHandler) Handle(peer *zond.Peer, packet zond.Packet) error { 56 switch packet := packet.(type) { 57 case *zond.NewBlockPacket: 58 h.blockBroadcasts.Send(packet.Block) 59 return nil 60 61 case *zond.NewPooledTransactionHashesPacket66: 62 h.txAnnounces.Send(([]common.Hash)(*packet)) 63 return nil 64 65 case *zond.NewPooledTransactionHashesPacket68: 66 h.txAnnounces.Send(packet.Hashes) 67 return nil 68 69 case *zond.TransactionsPacket: 70 h.txBroadcasts.Send(([]*types.Transaction)(*packet)) 71 return nil 72 73 case *zond.PooledTransactionsPacket: 74 h.txBroadcasts.Send(([]*types.Transaction)(*packet)) 75 return nil 76 77 default: 78 panic(fmt.Sprintf("unexpected zond packet type in tests: %T", packet)) 79 } 80 } 81 82 // Tests that peers are correctly accepted (or rejected) based on the advertised 83 // fork IDs in the protocol handshake. 84 func TestForkIDSplit66(t *testing.T) { testForkIDSplit(t, zond.ETH66) } 85 func TestForkIDSplit67(t *testing.T) { testForkIDSplit(t, zond.ETH67) } 86 func TestForkIDSplit68(t *testing.T) { testForkIDSplit(t, zond.ETH68) } 87 88 func testForkIDSplit(t *testing.T, protocol uint) { 89 t.Parallel() 90 91 var ( 92 engine = ethash.NewFaker() 93 94 configNoFork = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)} 95 configProFork = ¶ms.ChainConfig{ 96 HomesteadBlock: big.NewInt(1), 97 EIP150Block: big.NewInt(2), 98 EIP155Block: big.NewInt(2), 99 EIP158Block: big.NewInt(2), 100 ByzantiumBlock: big.NewInt(3), 101 } 102 dbNoFork = rawdb.NewMemoryDatabase() 103 dbProFork = rawdb.NewMemoryDatabase() 104 105 gspecNoFork = &core.Genesis{Config: configNoFork} 106 gspecProFork = &core.Genesis{Config: configProFork} 107 108 chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, gspecNoFork, nil, engine, vm.Config{}, nil, nil) 109 chainProFork, _ = core.NewBlockChain(dbProFork, nil, gspecProFork, nil, engine, vm.Config{}, nil, nil) 110 111 _, blocksNoFork, _ = core.GenerateChainWithGenesis(gspecNoFork, engine, 2, nil) 112 _, blocksProFork, _ = core.GenerateChainWithGenesis(gspecProFork, engine, 2, nil) 113 114 ethNoFork, _ = newHandler(&handlerConfig{ 115 Database: dbNoFork, 116 Chain: chainNoFork, 117 TxPool: newTestTxPool(), 118 Merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), 119 Network: 1, 120 Sync: downloader.FullSync, 121 BloomCache: 1, 122 }) 123 ethProFork, _ = newHandler(&handlerConfig{ 124 Database: dbProFork, 125 Chain: chainProFork, 126 TxPool: newTestTxPool(), 127 Merger: consensus.NewMerger(rawdb.NewMemoryDatabase()), 128 Network: 1, 129 Sync: downloader.FullSync, 130 BloomCache: 1, 131 }) 132 ) 133 ethNoFork.Start(1000) 134 ethProFork.Start(1000) 135 136 // Clean up everything after ourselves 137 defer chainNoFork.Stop() 138 defer chainProFork.Stop() 139 140 defer ethNoFork.Stop() 141 defer ethProFork.Stop() 142 143 // Both nodes should allow the other to connect (same genesis, next fork is the same) 144 p2pNoFork, p2pProFork := p2p.MsgPipe() 145 defer p2pNoFork.Close() 146 defer p2pProFork.Close() 147 148 peerNoFork := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pNoFork), p2pNoFork, nil) 149 peerProFork := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pProFork), p2pProFork, nil) 150 defer peerNoFork.Close() 151 defer peerProFork.Close() 152 153 errc := make(chan error, 2) 154 go func(errc chan error) { 155 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *zond.Peer) error { return nil }) 156 }(errc) 157 go func(errc chan error) { 158 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *zond.Peer) error { return nil }) 159 }(errc) 160 161 for i := 0; i < 2; i++ { 162 select { 163 case err := <-errc: 164 if err != nil { 165 t.Fatalf("frontier nofork <-> profork failed: %v", err) 166 } 167 case <-time.After(250 * time.Millisecond): 168 t.Fatalf("frontier nofork <-> profork handler timeout") 169 } 170 } 171 // Progress into Homestead. Fork's match, so we don't care what the future holds 172 chainNoFork.InsertChain(blocksNoFork[:1]) 173 chainProFork.InsertChain(blocksProFork[:1]) 174 175 p2pNoFork, p2pProFork = p2p.MsgPipe() 176 defer p2pNoFork.Close() 177 defer p2pProFork.Close() 178 179 peerNoFork = zond.NewPeer(protocol, p2p.NewPeer(enode.ID{1}, "", nil), p2pNoFork, nil) 180 peerProFork = zond.NewPeer(protocol, p2p.NewPeer(enode.ID{2}, "", nil), p2pProFork, nil) 181 defer peerNoFork.Close() 182 defer peerProFork.Close() 183 184 errc = make(chan error, 2) 185 go func(errc chan error) { 186 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *zond.Peer) error { return nil }) 187 }(errc) 188 go func(errc chan error) { 189 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *zond.Peer) error { return nil }) 190 }(errc) 191 192 for i := 0; i < 2; i++ { 193 select { 194 case err := <-errc: 195 if err != nil { 196 t.Fatalf("homestead nofork <-> profork failed: %v", err) 197 } 198 case <-time.After(250 * time.Millisecond): 199 t.Fatalf("homestead nofork <-> profork handler timeout") 200 } 201 } 202 // Progress into Spurious. Forks mismatch, signalling differing chains, reject 203 chainNoFork.InsertChain(blocksNoFork[1:2]) 204 chainProFork.InsertChain(blocksProFork[1:2]) 205 206 p2pNoFork, p2pProFork = p2p.MsgPipe() 207 defer p2pNoFork.Close() 208 defer p2pProFork.Close() 209 210 peerNoFork = zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pNoFork), p2pNoFork, nil) 211 peerProFork = zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pProFork), p2pProFork, nil) 212 defer peerNoFork.Close() 213 defer peerProFork.Close() 214 215 errc = make(chan error, 2) 216 go func(errc chan error) { 217 errc <- ethNoFork.runEthPeer(peerProFork, func(peer *zond.Peer) error { return nil }) 218 }(errc) 219 go func(errc chan error) { 220 errc <- ethProFork.runEthPeer(peerNoFork, func(peer *zond.Peer) error { return nil }) 221 }(errc) 222 223 var successes int 224 for i := 0; i < 2; i++ { 225 select { 226 case err := <-errc: 227 if err == nil { 228 successes++ 229 if successes == 2 { // Only one side disconnects 230 t.Fatalf("fork ID rejection didn't happen") 231 } 232 } 233 case <-time.After(250 * time.Millisecond): 234 t.Fatalf("split peers not rejected") 235 } 236 } 237 } 238 239 // Tests that received transactions are added to the local pool. 240 func TestRecvTransactions66(t *testing.T) { testRecvTransactions(t, zond.ETH66) } 241 func TestRecvTransactions67(t *testing.T) { testRecvTransactions(t, zond.ETH67) } 242 func TestRecvTransactions68(t *testing.T) { testRecvTransactions(t, zond.ETH68) } 243 244 func testRecvTransactions(t *testing.T, protocol uint) { 245 t.Parallel() 246 247 // Create a message handler, configure it to accept transactions and watch them 248 handler := newTestHandler() 249 defer handler.close() 250 251 handler.handler.acceptTxs.Store(true) // mark synced to accept transactions 252 253 txs := make(chan core.NewTxsEvent) 254 sub := handler.txpool.SubscribeNewTxsEvent(txs) 255 defer sub.Unsubscribe() 256 257 // Create a source peer to send messages through and a sink handler to receive them 258 p2pSrc, p2pSink := p2p.MsgPipe() 259 defer p2pSrc.Close() 260 defer p2pSink.Close() 261 262 src := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, handler.txpool) 263 sink := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, handler.txpool) 264 defer src.Close() 265 defer sink.Close() 266 267 go handler.handler.runEthPeer(sink, func(peer *zond.Peer) error { 268 return zond.Handle((*ethHandler)(handler.handler), peer) 269 }) 270 // Run the handshake locally to avoid spinning up a source handler 271 var ( 272 genesis = handler.chain.Genesis() 273 head = handler.chain.CurrentBlock() 274 td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) 275 ) 276 if err := src.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { 277 t.Fatalf("failed to run protocol handshake") 278 } 279 // Send the transaction to the sink and verify that it's added to the tx pool 280 tx := types.NewTransaction(0, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) 281 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 282 283 if err := src.SendTransactions([]*types.Transaction{tx}); err != nil { 284 t.Fatalf("failed to send transaction: %v", err) 285 } 286 select { 287 case event := <-txs: 288 if len(event.Txs) != 1 { 289 t.Errorf("wrong number of added transactions: got %d, want 1", len(event.Txs)) 290 } else if event.Txs[0].Hash() != tx.Hash() { 291 t.Errorf("added wrong tx hash: got %v, want %v", event.Txs[0].Hash(), tx.Hash()) 292 } 293 case <-time.After(2 * time.Second): 294 t.Errorf("no NewTxsEvent received within 2 seconds") 295 } 296 } 297 298 // This test checks that pending transactions are sent. 299 func TestSendTransactions66(t *testing.T) { testSendTransactions(t, zond.ETH66) } 300 func TestSendTransactions67(t *testing.T) { testSendTransactions(t, zond.ETH67) } 301 func TestSendTransactions68(t *testing.T) { testSendTransactions(t, zond.ETH68) } 302 303 func testSendTransactions(t *testing.T, protocol uint) { 304 t.Parallel() 305 306 // Create a message handler and fill the pool with big transactions 307 handler := newTestHandler() 308 defer handler.close() 309 310 insert := make([]*types.Transaction, 100) 311 for nonce := range insert { 312 tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, 10240)) 313 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 314 315 insert[nonce] = tx 316 } 317 go handler.txpool.AddRemotes(insert) // Need goroutine to not block on feed 318 time.Sleep(250 * time.Millisecond) // Wait until tx events get out of the system (can't use events, tx broadcaster races with peer join) 319 320 // Create a source handler to send messages through and a sink peer to receive them 321 p2pSrc, p2pSink := p2p.MsgPipe() 322 defer p2pSrc.Close() 323 defer p2pSink.Close() 324 325 src := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, handler.txpool) 326 sink := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, handler.txpool) 327 defer src.Close() 328 defer sink.Close() 329 330 go handler.handler.runEthPeer(src, func(peer *zond.Peer) error { 331 return zond.Handle((*ethHandler)(handler.handler), peer) 332 }) 333 // Run the handshake locally to avoid spinning up a source handler 334 var ( 335 genesis = handler.chain.Genesis() 336 head = handler.chain.CurrentBlock() 337 td = handler.chain.GetTd(head.Hash(), head.Number.Uint64()) 338 ) 339 if err := sink.Handshake(1, td, head.Hash(), genesis.Hash(), forkid.NewIDWithChain(handler.chain), forkid.NewFilter(handler.chain)); err != nil { 340 t.Fatalf("failed to run protocol handshake") 341 } 342 // After the handshake completes, the source handler should stream the sink 343 // the transactions, subscribe to all inbound network events 344 backend := new(testEthHandler) 345 346 anns := make(chan []common.Hash) 347 annSub := backend.txAnnounces.Subscribe(anns) 348 defer annSub.Unsubscribe() 349 350 bcasts := make(chan []*types.Transaction) 351 bcastSub := backend.txBroadcasts.Subscribe(bcasts) 352 defer bcastSub.Unsubscribe() 353 354 go zond.Handle(backend, sink) 355 356 // Make sure we get all the transactions on the correct channels 357 seen := make(map[common.Hash]struct{}) 358 for len(seen) < len(insert) { 359 switch protocol { 360 case 66, 67, 68: 361 select { 362 case hashes := <-anns: 363 for _, hash := range hashes { 364 if _, ok := seen[hash]; ok { 365 t.Errorf("duplicate transaction announced: %x", hash) 366 } 367 seen[hash] = struct{}{} 368 } 369 case <-bcasts: 370 t.Errorf("initial tx broadcast received on post zond/66") 371 } 372 373 default: 374 panic("unsupported protocol, please extend test") 375 } 376 } 377 for _, tx := range insert { 378 if _, ok := seen[tx.Hash()]; !ok { 379 t.Errorf("missing transaction: %x", tx.Hash()) 380 } 381 } 382 } 383 384 // Tests that transactions get propagated to all attached peers, either via direct 385 // broadcasts or via announcements/retrievals. 386 func TestTransactionPropagation66(t *testing.T) { testTransactionPropagation(t, zond.ETH66) } 387 func TestTransactionPropagation67(t *testing.T) { testTransactionPropagation(t, zond.ETH67) } 388 func TestTransactionPropagation68(t *testing.T) { testTransactionPropagation(t, zond.ETH68) } 389 390 func testTransactionPropagation(t *testing.T, protocol uint) { 391 t.Parallel() 392 393 // Create a source handler to send transactions from and a number of sinks 394 // to receive them. We need multiple sinks since a one-to-one peering would 395 // broadcast all transactions without announcement. 396 source := newTestHandler() 397 source.handler.snapSync.Store(false) // Avoid requiring snap, otherwise some will be dropped below 398 defer source.close() 399 400 sinks := make([]*testHandler, 10) 401 for i := 0; i < len(sinks); i++ { 402 sinks[i] = newTestHandler() 403 defer sinks[i].close() 404 405 sinks[i].handler.acceptTxs.Store(true) // mark synced to accept transactions 406 } 407 // Interconnect all the sink handlers with the source handler 408 for i, sink := range sinks { 409 sink := sink // Closure for gorotuine below 410 411 sourcePipe, sinkPipe := p2p.MsgPipe() 412 defer sourcePipe.Close() 413 defer sinkPipe.Close() 414 415 sourcePeer := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{byte(i + 1)}, "", nil, sourcePipe), sourcePipe, source.txpool) 416 sinkPeer := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, sink.txpool) 417 defer sourcePeer.Close() 418 defer sinkPeer.Close() 419 420 go source.handler.runEthPeer(sourcePeer, func(peer *zond.Peer) error { 421 return zond.Handle((*ethHandler)(source.handler), peer) 422 }) 423 go sink.handler.runEthPeer(sinkPeer, func(peer *zond.Peer) error { 424 return zond.Handle((*ethHandler)(sink.handler), peer) 425 }) 426 } 427 // Subscribe to all the transaction pools 428 txChs := make([]chan core.NewTxsEvent, len(sinks)) 429 for i := 0; i < len(sinks); i++ { 430 txChs[i] = make(chan core.NewTxsEvent, 1024) 431 432 sub := sinks[i].txpool.SubscribeNewTxsEvent(txChs[i]) 433 defer sub.Unsubscribe() 434 } 435 // Fill the source pool with transactions and wait for them at the sinks 436 txs := make([]*types.Transaction, 1024) 437 for nonce := range txs { 438 tx := types.NewTransaction(uint64(nonce), common.Address{}, big.NewInt(0), 100000, big.NewInt(0), nil) 439 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey) 440 441 txs[nonce] = tx 442 } 443 source.txpool.AddRemotes(txs) 444 445 // Iterate through all the sinks and ensure they all got the transactions 446 for i := range sinks { 447 for arrived, timeout := 0, false; arrived < len(txs) && !timeout; { 448 select { 449 case event := <-txChs[i]: 450 arrived += len(event.Txs) 451 case <-time.After(2 * time.Second): 452 t.Errorf("sink %d: transaction propagation timed out: have %d, want %d", i, arrived, len(txs)) 453 timeout = true 454 } 455 } 456 } 457 } 458 459 // Tests that blocks are broadcast to a sqrt number of peers only. 460 func TestBroadcastBlock1Peer(t *testing.T) { testBroadcastBlock(t, 1, 1) } 461 func TestBroadcastBlock2Peers(t *testing.T) { testBroadcastBlock(t, 2, 1) } 462 func TestBroadcastBlock3Peers(t *testing.T) { testBroadcastBlock(t, 3, 1) } 463 func TestBroadcastBlock4Peers(t *testing.T) { testBroadcastBlock(t, 4, 2) } 464 func TestBroadcastBlock5Peers(t *testing.T) { testBroadcastBlock(t, 5, 2) } 465 func TestBroadcastBlock8Peers(t *testing.T) { testBroadcastBlock(t, 9, 3) } 466 func TestBroadcastBlock12Peers(t *testing.T) { testBroadcastBlock(t, 12, 3) } 467 func TestBroadcastBlock16Peers(t *testing.T) { testBroadcastBlock(t, 16, 4) } 468 func TestBroadcastBloc26Peers(t *testing.T) { testBroadcastBlock(t, 26, 5) } 469 func TestBroadcastBlock100Peers(t *testing.T) { testBroadcastBlock(t, 100, 10) } 470 471 func testBroadcastBlock(t *testing.T, peers, bcasts int) { 472 t.Parallel() 473 474 // Create a source handler to broadcast blocks from and a number of sinks 475 // to receive them. 476 source := newTestHandlerWithBlocks(1) 477 defer source.close() 478 479 sinks := make([]*testEthHandler, peers) 480 for i := 0; i < len(sinks); i++ { 481 sinks[i] = new(testEthHandler) 482 } 483 // Interconnect all the sink handlers with the source handler 484 var ( 485 genesis = source.chain.Genesis() 486 td = source.chain.GetTd(genesis.Hash(), genesis.NumberU64()) 487 ) 488 for i, sink := range sinks { 489 sink := sink // Closure for gorotuine below 490 491 sourcePipe, sinkPipe := p2p.MsgPipe() 492 defer sourcePipe.Close() 493 defer sinkPipe.Close() 494 495 sourcePeer := zond.NewPeer(zond.ETH66, p2p.NewPeerPipe(enode.ID{byte(i)}, "", nil, sourcePipe), sourcePipe, nil) 496 sinkPeer := zond.NewPeer(zond.ETH66, p2p.NewPeerPipe(enode.ID{0}, "", nil, sinkPipe), sinkPipe, nil) 497 defer sourcePeer.Close() 498 defer sinkPeer.Close() 499 500 go source.handler.runEthPeer(sourcePeer, func(peer *zond.Peer) error { 501 return zond.Handle((*ethHandler)(source.handler), peer) 502 }) 503 if err := sinkPeer.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { 504 t.Fatalf("failed to run protocol handshake") 505 } 506 go zond.Handle(sink, sinkPeer) 507 } 508 // Subscribe to all the transaction pools 509 blockChs := make([]chan *types.Block, len(sinks)) 510 for i := 0; i < len(sinks); i++ { 511 blockChs[i] = make(chan *types.Block, 1) 512 defer close(blockChs[i]) 513 514 sub := sinks[i].blockBroadcasts.Subscribe(blockChs[i]) 515 defer sub.Unsubscribe() 516 } 517 // Initiate a block propagation across the peers 518 time.Sleep(100 * time.Millisecond) 519 header := source.chain.CurrentBlock() 520 source.handler.BroadcastBlock(source.chain.GetBlock(header.Hash(), header.Number.Uint64()), true) 521 522 // Iterate through all the sinks and ensure the correct number got the block 523 done := make(chan struct{}, peers) 524 for _, ch := range blockChs { 525 ch := ch 526 go func() { 527 <-ch 528 done <- struct{}{} 529 }() 530 } 531 var received int 532 for { 533 select { 534 case <-done: 535 received++ 536 537 case <-time.After(100 * time.Millisecond): 538 if received != bcasts { 539 t.Errorf("broadcast count mismatch: have %d, want %d", received, bcasts) 540 } 541 return 542 } 543 } 544 } 545 546 // Tests that a propagated malformed block (uncles or transactions don't match 547 // with the hashes in the header) gets discarded and not broadcast forward. 548 func TestBroadcastMalformedBlock66(t *testing.T) { testBroadcastMalformedBlock(t, zond.ETH66) } 549 func TestBroadcastMalformedBlock67(t *testing.T) { testBroadcastMalformedBlock(t, zond.ETH67) } 550 func TestBroadcastMalformedBlock68(t *testing.T) { testBroadcastMalformedBlock(t, zond.ETH68) } 551 552 func testBroadcastMalformedBlock(t *testing.T, protocol uint) { 553 t.Parallel() 554 555 // Create a source handler to broadcast blocks from and a number of sinks 556 // to receive them. 557 source := newTestHandlerWithBlocks(1) 558 defer source.close() 559 560 // Create a source handler to send messages through and a sink peer to receive them 561 p2pSrc, p2pSink := p2p.MsgPipe() 562 defer p2pSrc.Close() 563 defer p2pSink.Close() 564 565 src := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{1}, "", nil, p2pSrc), p2pSrc, source.txpool) 566 sink := zond.NewPeer(protocol, p2p.NewPeerPipe(enode.ID{2}, "", nil, p2pSink), p2pSink, source.txpool) 567 defer src.Close() 568 defer sink.Close() 569 570 go source.handler.runEthPeer(src, func(peer *zond.Peer) error { 571 return zond.Handle((*ethHandler)(source.handler), peer) 572 }) 573 // Run the handshake locally to avoid spinning up a sink handler 574 var ( 575 genesis = source.chain.Genesis() 576 td = source.chain.GetTd(genesis.Hash(), genesis.NumberU64()) 577 ) 578 if err := sink.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain)); err != nil { 579 t.Fatalf("failed to run protocol handshake") 580 } 581 // After the handshake completes, the source handler should stream the sink 582 // the blocks, subscribe to inbound network events 583 backend := new(testEthHandler) 584 585 blocks := make(chan *types.Block, 1) 586 sub := backend.blockBroadcasts.Subscribe(blocks) 587 defer sub.Unsubscribe() 588 589 go zond.Handle(backend, sink) 590 591 // Create various combinations of malformed blocks 592 head := source.chain.CurrentBlock() 593 block := source.chain.GetBlock(head.Hash(), head.Number.Uint64()) 594 595 malformedUncles := head 596 malformedUncles.UncleHash[0]++ 597 malformedTransactions := head 598 malformedTransactions.TxHash[0]++ 599 malformedEverything := head 600 malformedEverything.UncleHash[0]++ 601 malformedEverything.TxHash[0]++ 602 603 // Try to broadcast all malformations and ensure they all get discarded 604 for _, header := range []*types.Header{malformedUncles, malformedTransactions, malformedEverything} { 605 block := types.NewBlockWithHeader(header).WithBody(block.Transactions(), block.Uncles()) 606 if err := src.SendNewBlock(block, big.NewInt(131136)); err != nil { 607 t.Fatalf("failed to broadcast block: %v", err) 608 } 609 select { 610 case <-blocks: 611 t.Fatalf("malformed block forwarded") 612 case <-time.After(100 * time.Millisecond): 613 } 614 } 615 }