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 := &ethPeer{
   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  }