github.com/phillinzzz/newBsc@v1.1.6/eth/peerset.go (about) 1 // Copyright 2020 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/big" 22 "sync" 23 24 "github.com/phillinzzz/newBsc/common" 25 "github.com/phillinzzz/newBsc/eth/downloader" 26 "github.com/phillinzzz/newBsc/eth/protocols/diff" 27 "github.com/phillinzzz/newBsc/eth/protocols/eth" 28 "github.com/phillinzzz/newBsc/eth/protocols/snap" 29 "github.com/phillinzzz/newBsc/p2p" 30 ) 31 32 var ( 33 // errPeerSetClosed is returned if a peer is attempted to be added or removed 34 // from the peer set after it has been terminated. 35 errPeerSetClosed = errors.New("peerset closed") 36 37 // errPeerAlreadyRegistered is returned if a peer is attempted to be added 38 // to the peer set, but one with the same id already exists. 39 errPeerAlreadyRegistered = errors.New("peer already registered") 40 41 // errPeerNotRegistered is returned if a peer is attempted to be removed from 42 // a peer set, but no peer with the given id exists. 43 errPeerNotRegistered = errors.New("peer not registered") 44 45 // errSnapWithoutEth is returned if a peer attempts to connect only on the 46 // snap protocol without advertizing the eth main protocol. 47 errSnapWithoutEth = errors.New("peer connected on snap without compatible eth support") 48 49 // errDiffWithoutEth is returned if a peer attempts to connect only on the 50 // diff protocol without advertizing the eth main protocol. 51 errDiffWithoutEth = errors.New("peer connected on diff without compatible eth support") 52 ) 53 54 // peerSet represents the collection of active peers currently participating in 55 // the `eth` protocol, with or without the `snap` extension. 56 type peerSet struct { 57 peers map[string]*ethPeer // Peers connected on the `eth` protocol 58 snapPeers int // Number of `snap` compatible peers for connection prioritization 59 60 snapWait map[string]chan *snap.Peer // Peers connected on `eth` waiting for their snap extension 61 snapPend map[string]*snap.Peer // Peers connected on the `snap` protocol, but not yet on `eth` 62 63 diffWait map[string]chan *diff.Peer // Peers connected on `eth` waiting for their diff extension 64 diffPend map[string]*diff.Peer // Peers connected on the `diff` protocol, but not yet on `eth` 65 66 lock sync.RWMutex 67 closed bool 68 } 69 70 // newPeerSet creates a new peer set to track the active participants. 71 func newPeerSet() *peerSet { 72 return &peerSet{ 73 peers: make(map[string]*ethPeer), 74 snapWait: make(map[string]chan *snap.Peer), 75 snapPend: make(map[string]*snap.Peer), 76 diffWait: make(map[string]chan *diff.Peer), 77 diffPend: make(map[string]*diff.Peer), 78 } 79 } 80 81 // registerSnapExtension unblocks an already connected `eth` peer waiting for its 82 // `snap` extension, or if no such peer exists, tracks the extension for the time 83 // being until the `eth` main protocol starts looking for it. 84 func (ps *peerSet) registerSnapExtension(peer *snap.Peer) error { 85 // Reject the peer if it advertises `snap` without `eth` as `snap` is only a 86 // satellite protocol meaningful with the chain selection of `eth` 87 if !peer.RunningCap(eth.ProtocolName, eth.ProtocolVersions) { 88 return errSnapWithoutEth 89 } 90 // Ensure nobody can double connect 91 ps.lock.Lock() 92 defer ps.lock.Unlock() 93 94 id := peer.ID() 95 if _, ok := ps.peers[id]; ok { 96 return errPeerAlreadyRegistered // avoid connections with the same id as existing ones 97 } 98 if _, ok := ps.snapPend[id]; ok { 99 return errPeerAlreadyRegistered // avoid connections with the same id as pending ones 100 } 101 // Inject the peer into an `eth` counterpart is available, otherwise save for later 102 if wait, ok := ps.snapWait[id]; ok { 103 delete(ps.snapWait, id) 104 wait <- peer 105 return nil 106 } 107 ps.snapPend[id] = peer 108 return nil 109 } 110 111 // registerDiffExtension unblocks an already connected `eth` peer waiting for its 112 // `diff` extension, or if no such peer exists, tracks the extension for the time 113 // being until the `eth` main protocol starts looking for it. 114 func (ps *peerSet) registerDiffExtension(peer *diff.Peer) error { 115 // Reject the peer if it advertises `diff` without `eth` as `diff` is only a 116 // satellite protocol meaningful with the chain selection of `eth` 117 if !peer.RunningCap(eth.ProtocolName, eth.ProtocolVersions) { 118 return errDiffWithoutEth 119 } 120 // Ensure nobody can double connect 121 ps.lock.Lock() 122 defer ps.lock.Unlock() 123 124 id := peer.ID() 125 if _, ok := ps.peers[id]; ok { 126 return errPeerAlreadyRegistered // avoid connections with the same id as existing ones 127 } 128 if _, ok := ps.diffPend[id]; ok { 129 return errPeerAlreadyRegistered // avoid connections with the same id as pending ones 130 } 131 // Inject the peer into an `eth` counterpart is available, otherwise save for later 132 if wait, ok := ps.diffWait[id]; ok { 133 delete(ps.diffWait, id) 134 wait <- peer 135 return nil 136 } 137 ps.diffPend[id] = peer 138 return nil 139 } 140 141 // waitExtensions blocks until all satellite protocols are connected and tracked 142 // by the peerset. 143 func (ps *peerSet) waitSnapExtension(peer *eth.Peer) (*snap.Peer, error) { 144 // If the peer does not support a compatible `snap`, don't wait 145 if !peer.RunningCap(snap.ProtocolName, snap.ProtocolVersions) { 146 return nil, nil 147 } 148 // Ensure nobody can double connect 149 ps.lock.Lock() 150 151 id := peer.ID() 152 if _, ok := ps.peers[id]; ok { 153 ps.lock.Unlock() 154 return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones 155 } 156 if _, ok := ps.snapWait[id]; ok { 157 ps.lock.Unlock() 158 return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones 159 } 160 // If `snap` already connected, retrieve the peer from the pending set 161 if snap, ok := ps.snapPend[id]; ok { 162 delete(ps.snapPend, id) 163 164 ps.lock.Unlock() 165 return snap, nil 166 } 167 // Otherwise wait for `snap` to connect concurrently 168 wait := make(chan *snap.Peer) 169 ps.snapWait[id] = wait 170 ps.lock.Unlock() 171 172 return <-wait, nil 173 } 174 175 // waitDiffExtension blocks until all satellite protocols are connected and tracked 176 // by the peerset. 177 func (ps *peerSet) waitDiffExtension(peer *eth.Peer) (*diff.Peer, error) { 178 // If the peer does not support a compatible `diff`, don't wait 179 if !peer.RunningCap(diff.ProtocolName, diff.ProtocolVersions) { 180 return nil, nil 181 } 182 // Ensure nobody can double connect 183 ps.lock.Lock() 184 185 id := peer.ID() 186 if _, ok := ps.peers[id]; ok { 187 ps.lock.Unlock() 188 return nil, errPeerAlreadyRegistered // avoid connections with the same id as existing ones 189 } 190 if _, ok := ps.diffWait[id]; ok { 191 ps.lock.Unlock() 192 return nil, errPeerAlreadyRegistered // avoid connections with the same id as pending ones 193 } 194 // If `diff` already connected, retrieve the peer from the pending set 195 if diff, ok := ps.diffPend[id]; ok { 196 delete(ps.diffPend, id) 197 198 ps.lock.Unlock() 199 return diff, nil 200 } 201 // Otherwise wait for `diff` to connect concurrently 202 wait := make(chan *diff.Peer) 203 ps.diffWait[id] = wait 204 ps.lock.Unlock() 205 206 return <-wait, nil 207 } 208 209 func (ps *peerSet) GetDiffPeer(pid string) downloader.IDiffPeer { 210 if p := ps.peer(pid); p != nil && p.diffExt != nil { 211 return p.diffExt 212 } 213 return nil 214 } 215 216 // registerPeer injects a new `eth` peer into the working set, or returns an error 217 // if the peer is already known. 218 func (ps *peerSet) registerPeer(peer *eth.Peer, ext *snap.Peer, diffExt *diff.Peer) error { 219 // Start tracking the new peer 220 ps.lock.Lock() 221 defer ps.lock.Unlock() 222 223 if ps.closed { 224 return errPeerSetClosed 225 } 226 id := peer.ID() 227 if _, ok := ps.peers[id]; ok { 228 return errPeerAlreadyRegistered 229 } 230 eth := ðPeer{ 231 Peer: peer, 232 } 233 if ext != nil { 234 eth.snapExt = &snapPeer{ext} 235 ps.snapPeers++ 236 } 237 if diffExt != nil { 238 eth.diffExt = &diffPeer{diffExt} 239 } 240 ps.peers[id] = eth 241 return nil 242 } 243 244 // unregisterPeer removes a remote peer from the active set, disabling any further 245 // actions to/from that particular entity. 246 func (ps *peerSet) unregisterPeer(id string) error { 247 ps.lock.Lock() 248 defer ps.lock.Unlock() 249 250 peer, ok := ps.peers[id] 251 if !ok { 252 return errPeerNotRegistered 253 } 254 delete(ps.peers, id) 255 if peer.snapExt != nil { 256 ps.snapPeers-- 257 } 258 return nil 259 } 260 261 // peer retrieves the registered peer with the given id. 262 func (ps *peerSet) peer(id string) *ethPeer { 263 ps.lock.RLock() 264 defer ps.lock.RUnlock() 265 266 return ps.peers[id] 267 } 268 269 // peersWithoutBlock retrieves a list of peers that do not have a given block in 270 // their set of known hashes so it might be propagated to them. 271 func (ps *peerSet) peersWithoutBlock(hash common.Hash) []*ethPeer { 272 ps.lock.RLock() 273 defer ps.lock.RUnlock() 274 275 list := make([]*ethPeer, 0, len(ps.peers)) 276 for _, p := range ps.peers { 277 if !p.KnownBlock(hash) { 278 list = append(list, p) 279 } 280 } 281 return list 282 } 283 284 // peersWithoutTransaction retrieves a list of peers that do not have a given 285 // transaction in their set of known hashes. 286 func (ps *peerSet) peersWithoutTransaction(hash common.Hash) []*ethPeer { 287 ps.lock.RLock() 288 defer ps.lock.RUnlock() 289 290 list := make([]*ethPeer, 0, len(ps.peers)) 291 for _, p := range ps.peers { 292 if !p.KnownTransaction(hash) { 293 list = append(list, p) 294 } 295 } 296 return list 297 } 298 299 // len returns if the current number of `eth` peers in the set. Since the `snap` 300 // peers are tied to the existence of an `eth` connection, that will always be a 301 // subset of `eth`. 302 func (ps *peerSet) len() int { 303 ps.lock.RLock() 304 defer ps.lock.RUnlock() 305 306 return len(ps.peers) 307 } 308 309 // snapLen returns if the current number of `snap` peers in the set. 310 func (ps *peerSet) snapLen() int { 311 ps.lock.RLock() 312 defer ps.lock.RUnlock() 313 314 return ps.snapPeers 315 } 316 317 // peerWithHighestTD retrieves the known peer with the currently highest total 318 // difficulty. 319 func (ps *peerSet) peerWithHighestTD() *eth.Peer { 320 ps.lock.RLock() 321 defer ps.lock.RUnlock() 322 323 var ( 324 bestPeer *eth.Peer 325 bestTd *big.Int 326 ) 327 for _, p := range ps.peers { 328 if _, td := p.Head(); bestPeer == nil || td.Cmp(bestTd) > 0 { 329 bestPeer, bestTd = p.Peer, td 330 } 331 } 332 return bestPeer 333 } 334 335 // close disconnects all peers. 336 func (ps *peerSet) close() { 337 ps.lock.Lock() 338 defer ps.lock.Unlock() 339 340 for _, p := range ps.peers { 341 p.Disconnect(p2p.DiscQuitting) 342 } 343 ps.closed = true 344 }