2021-11-16 14:22:01 +00:00
|
|
|
package discv5
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/ecdsa"
|
2023-01-13 23:58:22 +00:00
|
|
|
"errors"
|
2023-01-27 17:36:52 +00:00
|
|
|
"fmt"
|
2021-11-16 14:22:01 +00:00
|
|
|
"net"
|
|
|
|
"sync"
|
2023-05-04 05:39:51 +00:00
|
|
|
"sync/atomic"
|
2023-01-27 17:36:52 +00:00
|
|
|
"time"
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2022-10-19 19:39:32 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
2023-02-08 16:02:06 +00:00
|
|
|
"github.com/multiformats/go-multiaddr"
|
2022-10-27 15:23:20 +00:00
|
|
|
"github.com/waku-org/go-discover/discover"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/logging"
|
2023-06-05 14:39:38 +00:00
|
|
|
v2 "github.com/waku-org/go-waku/waku/v2"
|
2023-04-19 20:54:33 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/metrics"
|
2023-06-05 14:39:38 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/peers"
|
2023-07-27 18:14:14 +00:00
|
|
|
wenr "github.com/waku-org/go-waku/waku/v2/protocol/enr"
|
|
|
|
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/utils"
|
2022-01-18 18:17:06 +00:00
|
|
|
"go.uber.org/zap"
|
2022-12-09 18:09:06 +00:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
2021-11-16 14:22:01 +00:00
|
|
|
)
|
|
|
|
|
2023-02-07 22:27:22 +00:00
|
|
|
var ErrNoDiscV5Listener = errors.New("no discv5 listener")
|
|
|
|
|
2023-07-07 12:35:22 +00:00
|
|
|
type PeerConnector interface {
|
|
|
|
Subscribe(context.Context, <-chan v2.PeerData)
|
|
|
|
}
|
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
type DiscoveryV5 struct {
|
2023-07-07 12:35:22 +00:00
|
|
|
params *discV5Parameters
|
|
|
|
host host.Host
|
|
|
|
config discover.Config
|
|
|
|
udpAddr *net.UDPAddr
|
|
|
|
listener *discover.UDPv5
|
|
|
|
localnode *enode.LocalNode
|
|
|
|
|
2023-01-13 23:58:22 +00:00
|
|
|
peerConnector PeerConnector
|
2023-07-07 12:35:22 +00:00
|
|
|
peerCh chan v2.PeerData
|
2023-01-13 23:58:22 +00:00
|
|
|
NAT nat.Interface
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2022-05-30 15:55:30 +00:00
|
|
|
log *zap.Logger
|
2022-01-18 18:17:06 +00:00
|
|
|
|
2023-05-04 10:02:00 +00:00
|
|
|
started atomic.Bool
|
2022-12-10 15:38:18 +00:00
|
|
|
cancel context.CancelFunc
|
|
|
|
wg *sync.WaitGroup
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type discV5Parameters struct {
|
2021-11-17 16:19:42 +00:00
|
|
|
autoUpdate bool
|
2023-06-12 14:36:06 +00:00
|
|
|
autoFindPeers bool
|
2021-11-17 16:19:42 +00:00
|
|
|
bootnodes []*enode.Node
|
2023-01-12 02:20:23 +00:00
|
|
|
udpPort uint
|
2023-02-08 16:02:06 +00:00
|
|
|
advertiseAddr []multiaddr.Multiaddr
|
2023-06-12 14:36:06 +00:00
|
|
|
loopPredicate func(*enode.Node) bool
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type DiscoveryV5Option func(*discV5Parameters)
|
|
|
|
|
2022-10-27 15:23:20 +00:00
|
|
|
var protocolID = [6]byte{'d', '5', 'w', 'a', 'k', 'u'}
|
|
|
|
|
2023-07-07 15:51:15 +00:00
|
|
|
const peerDelay = 100 * time.Millisecond
|
|
|
|
const bucketSize = 16
|
|
|
|
const delayBetweenDiscoveredPeerCnt = 5 * time.Second
|
|
|
|
|
2021-11-17 16:19:42 +00:00
|
|
|
func WithAutoUpdate(autoUpdate bool) DiscoveryV5Option {
|
|
|
|
return func(params *discV5Parameters) {
|
|
|
|
params.autoUpdate = autoUpdate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
func WithBootnodes(bootnodes []*enode.Node) DiscoveryV5Option {
|
|
|
|
return func(params *discV5Parameters) {
|
|
|
|
params.bootnodes = bootnodes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-08 16:02:06 +00:00
|
|
|
func WithAdvertiseAddr(addr []multiaddr.Multiaddr) DiscoveryV5Option {
|
2021-11-16 14:22:01 +00:00
|
|
|
return func(params *discV5Parameters) {
|
2023-02-08 16:02:06 +00:00
|
|
|
params.advertiseAddr = addr
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-12 02:20:23 +00:00
|
|
|
func WithUDPPort(port uint) DiscoveryV5Option {
|
2021-11-16 14:22:01 +00:00
|
|
|
return func(params *discV5Parameters) {
|
|
|
|
params.udpPort = port
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-12 14:36:06 +00:00
|
|
|
func WithPredicate(predicate func(*enode.Node) bool) DiscoveryV5Option {
|
|
|
|
return func(params *discV5Parameters) {
|
|
|
|
params.loopPredicate = predicate
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func WithAutoFindPeers(find bool) DiscoveryV5Option {
|
|
|
|
return func(params *discV5Parameters) {
|
|
|
|
params.autoFindPeers = find
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
func DefaultOptions() []DiscoveryV5Option {
|
|
|
|
return []DiscoveryV5Option{
|
|
|
|
WithUDPPort(9000),
|
2023-06-12 14:36:06 +00:00
|
|
|
WithAutoFindPeers(true),
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-17 00:04:12 +00:00
|
|
|
func NewDiscoveryV5(priv *ecdsa.PrivateKey, localnode *enode.LocalNode, peerConnector PeerConnector, log *zap.Logger, opts ...DiscoveryV5Option) (*DiscoveryV5, error) {
|
2021-11-16 14:22:01 +00:00
|
|
|
params := new(discV5Parameters)
|
|
|
|
optList := DefaultOptions()
|
|
|
|
optList = append(optList, opts...)
|
|
|
|
for _, opt := range optList {
|
|
|
|
opt(params)
|
|
|
|
}
|
|
|
|
|
2022-01-18 18:17:06 +00:00
|
|
|
logger := log.Named("discv5")
|
|
|
|
|
2021-11-23 14:24:05 +00:00
|
|
|
var NAT nat.Interface = nil
|
|
|
|
if params.advertiseAddr == nil {
|
|
|
|
NAT = nat.Any()
|
|
|
|
}
|
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
return &DiscoveryV5{
|
2023-01-13 23:58:22 +00:00
|
|
|
params: params,
|
2023-07-07 12:35:22 +00:00
|
|
|
peerConnector: peerConnector,
|
2023-01-13 23:58:22 +00:00
|
|
|
NAT: NAT,
|
|
|
|
wg: &sync.WaitGroup{},
|
|
|
|
localnode: localnode,
|
2021-11-16 14:22:01 +00:00
|
|
|
config: discover.Config{
|
|
|
|
PrivateKey: priv,
|
|
|
|
Bootnodes: params.bootnodes,
|
2022-02-28 18:28:09 +00:00
|
|
|
V5Config: discover.V5Config{
|
2022-10-27 15:23:20 +00:00
|
|
|
ProtocolID: &protocolID,
|
2022-02-28 18:28:09 +00:00
|
|
|
},
|
2021-11-16 14:22:01 +00:00
|
|
|
},
|
|
|
|
udpAddr: &net.UDPAddr{
|
2021-11-17 16:19:42 +00:00
|
|
|
IP: net.IPv4zero,
|
2023-01-12 02:20:23 +00:00
|
|
|
Port: int(params.udpPort),
|
2021-11-16 14:22:01 +00:00
|
|
|
},
|
2022-06-13 18:30:35 +00:00
|
|
|
log: logger,
|
2021-11-16 14:22:01 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2022-10-23 13:13:43 +00:00
|
|
|
func (d *DiscoveryV5) Node() *enode.Node {
|
|
|
|
return d.localnode.Node()
|
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
func (d *DiscoveryV5) listen(ctx context.Context) error {
|
2021-11-16 14:22:01 +00:00
|
|
|
conn, err := net.ListenUDP("udp", d.udpAddr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-11-23 14:24:05 +00:00
|
|
|
d.udpAddr = conn.LocalAddr().(*net.UDPAddr)
|
2023-05-04 05:39:51 +00:00
|
|
|
|
2021-11-23 14:24:05 +00:00
|
|
|
if d.NAT != nil && !d.udpAddr.IP.IsLoopback() {
|
2021-11-23 15:03:12 +00:00
|
|
|
d.wg.Add(1)
|
2021-11-23 14:24:05 +00:00
|
|
|
go func() {
|
2021-11-23 15:03:12 +00:00
|
|
|
defer d.wg.Done()
|
2022-12-10 15:38:18 +00:00
|
|
|
nat.Map(d.NAT, ctx.Done(), "udp", d.udpAddr.Port, d.udpAddr.Port, "go-waku discv5 discovery")
|
2021-11-23 14:24:05 +00:00
|
|
|
}()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
d.localnode.SetFallbackUDP(d.udpAddr.Port)
|
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
listener, err := discover.ListenV5(conn, d.localnode, d.config)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
d.listener = listener
|
|
|
|
|
2022-05-30 15:55:30 +00:00
|
|
|
d.log.Info("started Discovery V5",
|
|
|
|
zap.Stringer("listening", d.udpAddr),
|
|
|
|
logging.TCPAddr("advertising", d.localnode.Node().IP(), d.localnode.Node().TCP()))
|
|
|
|
d.log.Info("Discovery V5: discoverable ENR ", logging.ENode("enr", d.localnode.Node()))
|
2021-11-23 14:24:05 +00:00
|
|
|
|
2021-11-17 16:19:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-17 00:04:12 +00:00
|
|
|
// Sets the host to be able to mount or consume a protocol
|
|
|
|
func (d *DiscoveryV5) SetHost(h host.Host) {
|
|
|
|
d.host = h
|
|
|
|
}
|
|
|
|
|
2023-05-04 05:39:51 +00:00
|
|
|
// only works if the discovery v5 hasn't been started yet.
|
2022-12-10 15:38:18 +00:00
|
|
|
func (d *DiscoveryV5) Start(ctx context.Context) error {
|
2023-05-04 05:39:51 +00:00
|
|
|
// compare and swap sets the discovery v5 to `started` state
|
|
|
|
// and prevents multiple calls to the start method by being atomic.
|
2023-05-04 10:02:00 +00:00
|
|
|
if !d.started.CompareAndSwap(false, true) {
|
2023-05-04 05:39:51 +00:00
|
|
|
return nil
|
|
|
|
}
|
2021-11-17 16:19:42 +00:00
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
d.cancel = cancel
|
2021-11-23 15:03:12 +00:00
|
|
|
|
2023-07-07 12:35:22 +00:00
|
|
|
d.peerCh = make(chan v2.PeerData)
|
|
|
|
d.peerConnector.Subscribe(ctx, d.peerCh)
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
err := d.listen(ctx)
|
2021-11-17 16:19:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-06-12 14:36:06 +00:00
|
|
|
if d.params.autoFindPeers {
|
|
|
|
d.wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer d.wg.Done()
|
|
|
|
d.runDiscoveryV5Loop(ctx)
|
|
|
|
}()
|
|
|
|
}
|
2022-11-29 17:39:34 +00:00
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-09 17:50:20 +00:00
|
|
|
func (d *DiscoveryV5) SetBootnodes(nodes []*enode.Node) error {
|
2023-02-07 22:27:22 +00:00
|
|
|
if d.listener == nil {
|
|
|
|
return ErrNoDiscV5Listener
|
|
|
|
}
|
|
|
|
|
2022-12-09 18:09:06 +00:00
|
|
|
return d.listener.SetFallbackNodes(nodes)
|
2022-12-09 17:50:20 +00:00
|
|
|
}
|
|
|
|
|
2023-05-04 05:39:51 +00:00
|
|
|
// only works if the discovery v5 is in running state
|
|
|
|
// so we can assume that cancel method is set
|
2021-11-16 14:22:01 +00:00
|
|
|
func (d *DiscoveryV5) Stop() {
|
2023-05-04 10:02:00 +00:00
|
|
|
if !d.started.CompareAndSwap(true, false) { // if Discoveryv5 is running, set started to false
|
2023-01-06 22:37:57 +00:00
|
|
|
return
|
|
|
|
}
|
2023-07-07 12:35:22 +00:00
|
|
|
|
2023-01-06 22:37:57 +00:00
|
|
|
d.cancel()
|
2021-11-23 14:24:05 +00:00
|
|
|
|
2023-01-04 18:46:22 +00:00
|
|
|
if d.listener != nil {
|
|
|
|
d.listener.Close()
|
|
|
|
d.listener = nil
|
|
|
|
d.log.Info("stopped Discovery V5")
|
|
|
|
}
|
2021-11-23 15:03:12 +00:00
|
|
|
|
|
|
|
d.wg.Wait()
|
2023-07-07 12:35:22 +00:00
|
|
|
|
|
|
|
close(d.peerCh)
|
2021-11-17 16:19:42 +00:00
|
|
|
}
|
|
|
|
|
2022-03-18 19:50:10 +00:00
|
|
|
/*
|
2021-11-16 14:22:01 +00:00
|
|
|
func isWakuNode(node *enode.Node) bool {
|
2021-12-03 13:40:51 +00:00
|
|
|
enrField := new(utils.WakuEnrBitfield)
|
|
|
|
if err := node.Record().Load(enr.WithEntry(utils.WakuENRField, &enrField)); err != nil {
|
2021-11-16 14:22:01 +00:00
|
|
|
if !enr.IsNotFound(err) {
|
2022-01-18 18:17:06 +00:00
|
|
|
utils.Logger().Named("discv5").Error("could not retrieve port for enr ", zap.Any("node", node))
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if enrField != nil {
|
|
|
|
return *enrField != uint8(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2022-03-18 19:50:10 +00:00
|
|
|
*/
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2021-12-10 15:29:50 +00:00
|
|
|
func evaluateNode(node *enode.Node) bool {
|
2023-01-13 23:58:22 +00:00
|
|
|
if node == nil {
|
2021-11-16 14:22:01 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-03-10 22:14:50 +00:00
|
|
|
// TODO: consider node filtering based on ENR; we do not filter based on ENR in the first waku discv5 beta stage
|
2023-01-13 23:58:22 +00:00
|
|
|
/*if !isWakuNode(node) {
|
2021-11-16 14:22:01 +00:00
|
|
|
return false
|
2023-01-13 23:58:22 +00:00
|
|
|
}*/
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2023-07-27 18:14:14 +00:00
|
|
|
_, err := wenr.EnodeToPeerInfo(node)
|
2021-11-17 16:19:42 +00:00
|
|
|
|
2021-11-16 14:22:01 +00:00
|
|
|
if err != nil {
|
2023-04-19 20:54:33 +00:00
|
|
|
metrics.RecordDiscV5Error(context.Background(), "peer_info_failure")
|
2022-05-30 15:55:30 +00:00
|
|
|
utils.Logger().Named("discv5").Error("obtaining peer info from enode", logging.ENode("enr", node), zap.Error(err))
|
2021-11-16 14:22:01 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-07-27 18:14:14 +00:00
|
|
|
// Predicate is a function that is applied to an iterator to filter the nodes to be retrieved according to some logic
|
|
|
|
type Predicate func(enode.Iterator) enode.Iterator
|
|
|
|
|
|
|
|
// PeerIterator gets random nodes from DHT via discv5 listener.
|
|
|
|
// Used for caching enr address in peerExchange
|
|
|
|
// Used for connecting to peers in discovery_connector
|
|
|
|
func (d *DiscoveryV5) PeerIterator(predicate ...Predicate) (enode.Iterator, error) {
|
2023-01-13 23:58:22 +00:00
|
|
|
if d.listener == nil {
|
2023-02-07 22:27:22 +00:00
|
|
|
return nil, ErrNoDiscV5Listener
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
|
2023-06-12 14:36:06 +00:00
|
|
|
iterator := enode.Filter(d.listener.RandomNodes(), evaluateNode)
|
|
|
|
if d.params.loopPredicate != nil {
|
2023-07-27 18:14:14 +00:00
|
|
|
iterator = enode.Filter(iterator, d.params.loopPredicate)
|
2023-01-13 23:58:22 +00:00
|
|
|
}
|
2021-11-23 15:03:12 +00:00
|
|
|
|
2023-07-27 18:14:14 +00:00
|
|
|
for _, p := range predicate {
|
|
|
|
iterator = p(iterator)
|
2023-06-12 14:36:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return iterator, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *DiscoveryV5) Iterate(ctx context.Context, iterator enode.Iterator, onNode func(*enode.Node, peer.AddrInfo) error) {
|
2023-05-04 05:39:51 +00:00
|
|
|
defer iterator.Close()
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2023-07-06 13:27:10 +00:00
|
|
|
peerCnt := 0
|
|
|
|
for {
|
2023-07-07 15:51:15 +00:00
|
|
|
|
|
|
|
if !delayedHasNext(ctx, iterator) {
|
|
|
|
return
|
2023-07-06 13:27:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
peerCnt++
|
2023-07-07 15:51:15 +00:00
|
|
|
if peerCnt == bucketSize { // Delay every bucketSize peers discovered
|
|
|
|
peerCnt = 0
|
|
|
|
t := time.NewTimer(delayBetweenDiscoveredPeerCnt)
|
2023-07-06 13:27:10 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return
|
|
|
|
case <-t.C:
|
|
|
|
t.Stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-27 18:14:14 +00:00
|
|
|
_, addresses, err := wenr.Multiaddress(iterator.Node())
|
2021-11-16 14:22:01 +00:00
|
|
|
if err != nil {
|
2023-04-19 20:54:33 +00:00
|
|
|
metrics.RecordDiscV5Error(context.Background(), "peer_info_failure")
|
2022-05-30 15:55:30 +00:00
|
|
|
d.log.Error("extracting multiaddrs from enr", zap.Error(err))
|
2021-11-16 14:22:01 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-03-08 12:58:32 +00:00
|
|
|
peerAddrs, err := peer.AddrInfosFromP2pAddrs(addresses...)
|
2021-11-16 14:22:01 +00:00
|
|
|
if err != nil {
|
2023-04-19 20:54:33 +00:00
|
|
|
metrics.RecordDiscV5Error(context.Background(), "peer_info_failure")
|
2022-05-30 15:55:30 +00:00
|
|
|
d.log.Error("converting multiaddrs to addrinfos", zap.Error(err))
|
2021-11-16 14:22:01 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-01-13 23:58:22 +00:00
|
|
|
if len(peerAddrs) != 0 {
|
2023-06-12 14:36:06 +00:00
|
|
|
err := onNode(iterator.Node(), peerAddrs[0])
|
|
|
|
if err != nil {
|
|
|
|
d.log.Error("processing node", zap.Error(err))
|
2023-05-09 21:25:58 +00:00
|
|
|
}
|
2023-05-04 05:39:51 +00:00
|
|
|
}
|
2023-05-09 21:25:58 +00:00
|
|
|
|
2023-05-04 05:39:51 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2023-06-12 14:36:06 +00:00
|
|
|
return
|
2023-05-04 05:39:51 +00:00
|
|
|
default:
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-12 14:36:06 +00:00
|
|
|
}
|
|
|
|
|
2023-07-07 15:51:15 +00:00
|
|
|
func delayedHasNext(ctx context.Context, iterator enode.Iterator) bool {
|
|
|
|
// Delay if .Next() is too fast
|
|
|
|
start := time.Now()
|
|
|
|
hasNext := iterator.Next()
|
|
|
|
if !hasNext {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
elapsed := time.Since(start)
|
|
|
|
if elapsed < peerDelay {
|
|
|
|
t := time.NewTimer(peerDelay - elapsed)
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return false
|
|
|
|
case <-t.C:
|
|
|
|
t.Stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-06-20 20:39:20 +00:00
|
|
|
// Iterates over the nodes found via discv5 belonging to the node's current shard, and sends them to peerConnector
|
2023-06-12 14:36:06 +00:00
|
|
|
func (d *DiscoveryV5) peerLoop(ctx context.Context) error {
|
2023-07-27 18:14:14 +00:00
|
|
|
iterator, err := d.PeerIterator(FilterPredicate(func(n *enode.Node) bool {
|
|
|
|
localRS, err := wenr.RelaySharding(d.localnode.Node().Record())
|
2023-06-22 20:36:24 +00:00
|
|
|
if err != nil {
|
2023-06-20 20:39:20 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-06-22 20:36:24 +00:00
|
|
|
if localRS == nil { // No shard registered, so no need to check for shards
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-07-27 18:14:14 +00:00
|
|
|
nodeRS, err := wenr.RelaySharding(n.Record())
|
2023-06-20 20:39:20 +00:00
|
|
|
if err != nil || nodeRS == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if nodeRS.Cluster != localRS.Cluster {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Contains any
|
2023-07-05 19:17:43 +00:00
|
|
|
for _, idx := range localRS.Indices {
|
2023-06-20 20:39:20 +00:00
|
|
|
if nodeRS.Contains(localRS.Cluster, idx) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
2023-07-27 18:14:14 +00:00
|
|
|
}))
|
|
|
|
if err != nil {
|
|
|
|
metrics.RecordDiscV5Error(context.Background(), "iterator_failure")
|
|
|
|
return fmt.Errorf("obtaining iterator: %w", err)
|
|
|
|
}
|
2023-06-20 20:39:20 +00:00
|
|
|
|
2023-06-12 14:36:06 +00:00
|
|
|
defer iterator.Close()
|
|
|
|
|
|
|
|
d.Iterate(ctx, iterator, func(n *enode.Node, p peer.AddrInfo) error {
|
|
|
|
peer := v2.PeerData{
|
|
|
|
Origin: peers.Discv5,
|
|
|
|
AddrInfo: p,
|
|
|
|
ENR: n,
|
|
|
|
}
|
|
|
|
|
|
|
|
select {
|
2023-07-07 12:35:22 +00:00
|
|
|
case d.peerCh <- peer:
|
2023-06-12 14:36:06 +00:00
|
|
|
case <-ctx.Done():
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
2023-01-27 17:36:52 +00:00
|
|
|
|
|
|
|
return nil
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
func (d *DiscoveryV5) runDiscoveryV5Loop(ctx context.Context) {
|
2021-11-16 14:22:01 +00:00
|
|
|
|
2023-01-13 23:58:22 +00:00
|
|
|
restartLoop:
|
|
|
|
for {
|
2023-06-12 14:36:06 +00:00
|
|
|
err := d.peerLoop(ctx)
|
2023-05-04 05:39:51 +00:00
|
|
|
if err != nil {
|
|
|
|
d.log.Debug("iterating discv5", zap.Error(err))
|
|
|
|
}
|
2023-05-08 16:29:18 +00:00
|
|
|
|
|
|
|
t := time.NewTimer(5 * time.Second)
|
2023-01-13 23:58:22 +00:00
|
|
|
select {
|
2023-05-08 16:29:18 +00:00
|
|
|
case <-t.C:
|
|
|
|
t.Stop()
|
2023-01-13 23:58:22 +00:00
|
|
|
case <-ctx.Done():
|
2023-05-08 16:29:18 +00:00
|
|
|
t.Stop()
|
2023-01-13 23:58:22 +00:00
|
|
|
break restartLoop
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
2023-01-13 23:58:22 +00:00
|
|
|
d.log.Warn("Discv5 loop stopped")
|
2021-11-16 14:22:01 +00:00
|
|
|
}
|
2022-10-23 13:13:43 +00:00
|
|
|
|
|
|
|
func (d *DiscoveryV5) IsStarted() bool {
|
2023-05-04 10:02:00 +00:00
|
|
|
return d.started.Load()
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|