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  }