github.com/ethxdao/go-ethereum@v0.0.0-20221218102228-5ae34a9cc189/eth/handler.go (about) 1 // Copyright 2015 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 "errors" 21 "math" 22 "math/big" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 "github.com/ethxdao/go-ethereum/common" 28 "github.com/ethxdao/go-ethereum/core" 29 "github.com/ethxdao/go-ethereum/core/forkid" 30 "github.com/ethxdao/go-ethereum/core/types" 31 "github.com/ethxdao/go-ethereum/eth/downloader" 32 "github.com/ethxdao/go-ethereum/eth/fetcher" 33 "github.com/ethxdao/go-ethereum/eth/protocols/eth" 34 "github.com/ethxdao/go-ethereum/eth/protocols/snap" 35 "github.com/ethxdao/go-ethereum/ethdb" 36 "github.com/ethxdao/go-ethereum/event" 37 "github.com/ethxdao/go-ethereum/log" 38 "github.com/ethxdao/go-ethereum/p2p" 39 "github.com/ethxdao/go-ethereum/params" 40 ) 41 42 const ( 43 // txChanSize is the size of channel listening to NewTxsEvent. 44 // The number is referenced from the size of tx pool. 45 txChanSize = 4096 46 ) 47 48 var ( 49 syncChallengeTimeout = 15 * time.Second // Time allowance for a node to reply to the sync progress challenge 50 ) 51 52 // txPool defines the methods needed from a transaction pool implementation to 53 // support all the operations needed by the Ethereum chain protocols. 54 type txPool interface { 55 // Has returns an indicator whether txpool has a transaction 56 // cached with the given hash. 57 Has(hash common.Hash) bool 58 59 // Get retrieves the transaction from local txpool with given 60 // tx hash. 61 Get(hash common.Hash) *types.Transaction 62 63 // AddRemotes should add the given transactions to the pool. 64 AddRemotes([]*types.Transaction) []error 65 66 // Pending should return pending transactions. 67 // The slice should be modifiable by the caller. 68 Pending(enforceTips bool) map[common.Address]types.Transactions 69 70 // SubscribeNewTxsEvent should return an event subscription of 71 // NewTxsEvent and send events to the given channel. 72 SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription 73 } 74 75 // handlerConfig is the collection of initialization parameters to create a full 76 // node network handler. 77 type handlerConfig struct { 78 Database ethdb.Database // Database for direct sync insertions 79 Chain *core.BlockChain // Blockchain to serve data from 80 TxPool txPool // Transaction pool to propagate from 81 Network uint64 // Network identifier to adfvertise 82 Sync downloader.SyncMode // Whether to snap or full sync 83 BloomCache uint64 // Megabytes to alloc for snap sync bloom 84 EventMux *event.TypeMux // Legacy event mux, deprecate for `feed` 85 Checkpoint *params.TrustedCheckpoint // Hard coded checkpoint for sync challenges 86 RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges 87 } 88 89 type handler struct { 90 networkID uint64 91 forkFilter forkid.Filter // Fork ID filter, constant across the lifetime of the node 92 93 snapSync uint32 // Flag whether snap sync is enabled (gets disabled if we already have blocks) 94 acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing) 95 96 checkpointNumber uint64 // Block number for the sync progress validator to cross reference 97 checkpointHash common.Hash // Block hash for the sync progress validator to cross reference 98 99 database ethdb.Database 100 txpool txPool 101 chain *core.BlockChain 102 maxPeers int 103 104 downloader *downloader.Downloader 105 blockFetcher *fetcher.BlockFetcher 106 txFetcher *fetcher.TxFetcher 107 peers *peerSet 108 109 eventMux *event.TypeMux 110 txsCh chan core.NewTxsEvent 111 txsSub event.Subscription 112 minedBlockSub *event.TypeMuxSubscription 113 114 requiredBlocks map[uint64]common.Hash 115 116 // channels for fetcher, syncer, txsyncLoop 117 quitSync chan struct{} 118 119 chainSync *chainSyncer 120 wg sync.WaitGroup 121 peerWG sync.WaitGroup 122 } 123 124 // newHandler returns a handler for all Ethereum chain management protocol. 125 func newHandler(config *handlerConfig) (*handler, error) { 126 // Create the protocol manager with the base fields 127 if config.EventMux == nil { 128 config.EventMux = new(event.TypeMux) // Nicety initialization for tests 129 } 130 h := &handler{ 131 networkID: config.Network, 132 forkFilter: forkid.NewFilter(config.Chain), 133 eventMux: config.EventMux, 134 database: config.Database, 135 txpool: config.TxPool, 136 chain: config.Chain, 137 peers: newPeerSet(), 138 requiredBlocks: config.RequiredBlocks, 139 quitSync: make(chan struct{}), 140 } 141 if config.Sync == downloader.FullSync { 142 // The database seems empty as the current block is the genesis. Yet the snap 143 // block is ahead, so snap sync was enabled for this node at a certain point. 144 // The scenarios where this can happen is 145 // * if the user manually (or via a bad block) rolled back a snap sync node 146 // below the sync point. 147 // * the last snap sync is not finished while user specifies a full sync this 148 // time. But we don't have any recent state for full sync. 149 // In these cases however it's safe to reenable snap sync. 150 fullBlock, fastBlock := h.chain.CurrentBlock(), h.chain.CurrentFastBlock() 151 if fullBlock.NumberU64() == 0 && fastBlock.NumberU64() > 0 { 152 h.snapSync = uint32(1) 153 log.Warn("Switch sync mode from full sync to snap sync") 154 } 155 } else { 156 if h.chain.CurrentBlock().NumberU64() > 0 { 157 // Print warning log if database is not empty to run snap sync. 158 log.Warn("Switch sync mode from snap sync to full sync") 159 } else { 160 // If snap sync was requested and our database is empty, grant it 161 h.snapSync = uint32(1) 162 } 163 } 164 // If we have trusted checkpoints, enforce them on the chain 165 if config.Checkpoint != nil { 166 h.checkpointNumber = (config.Checkpoint.SectionIndex+1)*params.CHTFrequency - 1 167 h.checkpointHash = config.Checkpoint.SectionHead 168 } 169 // If sync succeeds, pass a callback to potentially disable snap sync mode 170 // and enable transaction propagation. 171 success := func() { 172 // If we were running snap sync and it finished, disable doing another 173 // round on next sync cycle 174 if atomic.LoadUint32(&h.snapSync) == 1 { 175 log.Info("Snap sync complete, auto disabling") 176 atomic.StoreUint32(&h.snapSync, 0) 177 } 178 // If we've successfully finished a sync cycle and passed any required 179 // checkpoint, enable accepting transactions from the network 180 head := h.chain.CurrentBlock() 181 if head.NumberU64() >= h.checkpointNumber { 182 // Checkpoint passed, sanity check the timestamp to have a fallback mechanism 183 // for non-checkpointed (number = 0) private networks. 184 if head.Time() >= uint64(time.Now().AddDate(0, -1, 0).Unix()) { 185 atomic.StoreUint32(&h.acceptTxs, 1) 186 } 187 } 188 } 189 // Construct the downloader (long sync) and its backing state bloom if snap 190 // sync is requested. The downloader is responsible for deallocating the state 191 // bloom when it's done. 192 h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success) 193 //if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil { 194 // if h.chain.Config().TerminalTotalDifficultyPassed { 195 // log.Info("Chain post-merge, sync via beacon client") 196 // } else { 197 // head := h.chain.CurrentBlock() 198 // if td := h.chain.GetTd(head.Hash(), head.NumberU64()); td.Cmp(ttd) >= 0 { 199 // log.Info("Chain post-TTD, sync via beacon client") 200 // } else { 201 // log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)") 202 // } 203 // } 204 //} else if h.chain.Config().TerminalTotalDifficultyPassed { 205 // log.Error("Chain configured post-merge, but without TTD. Are you debugging sync?") 206 //} 207 // Construct the fetcher (short sync) 208 validator := func(header *types.Header) error { 209 // All the block fetcher activities should be disabled 210 // after the transition. Print the warning log. 211 //if h.merger.PoSFinalized() { 212 // log.Warn("Unexpected validation activity", "hash", header.Hash(), "number", header.Number) 213 // return errors.New("unexpected behavior after transition") 214 //} 215 // Reject all the PoS style headers in the first place. No matter 216 // the chain has finished the transition or not, the PoS headers 217 // should only come from the trusted consensus layer instead of 218 // p2p network. 219 //if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { 220 // if beacon.IsPoSHeader(header) { 221 // return errors.New("unexpected post-merge header") 222 // } 223 //} 224 return h.chain.Engine().VerifyHeader(h.chain, header, true) 225 } 226 heighter := func() uint64 { 227 return h.chain.CurrentBlock().NumberU64() 228 } 229 inserter := func(blocks types.Blocks) (int, error) { 230 // All the block fetcher activities should be disabled 231 // after the transition. Print the warning log. 232 //if h.merger.PoSFinalized() { 233 // var ctx []interface{} 234 // ctx = append(ctx, "blocks", len(blocks)) 235 // if len(blocks) > 0 { 236 // ctx = append(ctx, "firsthash", blocks[0].Hash()) 237 // ctx = append(ctx, "firstnumber", blocks[0].Number()) 238 // ctx = append(ctx, "lasthash", blocks[len(blocks)-1].Hash()) 239 // ctx = append(ctx, "lastnumber", blocks[len(blocks)-1].Number()) 240 // } 241 // log.Warn("Unexpected insertion activity", ctx...) 242 // return 0, errors.New("unexpected behavior after transition") 243 //} 244 // If sync hasn't reached the checkpoint yet, deny importing weird blocks. 245 // 246 // Ideally we would also compare the head block's timestamp and similarly reject 247 // the propagated block if the head is too old. Unfortunately there is a corner 248 // case when starting new networks, where the genesis might be ancient (0 unix) 249 // which would prevent full nodes from accepting it. 250 if h.chain.CurrentBlock().NumberU64() < h.checkpointNumber { 251 log.Warn("Unsynced yet, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) 252 return 0, nil 253 } 254 // If snap sync is running, deny importing weird blocks. This is a problematic 255 // clause when starting up a new network, because snap-syncing miners might not 256 // accept each others' blocks until a restart. Unfortunately we haven't figured 257 // out a way yet where nodes can decide unilaterally whether the network is new 258 // or not. This should be fixed if we figure out a solution. 259 if atomic.LoadUint32(&h.snapSync) == 1 { 260 log.Warn("Snap syncing, discarded propagated block", "number", blocks[0].Number(), "hash", blocks[0].Hash()) 261 return 0, nil 262 } 263 //if h.merger.TDDReached() { 264 // The blocks from the p2p network is regarded as untrusted 265 // after the transition. In theory block gossip should be disabled 266 // entirely whenever the transition is started. But in order to 267 // handle the transition boundary reorg in the consensus-layer, 268 // the legacy blocks are still accepted, but only for the terminal 269 // pow blocks. Spec: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3675.md#halt-the-importing-of-pow-blocks 270 // for i, block := range blocks { 271 // ptd := h.chain.GetTd(block.ParentHash(), block.NumberU64()-1) 272 // if ptd == nil { 273 // return 0, nil 274 // } 275 // td := new(big.Int).Add(ptd, block.Difficulty()) 276 // if !h.chain.Config().IsTerminalPoWBlock(ptd, td) { 277 // log.Info("Filtered out non-termimal pow block", "number", block.NumberU64(), "hash", block.Hash()) 278 // return 0, nil 279 // } 280 // if err := h.chain.InsertBlockWithoutSetHead(block); err != nil { 281 // return i, err 282 // } 283 // } 284 // return 0, nil 285 //} 286 n, err := h.chain.InsertChain(blocks) 287 if err == nil { 288 atomic.StoreUint32(&h.acceptTxs, 1) // Mark initial sync done on any fetcher import 289 } 290 return n, err 291 } 292 h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock, heighter, nil, inserter, h.removePeer) 293 294 fetchTx := func(peer string, hashes []common.Hash) error { 295 p := h.peers.peer(peer) 296 if p == nil { 297 return errors.New("unknown peer") 298 } 299 return p.RequestTxs(hashes) 300 } 301 h.txFetcher = fetcher.NewTxFetcher(h.txpool.Has, h.txpool.AddRemotes, fetchTx) 302 h.chainSync = newChainSyncer(h) 303 return h, nil 304 } 305 306 // runEthPeer registers an eth peer into the joint eth/snap peerset, adds it to 307 // various subsystems and starts handling messages. 308 func (h *handler) runEthPeer(peer *eth.Peer, handler eth.Handler) error { 309 // If the peer has a `snap` extension, wait for it to connect so we can have 310 // a uniform initialization/teardown mechanism 311 snap, err := h.peers.waitSnapExtension(peer) 312 if err != nil { 313 peer.Log().Error("Snapshot extension barrier failed", "err", err) 314 return err 315 } 316 // TODO(karalabe): Not sure why this is needed 317 if !h.chainSync.handlePeerEvent(peer) { 318 return p2p.DiscQuitting 319 } 320 h.peerWG.Add(1) 321 defer h.peerWG.Done() 322 323 // Execute the Ethereum handshake 324 var ( 325 genesis = h.chain.Genesis() 326 head = h.chain.CurrentHeader() 327 hash = head.Hash() 328 number = head.Number.Uint64() 329 td = h.chain.GetTd(hash, number) 330 ) 331 forkID := forkid.NewID(h.chain.Config(), h.chain.Genesis().Hash(), h.chain.CurrentHeader().Number.Uint64()) 332 if err := peer.Handshake(h.networkID, td, hash, genesis.Hash(), forkID, h.forkFilter); err != nil { 333 peer.Log().Debug("Ethereum handshake failed", "err", err) 334 return err 335 } 336 reject := false // reserved peer slots 337 if atomic.LoadUint32(&h.snapSync) == 1 { 338 if snap == nil { 339 // If we are running snap-sync, we want to reserve roughly half the peer 340 // slots for peers supporting the snap protocol. 341 // The logic here is; we only allow up to 5 more non-snap peers than snap-peers. 342 if all, snp := h.peers.len(), h.peers.snapLen(); all-snp > snp+5 { 343 reject = true 344 } 345 } 346 } 347 // Ignore maxPeers if this is a trusted peer 348 if !peer.Peer.Info().Network.Trusted { 349 if reject || h.peers.len() >= h.maxPeers { 350 return p2p.DiscTooManyPeers 351 } 352 } 353 peer.Log().Debug("Ethereum peer connected", "name", peer.Name()) 354 355 // Register the peer locally 356 if err := h.peers.registerPeer(peer, snap); err != nil { 357 peer.Log().Error("Ethereum peer registration failed", "err", err) 358 return err 359 } 360 defer h.unregisterPeer(peer.ID()) 361 362 p := h.peers.peer(peer.ID()) 363 if p == nil { 364 return errors.New("peer dropped during handling") 365 } 366 // Register the peer in the downloader. If the downloader considers it banned, we disconnect 367 if err := h.downloader.RegisterPeer(peer.ID(), peer.Version(), peer); err != nil { 368 peer.Log().Error("Failed to register peer in eth syncer", "err", err) 369 return err 370 } 371 if snap != nil { 372 if err := h.downloader.SnapSyncer.Register(snap); err != nil { 373 peer.Log().Error("Failed to register peer in snap syncer", "err", err) 374 return err 375 } 376 } 377 h.chainSync.handlePeerEvent(peer) 378 379 // Propagate existing transactions. new transactions appearing 380 // after this will be sent via broadcasts. 381 h.syncTransactions(peer) 382 383 // Create a notification channel for pending requests if the peer goes down 384 dead := make(chan struct{}) 385 defer close(dead) 386 387 // If we have a trusted CHT, reject all peers below that (avoid fast sync eclipse) 388 if h.checkpointHash != (common.Hash{}) { 389 // Request the peer's checkpoint header for chain height/weight validation 390 resCh := make(chan *eth.Response) 391 if _, err := peer.RequestHeadersByNumber(h.checkpointNumber, 1, 0, false, resCh); err != nil { 392 return err 393 } 394 // Start a timer to disconnect if the peer doesn't reply in time 395 go func() { 396 timeout := time.NewTimer(syncChallengeTimeout) 397 defer timeout.Stop() 398 399 select { 400 case res := <-resCh: 401 headers := ([]*types.Header)(*res.Res.(*eth.BlockHeadersPacket)) 402 if len(headers) == 0 { 403 // If we're doing a snap sync, we must enforce the checkpoint 404 // block to avoid eclipse attacks. Unsynced nodes are welcome 405 // to connect after we're done joining the network. 406 if atomic.LoadUint32(&h.snapSync) == 1 { 407 peer.Log().Warn("Dropping unsynced node during sync", "addr", peer.RemoteAddr(), "type", peer.Name()) 408 res.Done <- errors.New("unsynced node cannot serve sync") 409 return 410 } 411 res.Done <- nil 412 return 413 } 414 // Validate the header and either drop the peer or continue 415 if len(headers) > 1 { 416 res.Done <- errors.New("too many headers in checkpoint response") 417 return 418 } 419 if headers[0].Hash() != h.checkpointHash { 420 res.Done <- errors.New("checkpoint hash mismatch") 421 return 422 } 423 res.Done <- nil 424 425 case <-timeout.C: 426 peer.Log().Warn("Checkpoint challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) 427 h.removePeer(peer.ID()) 428 429 case <-dead: 430 // Peer handler terminated, abort all goroutines 431 } 432 }() 433 } 434 // If we have any explicit peer required block hashes, request them 435 for number, hash := range h.requiredBlocks { 436 resCh := make(chan *eth.Response) 437 if _, err := peer.RequestHeadersByNumber(number, 1, 0, false, resCh); err != nil { 438 return err 439 } 440 go func(number uint64, hash common.Hash) { 441 timeout := time.NewTimer(syncChallengeTimeout) 442 defer timeout.Stop() 443 444 select { 445 case res := <-resCh: 446 headers := ([]*types.Header)(*res.Res.(*eth.BlockHeadersPacket)) 447 if len(headers) == 0 { 448 // Required blocks are allowed to be missing if the remote 449 // node is not yet synced 450 res.Done <- nil 451 return 452 } 453 // Validate the header and either drop the peer or continue 454 if len(headers) > 1 { 455 res.Done <- errors.New("too many headers in required block response") 456 return 457 } 458 if headers[0].Number.Uint64() != number || headers[0].Hash() != hash { 459 peer.Log().Info("Required block mismatch, dropping peer", "number", number, "hash", headers[0].Hash(), "want", hash) 460 res.Done <- errors.New("required block mismatch") 461 return 462 } 463 peer.Log().Debug("Peer required block verified", "number", number, "hash", hash) 464 res.Done <- nil 465 case <-timeout.C: 466 peer.Log().Warn("Required block challenge timed out, dropping", "addr", peer.RemoteAddr(), "type", peer.Name()) 467 h.removePeer(peer.ID()) 468 } 469 }(number, hash) 470 } 471 // Handle incoming messages until the connection is torn down 472 return handler(peer) 473 } 474 475 // runSnapExtension registers a `snap` peer into the joint eth/snap peerset and 476 // starts handling inbound messages. As `snap` is only a satellite protocol to 477 // `eth`, all subsystem registrations and lifecycle management will be done by 478 // the main `eth` handler to prevent strange races. 479 func (h *handler) runSnapExtension(peer *snap.Peer, handler snap.Handler) error { 480 h.peerWG.Add(1) 481 defer h.peerWG.Done() 482 483 if err := h.peers.registerSnapExtension(peer); err != nil { 484 peer.Log().Warn("Snapshot extension registration failed", "err", err) 485 return err 486 } 487 return handler(peer) 488 } 489 490 // removePeer requests disconnection of a peer. 491 func (h *handler) removePeer(id string) { 492 peer := h.peers.peer(id) 493 if peer != nil { 494 peer.Peer.Disconnect(p2p.DiscUselessPeer) 495 } 496 } 497 498 // unregisterPeer removes a peer from the downloader, fetchers and main peer set. 499 func (h *handler) unregisterPeer(id string) { 500 // Create a custom logger to avoid printing the entire id 501 var logger log.Logger 502 if len(id) < 16 { 503 // Tests use short IDs, don't choke on them 504 logger = log.New("peer", id) 505 } else { 506 logger = log.New("peer", id[:8]) 507 } 508 // Abort if the peer does not exist 509 peer := h.peers.peer(id) 510 if peer == nil { 511 logger.Error("Ethereum peer removal failed", "err", errPeerNotRegistered) 512 return 513 } 514 // Remove the `eth` peer if it exists 515 logger.Debug("Removing Ethereum peer", "snap", peer.snapExt != nil) 516 517 // Remove the `snap` extension if it exists 518 if peer.snapExt != nil { 519 h.downloader.SnapSyncer.Unregister(id) 520 } 521 h.downloader.UnregisterPeer(id) 522 h.txFetcher.Drop(id) 523 524 if err := h.peers.unregisterPeer(id); err != nil { 525 logger.Error("Ethereum peer removal failed", "err", err) 526 } 527 } 528 529 func (h *handler) Start(maxPeers int) { 530 h.maxPeers = maxPeers 531 532 // broadcast transactions 533 h.wg.Add(1) 534 h.txsCh = make(chan core.NewTxsEvent, txChanSize) 535 h.txsSub = h.txpool.SubscribeNewTxsEvent(h.txsCh) 536 go h.txBroadcastLoop() 537 538 // broadcast mined blocks 539 h.wg.Add(1) 540 h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}) 541 go h.minedBroadcastLoop() 542 543 // start sync handlers 544 h.wg.Add(1) 545 go h.chainSync.loop() 546 } 547 548 func (h *handler) Stop() { 549 h.txsSub.Unsubscribe() // quits txBroadcastLoop 550 h.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop 551 552 // Quit chainSync and txsync64. 553 // After this is done, no new peers will be accepted. 554 close(h.quitSync) 555 h.wg.Wait() 556 557 // Disconnect existing sessions. 558 // This also closes the gate for any new registrations on the peer set. 559 // sessions which are already established but not added to h.peers yet 560 // will exit when they try to register. 561 h.peers.close() 562 h.peerWG.Wait() 563 564 log.Info("Ethereum protocol stopped") 565 } 566 567 // BroadcastBlock will either propagate a block to a subset of its peers, or 568 // will only announce its availability (depending what's requested). 569 func (h *handler) BroadcastBlock(block *types.Block, propagate bool) { 570 // Disable the block propagation if the chain has already entered the PoS 571 // stage. The block propagation is delegated to the consensus layer. 572 //if h.merger.PoSFinalized() { 573 // return 574 //} 575 // Disable the block propagation if it's the post-merge block. 576 //if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok { 577 // if beacon.IsPoSHeader(block.Header()) { 578 // return 579 // } 580 //} 581 hash := block.Hash() 582 peers := h.peers.peersWithoutBlock(hash) 583 584 // If propagation is requested, send to a subset of the peer 585 if propagate { 586 // Calculate the TD of the block (it's not imported yet, so block.Td is not valid) 587 var td *big.Int 588 if parent := h.chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent != nil { 589 td = new(big.Int).Add(block.Difficulty(), h.chain.GetTd(block.ParentHash(), block.NumberU64()-1)) 590 } else { 591 log.Error("Propagating dangling block", "number", block.Number(), "hash", hash) 592 return 593 } 594 // Send the block to a subset of our peers 595 transfer := peers[:int(math.Sqrt(float64(len(peers))))] 596 for _, peer := range transfer { 597 peer.AsyncSendNewBlock(block, td) 598 } 599 log.Trace("Propagated block", "hash", hash, "recipients", len(transfer), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 600 return 601 } 602 // Otherwise if the block is indeed in out own chain, announce it 603 if h.chain.HasBlock(hash, block.NumberU64()) { 604 for _, peer := range peers { 605 peer.AsyncSendNewBlockHash(block) 606 } 607 log.Trace("Announced block", "hash", hash, "recipients", len(peers), "duration", common.PrettyDuration(time.Since(block.ReceivedAt))) 608 } 609 } 610 611 // BroadcastTransactions will propagate a batch of transactions 612 // - To a square root of all peers 613 // - And, separately, as announcements to all peers which are not known to 614 // already have the given transaction. 615 func (h *handler) BroadcastTransactions(txs types.Transactions) { 616 var ( 617 annoCount int // Count of announcements made 618 annoPeers int 619 directCount int // Count of the txs sent directly to peers 620 directPeers int // Count of the peers that were sent transactions directly 621 622 txset = make(map[*ethPeer][]common.Hash) // Set peer->hash to transfer directly 623 annos = make(map[*ethPeer][]common.Hash) // Set peer->hash to announce 624 625 ) 626 // Broadcast transactions to a batch of peers not knowing about it 627 for _, tx := range txs { 628 peers := h.peers.peersWithoutTransaction(tx.Hash()) 629 // Send the tx unconditionally to a subset of our peers 630 numDirect := int(math.Sqrt(float64(len(peers)))) 631 for _, peer := range peers[:numDirect] { 632 txset[peer] = append(txset[peer], tx.Hash()) 633 } 634 // For the remaining peers, send announcement only 635 for _, peer := range peers[numDirect:] { 636 annos[peer] = append(annos[peer], tx.Hash()) 637 } 638 } 639 for peer, hashes := range txset { 640 directPeers++ 641 directCount += len(hashes) 642 peer.AsyncSendTransactions(hashes) 643 } 644 for peer, hashes := range annos { 645 annoPeers++ 646 annoCount += len(hashes) 647 peer.AsyncSendPooledTransactionHashes(hashes) 648 } 649 log.Debug("Transaction broadcast", "txs", len(txs), 650 "announce packs", annoPeers, "announced hashes", annoCount, 651 "tx packs", directPeers, "broadcast txs", directCount) 652 } 653 654 // minedBroadcastLoop sends mined blocks to connected peers. 655 func (h *handler) minedBroadcastLoop() { 656 defer h.wg.Done() 657 658 for obj := range h.minedBlockSub.Chan() { 659 if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok { 660 h.BroadcastBlock(ev.Block, true) // First propagate block to peers 661 h.BroadcastBlock(ev.Block, false) // Only then announce to the rest 662 } 663 } 664 } 665 666 // txBroadcastLoop announces new transactions to connected peers. 667 func (h *handler) txBroadcastLoop() { 668 defer h.wg.Done() 669 for { 670 select { 671 case event := <-h.txsCh: 672 h.BroadcastTransactions(event.Txs) 673 case <-h.txsSub.Err(): 674 return 675 } 676 } 677 }