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 }