github.com/m3shine/gochain@v2.2.26+incompatible/eth/peer.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 "bytes" 21 "context" 22 "errors" 23 "fmt" 24 "math/big" 25 "sync" 26 "time" 27 28 "go.opencensus.io/trace" 29 30 "github.com/gochain-io/gochain/common" 31 "github.com/gochain-io/gochain/core/types" 32 "github.com/gochain-io/gochain/log" 33 "github.com/gochain-io/gochain/p2p" 34 "github.com/gochain-io/gochain/rlp" 35 ) 36 37 var ( 38 errClosed = errors.New("peer set is closed") 39 errAlreadyRegistered = errors.New("peer is already registered") 40 errNotRegistered = errors.New("peer is not registered") 41 ) 42 43 const ( 44 maxKnownTxs = 65536 // Maximum transactions hashes to keep in the known list (prevent DOS) 45 maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) 46 forgetTxsInterval = 2 * time.Minute // Timer interval to forget known txs 47 handshakeTimeout = 5 * time.Second 48 49 // maxQueuedTxs is the maximum number of transaction lists to queue up before 50 // dropping broadcasts. This is a sensitive number as a transaction list might 51 // contain a single transaction, or thousands. 52 maxQueuedTxs = 16384 53 54 // maxQueuedProps is the maximum number of block propagations to queue up before 55 // dropping broadcasts. 56 maxQueuedProps = 32 57 58 // maxQueuedAnns is the maximum number of block announcements to queue up before 59 // dropping broadcasts. 60 maxQueuedAnns = 32 61 ) 62 63 // PeerInfo represents a short summary of the GoChain sub-protocol metadata known 64 // about a connected peer. 65 type PeerInfo struct { 66 Version int `json:"version"` // GoChain protocol version negotiated 67 Difficulty *big.Int `json:"difficulty"` // Total difficulty of the peer's blockchain 68 Head string `json:"head"` // SHA3 hash of the peer's best owned block 69 } 70 71 // knownHashes is a capped set of common.Hash safe for concurrent access. 72 // If forgetInterval is set, then the backing map is ignored or reset when older 73 // than forgetInterval. 74 type knownHashes struct { 75 sync.RWMutex 76 m map[common.Hash]struct{} 77 cap int 78 lastReset time.Time 79 forgetInterval time.Duration 80 } 81 82 func (s *knownHashes) reset() { 83 s.m = make(map[common.Hash]struct{}, s.cap) 84 s.lastReset = time.Now() 85 } 86 87 func (s *knownHashes) Add(h common.Hash) { 88 s.Lock() 89 if s.m == nil || (s.forgetInterval != 0 && time.Since(s.lastReset) > s.forgetInterval) { 90 s.reset() 91 } 92 s.m[h] = struct{}{} 93 s.Unlock() 94 } 95 96 func (s *knownHashes) AddAll(txs types.Transactions) { 97 s.Lock() 98 if s.m == nil || (s.forgetInterval != 0 && time.Since(s.lastReset) > s.forgetInterval) { 99 s.reset() 100 } 101 for _, tx := range txs { 102 s.m[tx.Hash()] = struct{}{} 103 } 104 s.Unlock() 105 } 106 107 // AddCapped is like Add, but first makes room if cap has been reached. 108 func (s *knownHashes) AddCapped(h common.Hash) { 109 s.Lock() 110 if s.m == nil || (s.forgetInterval != 0 && time.Since(s.lastReset) > s.forgetInterval) { 111 s.reset() 112 } else if len(s.m) >= s.cap { 113 i := len(s.m) + 1 - s.cap 114 for d := range s.m { 115 delete(s.m, d) 116 i-- 117 if i == 0 { 118 break 119 } 120 } 121 } 122 s.m[h] = struct{}{} 123 s.Unlock() 124 } 125 126 func (s *knownHashes) Has(h common.Hash) bool { 127 var ok bool 128 s.RLock() 129 if s.m == nil || (s.forgetInterval != 0 && time.Since(s.lastReset) > s.forgetInterval) { 130 ok = false 131 } else { 132 _, ok = s.m[h] 133 } 134 s.RUnlock() 135 return ok 136 } 137 138 // propEvent is a block propagation, waiting for its turn in the broadcast queue. 139 type propEvent struct { 140 block *types.Block 141 td *big.Int 142 } 143 144 type peer struct { 145 id string 146 147 *p2p.Peer 148 rw p2p.MsgReadWriter 149 150 version int // Protocol version negotiated 151 forkDrop *time.Timer // Timed connection dropper if forks aren't validated in time 152 153 head common.Hash 154 td *big.Int 155 lock sync.RWMutex 156 157 knownTxs knownHashes // Set of transaction hashes known to be known by this peer 158 knownBlocks knownHashes // Set of block hashes known to be known by this peer 159 160 queuedTxs chan types.Transactions // Queue of transactions to broadcast to the peer 161 queuedProps chan *propEvent //Queue of blocks to broadcast to the peer 162 queuedAnns chan *types.Block //Queue of blocks to announce to the peer 163 term chan struct{} // Termination channel to stop the broadcaster 164 } 165 166 func newPeer(version int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer { 167 return &peer{ 168 Peer: p, 169 rw: rw, 170 version: version, 171 id: fmt.Sprintf("%x", p.ID().Bytes()[:8]), 172 knownTxs: knownHashes{cap: maxKnownTxs, forgetInterval: forgetTxsInterval}, 173 knownBlocks: knownHashes{cap: maxKnownBlocks}, 174 queuedTxs: make(chan types.Transactions, maxQueuedTxs), 175 queuedProps: make(chan *propEvent, maxQueuedProps), 176 queuedAnns: make(chan *types.Block, maxQueuedAnns), 177 term: make(chan struct{}), 178 } 179 } 180 181 // broadcast is a write loop that multiplexes block propagations, announcements 182 // and transaction broadcasts into the remote peer. The goal is to have an async 183 // writer that does not lock up node internals. 184 func (p *peer) broadcast() { 185 for { 186 select { 187 case txs := <-p.queuedTxs: 188 ctx, span := trace.StartSpan(context.Background(), "peer.broadcast-queuedTxs") 189 190 const batchSize = 1000 191 batchLoop: 192 for len(txs) < batchSize { 193 select { 194 case more := <-p.queuedTxs: 195 txs = append(txs, more...) 196 default: 197 break batchLoop 198 } 199 } 200 span.AddAttributes(trace.Int64Attribute("txs", int64(len(txs)))) 201 if err := p.SendTransactions(ctx, txs); err != nil { 202 if err != p2p.ErrShuttingDown { 203 p.Log().Error("Failed to broadcast txs", "len", len(txs), "err", err) 204 } 205 span.SetStatus(trace.Status{ 206 Code: trace.StatusCodeInternal, 207 Message: err.Error(), 208 }) 209 } else { 210 p.Log().Trace("Broadcast txs", "len", len(txs)) 211 } 212 213 span.End() 214 215 case prop := <-p.queuedProps: 216 ctx, span := trace.StartSpan(context.Background(), "peer.broadcast-queuedProps") 217 span.AddAttributes(trace.Int64Attribute("num", int64(prop.block.NumberU64()))) 218 if err := p.SendNewBlock(ctx, prop.block, prop.td); err != nil { 219 p.Log().Error("Failed to propagate block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td, "err", err) 220 span.SetStatus(trace.Status{ 221 Code: trace.StatusCodeInternal, 222 Message: err.Error(), 223 }) 224 } else { 225 p.Log().Trace("Propagated block", "number", prop.block.Number(), "hash", prop.block.Hash(), "td", prop.td) 226 } 227 span.End() 228 229 case block := <-p.queuedAnns: 230 ctx, span := trace.StartSpan(context.Background(), "peer.broadcast-queuedAnns") 231 span.AddAttributes(trace.Int64Attribute("num", int64(block.NumberU64()))) 232 if err := p.SendNewBlockHash(ctx, block.Hash(), block.NumberU64()); err != nil { 233 p.Log().Error("Failed to announce block", "number", block.Number(), "hash", block.Hash(), "err", err) 234 span.SetStatus(trace.Status{ 235 Code: trace.StatusCodeInternal, 236 Message: err.Error(), 237 }) 238 } else { 239 p.Log().Trace("Announced block", "number", block.Number(), "hash", block.Hash()) 240 } 241 span.End() 242 243 case <-p.term: 244 return 245 } 246 } 247 } 248 249 // Close signals the broadcast goroutine to terminate. 250 func (p *peer) Close() { 251 close(p.term) 252 } 253 254 // Info gathers and returns a collection of metadata known about a peer. 255 func (p *peer) Info() *PeerInfo { 256 hash, td := p.Head() 257 258 return &PeerInfo{ 259 Version: p.version, 260 Difficulty: td, 261 Head: hash.Hex(), 262 } 263 } 264 265 // Head retrieves a copy of the current head hash and total difficulty of the 266 // peer. 267 func (p *peer) Head() (hash common.Hash, td *big.Int) { 268 p.lock.RLock() 269 defer p.lock.RUnlock() 270 271 copy(hash[:], p.head[:]) 272 return hash, new(big.Int).Set(p.td) 273 } 274 275 // SetHead updates the head hash and total difficulty of the peer. 276 func (p *peer) SetHead(hash common.Hash, td *big.Int) { 277 p.lock.Lock() 278 defer p.lock.Unlock() 279 280 copy(p.head[:], hash[:]) 281 p.td.Set(td) 282 } 283 284 // MarkBlock marks a block as known for the peer, ensuring that the block will 285 // never be propagated to this particular peer. 286 func (p *peer) MarkBlock(ctx context.Context, hash common.Hash) { 287 p.knownBlocks.AddCapped(hash) 288 } 289 290 // MarkTransaction marks a transaction as known for the peer, ensuring that it 291 // will never be propagated to this particular peer. 292 func (p *peer) MarkTransaction(ctx context.Context, hash common.Hash) { 293 p.knownTxs.AddCapped(hash) 294 } 295 296 // SendTransactions sends transactions to the peer and includes the hashes 297 // in its transaction hash set for future reference. 298 func (p *peer) SendTransactions(ctx context.Context, txs types.Transactions) error { 299 ctx, span := trace.StartSpan(ctx, "peer.Transactions") 300 defer span.End() 301 302 if err := p2p.SendCtx(ctx, p.rw, TxMsg, txs); err != nil { 303 span.SetStatus(trace.Status{ 304 Code: trace.StatusCodeInternal, 305 Message: err.Error(), 306 }) 307 return err 308 } 309 p.knownTxs.AddAll(txs) 310 return nil 311 } 312 313 // SendTransactionsAsync queues txs for broadcast, or drops them if the queue is full. 314 func (p *peer) SendTransactionsAsync(txs types.Transactions) { 315 select { 316 case p.queuedTxs <- txs: 317 default: 318 p.Log().Trace("Dropping transaction propagation: queue full", "count", len(txs)) 319 } 320 } 321 322 // SendNewBlockAsync queues a block for propagation, or drops it if the queue is full. 323 func (p *peer) SendNewBlockAsync(block *types.Block, td *big.Int) { 324 select { 325 case p.queuedProps <- &propEvent{block: block, td: td}: 326 default: 327 p.Log().Info("Dropping block propagation; queue full", "number", block.NumberU64(), "hash", block.Hash(), "diff", block.Difficulty(), "parent", block.ParentHash()) 328 } 329 } 330 331 // SendNewBlockHashAsync queues a block announcement, or drops it if the queue is full. 332 func (p *peer) SendNewBlockHashAsync(block *types.Block) { 333 select { 334 case p.queuedAnns <- block: 335 default: 336 p.Log().Info("Dropping block announcement; queue full", "number", block.NumberU64(), "hash", block.Hash(), "diff", block.Difficulty(), "parent", block.ParentHash()) 337 } 338 } 339 340 // SendNewBlockHash announces the availability of a block. 341 func (p *peer) SendNewBlockHash(ctx context.Context, hash common.Hash, number uint64) error { 342 ctx, span := trace.StartSpan(ctx, "peer.SendNewBlockHash") 343 defer span.End() 344 345 b, err := rlp.EncodeToBytes(newBlockHashesData{{Hash: hash, Number: number}}) 346 if err != nil { 347 return err 348 } 349 msg := p2p.Msg{Code: NewBlockHashesMsg, Size: uint32(len(b)), Payload: bytes.NewReader(b)} 350 351 if err := p.rw.WriteMsg(ctx, msg); err != nil { 352 return err 353 } 354 p.knownBlocks.Add(hash) 355 return nil 356 } 357 358 // SendNewBlock propagates an entire block. 359 func (p *peer) SendNewBlock(ctx context.Context, block *types.Block, td *big.Int) error { 360 ctx, span := trace.StartSpan(ctx, "peer.SendNewBlock") 361 defer span.End() 362 363 b, err := rlp.EncodeToBytes([]interface{}{block, td}) 364 if err != nil { 365 return err 366 } 367 msg := p2p.Msg{Code: NewBlockMsg, Size: uint32(len(b)), Payload: bytes.NewReader(b)} 368 369 _, ws := trace.StartSpan(ctx, "MsgWriter.WriteMsg") 370 if err := p.rw.WriteMsg(ctx, msg); err != nil { 371 ws.SetStatus(trace.Status{ 372 Code: trace.StatusCodeInternal, 373 Message: err.Error(), 374 }) 375 ws.End() 376 return err 377 } 378 ws.End() 379 p.knownBlocks.Add(block.Hash()) 380 return nil 381 } 382 383 // SendBlockHeaders sends a batch of block headers to the remote peer. 384 func (p *peer) SendBlockHeaders(ctx context.Context, headers []*types.Header) error { 385 return p2p.SendCtx(ctx, p.rw, BlockHeadersMsg, headers) 386 } 387 388 // SendBlockBodiesRLP sends a batch of block contents to the remote peer from 389 // an already RLP encoded format. 390 func (p *peer) SendBlockBodiesRLP(ctx context.Context, bodies []rlp.RawValue) error { 391 return p2p.SendCtx(ctx, p.rw, BlockBodiesMsg, bodies) 392 } 393 394 // SendNodeDataRLP sends a batch of arbitrary internal data, corresponding to the 395 // hashes requested. 396 func (p *peer) SendNodeData(ctx context.Context, data [][]byte) error { 397 return p2p.SendCtx(ctx, p.rw, NodeDataMsg, data) 398 } 399 400 // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the 401 // ones requested from an already RLP encoded format. 402 func (p *peer) SendReceiptsRLP(ctx context.Context, receipts []rlp.RawValue) error { 403 return p2p.SendCtx(ctx, p.rw, ReceiptsMsg, receipts) 404 } 405 406 // RequestOneHeader is a wrapper around the header query functions to fetch a 407 // single header. It is used solely by the fetcher. 408 func (p *peer) RequestOneHeader(ctx context.Context, hash common.Hash) error { 409 p.Log().Debug("Fetching single header", "hash", hash) 410 return p2p.SendCtx(ctx, p.rw, GetBlockHeadersMsg, 411 &getBlockHeadersData{Origin: hashOrNumber{Hash: hash}, Amount: uint64(1), Skip: uint64(0), Reverse: false}) 412 } 413 414 // RequestHeadersByHash fetches a batch of blocks' headers corresponding to the 415 // specified header query, based on the hash of an origin block. 416 func (p *peer) RequestHeadersByHash(ctx context.Context, origin common.Hash, amount int, skip int, reverse bool) error { 417 p.Log().Debug("Fetching batch of headers", "count", amount, "fromhash", origin, "skip", skip, "reverse", reverse) 418 return p2p.SendCtx(ctx, p.rw, GetBlockHeadersMsg, 419 &getBlockHeadersData{Origin: hashOrNumber{Hash: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 420 } 421 422 // RequestHeadersByNumber fetches a batch of blocks' headers corresponding to the 423 // specified header query, based on the number of an origin block. 424 func (p *peer) RequestHeadersByNumber(ctx context.Context, origin uint64, amount int, skip int, reverse bool) error { 425 p.Log().Debug("Fetching batch of headers", "count", amount, "fromnum", origin, "skip", skip, "reverse", reverse) 426 return p2p.SendCtx(ctx, p.rw, GetBlockHeadersMsg, 427 &getBlockHeadersData{Origin: hashOrNumber{Number: origin}, Amount: uint64(amount), Skip: uint64(skip), Reverse: reverse}) 428 } 429 430 // RequestBodies fetches a batch of blocks' bodies corresponding to the hashes 431 // specified. 432 func (p *peer) RequestBodies(ctx context.Context, hashes []common.Hash) error { 433 p.Log().Debug("Fetching batch of block bodies", "count", len(hashes)) 434 return p2p.SendCtx(ctx, p.rw, GetBlockBodiesMsg, hashes) 435 } 436 437 // RequestNodeData fetches a batch of arbitrary data from a node's known state 438 // data, corresponding to the specified hashes. 439 func (p *peer) RequestNodeData(ctx context.Context, hashes []common.Hash) error { 440 p.Log().Debug("Fetching batch of state data", "count", len(hashes)) 441 return p2p.SendCtx(ctx, p.rw, GetNodeDataMsg, hashes) 442 } 443 444 // RequestReceipts fetches a batch of transaction receipts from a remote node. 445 func (p *peer) RequestReceipts(ctx context.Context, hashes []common.Hash) error { 446 p.Log().Debug("Fetching batch of receipts", "count", len(hashes)) 447 return p2p.SendCtx(ctx, p.rw, GetReceiptsMsg, hashes) 448 } 449 450 // Handshake executes the eth protocol handshake, negotiating version number, 451 // network IDs, difficulties, head and genesis blocks. 452 func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash) error { 453 ctx, span := trace.StartSpan(context.Background(), "peer.Handshake-send-StatusMsg") 454 defer span.End() 455 456 // Send out own handshake in a new thread 457 errc := make(chan error, 2) 458 var status statusData // safe to read after two values have been received from errc 459 460 go func() { 461 errc <- p2p.SendCtx(ctx, p.rw, StatusMsg, &statusData{ 462 ProtocolVersion: uint32(p.version), 463 NetworkId: network, 464 TD: td, 465 CurrentBlock: head, 466 GenesisBlock: genesis, 467 }) 468 }() 469 go func() { 470 errc <- p.readStatus(network, &status, genesis) 471 }() 472 timeout := time.NewTimer(handshakeTimeout) 473 defer timeout.Stop() 474 for i := 0; i < 2; i++ { 475 select { 476 case err := <-errc: 477 if err != nil { 478 return err 479 } 480 case <-timeout.C: 481 span.SetStatus(trace.Status{ 482 Code: trace.StatusCodeDeadlineExceeded, 483 Message: p2p.DiscReadTimeout.Error(), 484 }) 485 return p2p.DiscReadTimeout 486 } 487 } 488 p.td, p.head = status.TD, status.CurrentBlock 489 return nil 490 } 491 492 func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash) (err error) { 493 msg, err := p.rw.ReadMsg() 494 if err != nil { 495 return err 496 } 497 if msg.Code != StatusMsg { 498 return errResp(ErrNoStatusMsg, "first msg has code %x (!= %x)", msg.Code, StatusMsg) 499 } 500 if msg.Size > ProtocolMaxMsgSize { 501 return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) 502 } 503 // Decode the handshake and make sure everything matches 504 if err := msg.Decode(&status); err != nil { 505 return errResp(ErrDecode, "msg %v: %v", msg, err) 506 } 507 if status.GenesisBlock != genesis { 508 return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8]) 509 } 510 if status.NetworkId != network { 511 return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network) 512 } 513 if int(status.ProtocolVersion) != p.version { 514 return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) 515 } 516 return nil 517 } 518 519 // String implements fmt.Stringer. 520 func (p *peer) String() string { 521 return fmt.Sprintf("Peer %s [%s]", p.id, 522 fmt.Sprintf("eth/%2d", p.version), 523 ) 524 } 525 526 // peerSet represents the collection of active peers currently participating in 527 // the GoChain sub-protocol. 528 type peerSet struct { 529 peers map[string]*peer 530 lock sync.RWMutex 531 closed bool 532 } 533 534 // newPeerSet creates a new peer set to track the active participants. 535 func newPeerSet() *peerSet { 536 return &peerSet{ 537 peers: make(map[string]*peer), 538 } 539 } 540 541 // Register injects a new peer into the working set, or returns an error if the 542 // peer is already known. If a new peer is registered, its broadcast loop is also 543 // started. 544 func (ps *peerSet) Register(p *peer) error { 545 ps.lock.Lock() 546 defer ps.lock.Unlock() 547 548 if ps.closed { 549 return errClosed 550 } 551 if _, ok := ps.peers[p.id]; ok { 552 return errAlreadyRegistered 553 } 554 ps.peers[p.id] = p 555 go p.broadcast() 556 return nil 557 } 558 559 // Unregister removes a remote peer from the active set, disabling any further 560 // actions to/from that particular entity. 561 func (ps *peerSet) Unregister(id string) error { 562 ps.lock.Lock() 563 defer ps.lock.Unlock() 564 p, ok := ps.peers[id] 565 if !ok { 566 return errNotRegistered 567 } 568 delete(ps.peers, id) 569 p.Close() 570 return nil 571 } 572 573 // Peer retrieves the registered peer with the given id. 574 func (ps *peerSet) Peer(id string) *peer { 575 ps.lock.RLock() 576 defer ps.lock.RUnlock() 577 578 return ps.peers[id] 579 } 580 581 // Len returns if the current number of peers in the set. 582 func (ps *peerSet) Len() int { 583 ps.lock.RLock() 584 defer ps.lock.RUnlock() 585 586 return len(ps.peers) 587 } 588 589 // All returns all current peers. 590 func (ps *peerSet) All() []*peer { 591 ps.lock.RLock() 592 defer ps.lock.RUnlock() 593 594 all := make([]*peer, 0, ps.Len()) 595 for _, p := range ps.peers { 596 all = append(all, p) 597 } 598 return all 599 } 600 601 // PeersWithoutBlock retrieves a list of peers that do not have a given block in 602 // their set of known hashes. cap is the total number of peers. 603 func (ps *peerSet) PeersWithoutBlock(ctx context.Context, hash common.Hash) []*peer { 604 ctx, span := trace.StartSpan(ctx, "peerSet.PeersWithoutBlock") 605 defer span.End() 606 607 ps.lock.RLock() 608 defer ps.lock.RUnlock() 609 610 l := len(ps.peers) 611 612 span.AddAttributes(trace.Int64Attribute("peers", int64(l))) 613 614 list := make([]*peer, 0, l) 615 for _, p := range ps.peers { 616 if !p.knownBlocks.Has(hash) { 617 list = append(list, p) 618 } 619 } 620 return list 621 } 622 623 // PeersWithoutTxs retrieves a map of peers to transactions from txs which are not in their set of known hashes. 624 // Each transaction will be included in the lists of, at most, square root of total peers. 625 func (ps *peerSet) PeersWithoutTxs(ctx context.Context, txs types.Transactions) map[*peer]types.Transactions { 626 ctx, span := trace.StartSpan(ctx, "peerSet.PeersWithoutTxs") 627 defer span.End() 628 span.AddAttributes(trace.Int64Attribute("txs", int64(len(txs)))) 629 630 peerTxs := make(map[*peer]types.Transactions) 631 tracing := log.Tracing() 632 633 ps.lock.RLock() 634 defer ps.lock.RUnlock() 635 636 span.AddAttributes(trace.Int64Attribute("peers", int64(len(ps.peers)))) 637 638 for _, tx := range txs { 639 hash := tx.Hash() 640 var count int 641 for _, p := range ps.peers { 642 if p.knownTxs.Has(hash) { 643 continue 644 } 645 peerTxs[p] = append(peerTxs[p], tx) 646 count++ 647 } 648 if tracing && count > 0 { 649 log.Trace("Broadcast transaction", "hash", hash, "recipients", count) 650 } 651 } 652 653 return peerTxs 654 } 655 656 // BestPeer retrieves the known peer with the currently highest total difficulty. 657 func (ps *peerSet) BestPeer(ctx context.Context) *peer { 658 ctx, span := trace.StartSpan(ctx, "peerSet.BestPeer") 659 defer span.End() 660 ps.lock.RLock() 661 defer ps.lock.RUnlock() 662 663 var ( 664 bestPeer *peer 665 bestTd *big.Int 666 ) 667 for _, p := range ps.peers { 668 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 669 bestPeer, bestTd = p, td 670 } 671 } 672 return bestPeer 673 } 674 675 // Close disconnects all peers. 676 // No new peers can be registered after Close has returned. 677 func (ps *peerSet) Close() { 678 ps.lock.Lock() 679 defer ps.lock.Unlock() 680 681 for _, p := range ps.peers { 682 p.Disconnect(p2p.DiscQuitting) 683 } 684 ps.closed = true 685 }