github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/eth/peerSet.go (about)

     1  package eth
     2  
     3  import (
     4  	"github.com/ethereumproject/go-ethereum/common"
     5  	"github.com/ethereumproject/go-ethereum/p2p"
     6  	"math/big"
     7  	"sync"
     8  )
     9  
    10  // peerSet represents the collection of active peers currently participating in
    11  // the Ethereum sub-protocol.
    12  type peerSet struct {
    13  	peers  map[string]*peer
    14  	lock   sync.RWMutex
    15  	closed bool
    16  }
    17  
    18  // newPeerSet creates a new peer set to track the active participants.
    19  func newPeerSet() *peerSet {
    20  	return &peerSet{
    21  		peers: make(map[string]*peer),
    22  	}
    23  }
    24  
    25  // Register injects a new peer into the working set, or returns an error if the
    26  // peer is already known.
    27  func (ps *peerSet) Register(p *peer) error {
    28  	ps.lock.Lock()
    29  	defer ps.lock.Unlock()
    30  
    31  	if ps.closed {
    32  		return errClosed
    33  	}
    34  	if _, ok := ps.peers[p.id]; ok {
    35  		return errAlreadyRegistered
    36  	}
    37  	ps.peers[p.id] = p
    38  	go p.broadcast()
    39  	return nil
    40  }
    41  
    42  // Unregister removes a remote peer from the active set, disabling any further
    43  // actions to/from that particular entity.
    44  func (ps *peerSet) Unregister(id string) error {
    45  	ps.lock.Lock()
    46  	defer ps.lock.Unlock()
    47  
    48  	p, ok := ps.peers[id]
    49  	if !ok {
    50  		return errNotRegistered
    51  	}
    52  	delete(ps.peers, id)
    53  	p.close()
    54  
    55  	return nil
    56  }
    57  
    58  // Peer retrieves the registered peer with the given id.
    59  func (ps *peerSet) Peer(id string) *peer {
    60  	ps.lock.RLock()
    61  	defer ps.lock.RUnlock()
    62  
    63  	return ps.peers[id]
    64  }
    65  
    66  // Len returns if the current number of peers in the set.
    67  func (ps *peerSet) Len() int {
    68  	ps.lock.RLock()
    69  	defer ps.lock.RUnlock()
    70  
    71  	return len(ps.peers)
    72  }
    73  
    74  // PeersWithoutBlock retrieves a list of peers that do not have a given block in
    75  // their set of known hashes.
    76  func (ps *peerSet) PeersWithoutBlock(hash common.Hash) []*peer {
    77  	ps.lock.RLock()
    78  	defer ps.lock.RUnlock()
    79  
    80  	list := make([]*peer, 0, len(ps.peers))
    81  	for _, p := range ps.peers {
    82  		if !p.knownBlocks.Has(hash) {
    83  			list = append(list, p)
    84  		}
    85  	}
    86  	return list
    87  }
    88  
    89  // PeersWithoutTx retrieves a list of peers that do not have a given transaction
    90  // in their set of known hashes.
    91  func (ps *peerSet) PeersWithoutTx(hash common.Hash) []*peer {
    92  	ps.lock.RLock()
    93  	defer ps.lock.RUnlock()
    94  
    95  	list := make([]*peer, 0, len(ps.peers))
    96  	for _, p := range ps.peers {
    97  		if !p.knownTxs.Has(hash) {
    98  			list = append(list, p)
    99  		}
   100  	}
   101  	return list
   102  }
   103  
   104  // BestPeer retrieves the known peer with the currently highest total difficulty.
   105  func (ps *peerSet) BestPeer() *peer {
   106  	ps.lock.RLock()
   107  	defer ps.lock.RUnlock()
   108  
   109  	var (
   110  		bestPeer *peer
   111  		bestTd   *big.Int
   112  	)
   113  	for _, p := range ps.peers {
   114  		if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 {
   115  			bestPeer, bestTd = p, td
   116  		}
   117  	}
   118  	return bestPeer
   119  }
   120  
   121  // Close disconnects all peers.
   122  // No new peers can be registered after Close has returned.
   123  func (ps *peerSet) Close() {
   124  	ps.lock.Lock()
   125  	defer ps.lock.Unlock()
   126  
   127  	for _, p := range ps.peers {
   128  		p.Disconnect(p2p.DiscQuitting)
   129  	}
   130  	ps.closed = true
   131  }