erigon-pulse/eth/peerset.go
Artem Vorotnikov e67be2b1be
Remove unused code (#1604)
* Remove graphql, legacy options

* Remove CODEOWNERS

* Remove EWASM and custom EVM interpreter
2021-03-26 09:08:01 +07:00

168 lines
4.5 KiB
Go

// Copyright 2020 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package eth
import (
"errors"
"sync"
"github.com/ledgerwatch/turbo-geth/common"
"github.com/ledgerwatch/turbo-geth/eth/protocols/eth"
"github.com/ledgerwatch/turbo-geth/p2p"
)
var (
// errPeerSetClosed is returned if a peer is attempted to be added or removed
// from the peer set after it has been terminated.
errPeerSetClosed = errors.New("peerset closed")
// errPeerAlreadyRegistered is returned if a peer is attempted to be added
// to the peer set, but one with the same id already exists.
errPeerAlreadyRegistered = errors.New("peer already registered")
// errPeerNotRegistered is returned if a peer is attempted to be removed from
// a peer set, but no peer with the given id exists.
errPeerNotRegistered = errors.New("peer not registered")
)
// peerSet represents the collection of active peers currently participating in
// the `eth` protocol, with or without the `snap` extension.
type peerSet struct {
peers map[string]*ethPeer // Peers connected on the `eth` protocol
lock sync.RWMutex
closed bool
}
// newPeerSet creates a new peer set to track the active participants.
func newPeerSet() *peerSet {
return &peerSet{
peers: make(map[string]*ethPeer),
}
}
// registerPeer injects a new `eth` peer into the working set, or returns an error
// if the peer is already known.
func (ps *peerSet) registerPeer(peer *eth.Peer) error {
// Start tracking the new peer
ps.lock.Lock()
defer ps.lock.Unlock()
if ps.closed {
return errPeerSetClosed
}
id := peer.ID()
if _, ok := ps.peers[id]; ok {
return errPeerAlreadyRegistered
}
eth := &ethPeer{
Peer: peer,
}
ps.peers[id] = eth
return nil
}
// unregisterPeer removes a remote peer from the active set, disabling any further
// actions to/from that particular entity.
func (ps *peerSet) unregisterPeer(id string) error {
ps.lock.Lock()
defer ps.lock.Unlock()
_, ok := ps.peers[id]
if !ok {
return errPeerNotRegistered
}
delete(ps.peers, id)
return nil
}
// peer retrieves the registered peer with the given id.
func (ps *peerSet) peer(id string) *ethPeer {
ps.lock.RLock()
defer ps.lock.RUnlock()
return ps.peers[id]
}
// peersWithoutBlock retrieves a list of peers that do not have a given block in
// their set of known hashes so it might be propagated to them.
func (ps *peerSet) peersWithoutBlock(hash common.Hash) []*ethPeer {
ps.lock.RLock()
defer ps.lock.RUnlock()
list := make([]*ethPeer, 0, len(ps.peers))
for _, p := range ps.peers {
if !p.KnownBlock(hash) {
list = append(list, p)
}
}
return list
}
// peersWithoutTransaction retrieves a list of peers that do not have a given
// transaction in their set of known hashes.
func (ps *peerSet) peersWithoutTransaction(hash common.Hash) []*ethPeer {
ps.lock.RLock()
defer ps.lock.RUnlock()
list := make([]*ethPeer, 0, len(ps.peers))
for _, p := range ps.peers {
if !p.KnownTransaction(hash) {
list = append(list, p)
}
}
return list
}
// len returns if the current number of `eth` peers in the set. Since the `snap`
// peers are tied to the existence of an `eth` connection, that will always be a
// subset of `eth`.
func (ps *peerSet) len() int {
ps.lock.RLock()
defer ps.lock.RUnlock()
return len(ps.peers)
}
// peerWithHighestNumber retrieves the known peer with the currently highest block height.
func (ps *peerSet) peerWithHighestNumber() *eth.Peer {
ps.lock.RLock()
defer ps.lock.RUnlock()
var (
bestPeer *eth.Peer
bestNumber uint64
)
for _, p := range ps.peers {
if _, headNumber := p.Head(); bestPeer == nil || headNumber > bestNumber {
bestPeer, bestNumber = p.Peer, headNumber
}
}
return bestPeer
}
// close disconnects all peers.
func (ps *peerSet) close() {
ps.lock.Lock()
defer ps.lock.Unlock()
for _, p := range ps.peers {
p.Disconnect(p2p.DiscQuitting)
}
ps.closed = true
}