2022-10-23 13:13:43 +00:00
|
|
|
package peer_exchange
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2023-01-27 17:36:52 +00:00
|
|
|
"fmt"
|
2022-10-23 13:13:43 +00:00
|
|
|
"math"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/libp2p/go-libp2p/core/host"
|
|
|
|
"github.com/libp2p/go-libp2p/core/network"
|
|
|
|
libp2pProtocol "github.com/libp2p/go-libp2p/core/protocol"
|
2023-02-06 22:16:20 +00:00
|
|
|
"github.com/libp2p/go-msgio/pbio"
|
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"
|
2022-11-09 19:53:01 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/discv5"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/metrics"
|
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol"
|
2023-04-20 18:51:13 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/enr"
|
2023-02-06 22:16:20 +00:00
|
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/peer_exchange/pb"
|
2022-10-23 13:13:43 +00:00
|
|
|
"go.uber.org/zap"
|
|
|
|
)
|
|
|
|
|
|
|
|
// PeerExchangeID_v20alpha1 is the current Waku Peer Exchange protocol identifier
|
|
|
|
const PeerExchangeID_v20alpha1 = libp2pProtocol.ID("/vac/waku/peer-exchange/2.0.0-alpha1")
|
|
|
|
const MaxCacheSize = 1000
|
|
|
|
|
|
|
|
var (
|
|
|
|
ErrNoPeersAvailable = errors.New("no suitable remote peers")
|
|
|
|
ErrInvalidId = errors.New("invalid request id")
|
|
|
|
)
|
|
|
|
|
2023-07-07 12:35:22 +00:00
|
|
|
type PeerConnector interface {
|
|
|
|
Subscribe(context.Context, <-chan v2.PeerData)
|
|
|
|
}
|
|
|
|
|
2022-10-23 13:13:43 +00:00
|
|
|
type WakuPeerExchange struct {
|
|
|
|
h host.Host
|
|
|
|
disc *discv5.DiscoveryV5
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
log *zap.Logger
|
|
|
|
|
2023-01-13 23:58:22 +00:00
|
|
|
cancel context.CancelFunc
|
|
|
|
|
2023-01-11 00:52:10 +00:00
|
|
|
wg sync.WaitGroup
|
2023-01-13 23:58:22 +00:00
|
|
|
peerConnector PeerConnector
|
2023-05-04 11:26:27 +00:00
|
|
|
enrCache *enrCache
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewWakuPeerExchange returns a new instance of WakuPeerExchange struct
|
2023-04-17 00:04:12 +00:00
|
|
|
func NewWakuPeerExchange(disc *discv5.DiscoveryV5, peerConnector PeerConnector, log *zap.Logger) (*WakuPeerExchange, error) {
|
2023-05-04 11:26:27 +00:00
|
|
|
newEnrCache, err := newEnrCache(MaxCacheSize)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-10-23 13:13:43 +00:00
|
|
|
wakuPX := new(WakuPeerExchange)
|
|
|
|
wakuPX.disc = disc
|
|
|
|
wakuPX.log = log.Named("wakupx")
|
2023-05-04 11:26:27 +00:00
|
|
|
wakuPX.enrCache = newEnrCache
|
2023-01-13 23:58:22 +00:00
|
|
|
wakuPX.peerConnector = peerConnector
|
2023-07-07 12:35:22 +00:00
|
|
|
|
2023-01-11 00:52:10 +00:00
|
|
|
return wakuPX, nil
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
|
2023-04-17 00:04:12 +00:00
|
|
|
// Sets the host to be able to mount or consume a protocol
|
|
|
|
func (wakuPX *WakuPeerExchange) SetHost(h host.Host) {
|
|
|
|
wakuPX.h = h
|
|
|
|
}
|
|
|
|
|
2022-10-23 13:13:43 +00:00
|
|
|
// Start inits the peer exchange protocol
|
2022-12-10 15:38:18 +00:00
|
|
|
func (wakuPX *WakuPeerExchange) Start(ctx context.Context) error {
|
2023-01-13 23:58:22 +00:00
|
|
|
if wakuPX.cancel != nil {
|
2023-01-06 22:37:57 +00:00
|
|
|
return errors.New("peer exchange already started")
|
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
wakuPX.wg.Wait() // Waiting for any go routines to stop
|
2023-01-06 22:37:57 +00:00
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
wakuPX.cancel = cancel
|
|
|
|
|
|
|
|
wakuPX.h.SetStreamHandlerMatch(PeerExchangeID_v20alpha1, protocol.PrefixTextMatch(string(PeerExchangeID_v20alpha1)), wakuPX.onRequest(ctx))
|
2022-10-23 13:13:43 +00:00
|
|
|
wakuPX.log.Info("Peer exchange protocol started")
|
|
|
|
|
|
|
|
wakuPX.wg.Add(1)
|
2022-12-10 15:38:18 +00:00
|
|
|
go wakuPX.runPeerExchangeDiscv5Loop(ctx)
|
2022-10-23 13:13:43 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
func (wakuPX *WakuPeerExchange) onRequest(ctx context.Context) func(s network.Stream) {
|
|
|
|
return func(s network.Stream) {
|
|
|
|
defer s.Close()
|
|
|
|
logger := wakuPX.log.With(logging.HostID("peer", s.Conn().RemotePeer()))
|
|
|
|
requestRPC := &pb.PeerExchangeRPC{}
|
2023-02-06 22:16:20 +00:00
|
|
|
reader := pbio.NewDelimitedReader(s, math.MaxInt32)
|
2022-12-10 15:38:18 +00:00
|
|
|
err := reader.ReadMsg(requestRPC)
|
2022-10-23 13:13:43 +00:00
|
|
|
if err != nil {
|
2022-12-10 15:38:18 +00:00
|
|
|
logger.Error("reading request", zap.Error(err))
|
|
|
|
metrics.RecordPeerExchangeError(ctx, "decodeRpcFailure")
|
2022-10-23 13:13:43 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
if requestRPC.Query != nil {
|
|
|
|
logger.Info("request received")
|
2023-02-28 18:02:47 +00:00
|
|
|
|
2023-05-04 11:26:27 +00:00
|
|
|
records, err := wakuPX.enrCache.getENRs(int(requestRPC.Query.NumPeers))
|
2022-12-10 15:38:18 +00:00
|
|
|
if err != nil {
|
2023-02-28 18:02:47 +00:00
|
|
|
logger.Error("obtaining enrs from cache", zap.Error(err))
|
2022-12-10 15:38:18 +00:00
|
|
|
metrics.RecordPeerExchangeError(ctx, "pxFailure")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-02-28 18:02:47 +00:00
|
|
|
responseRPC := &pb.PeerExchangeRPC{}
|
|
|
|
responseRPC.Response = new(pb.PeerExchangeResponse)
|
|
|
|
responseRPC.Response.PeerInfos = records
|
|
|
|
|
|
|
|
writer := pbio.NewDelimitedWriter(s)
|
|
|
|
err = writer.WriteMsg(responseRPC)
|
2022-12-10 15:38:18 +00:00
|
|
|
if err != nil {
|
2023-02-28 18:02:47 +00:00
|
|
|
logger.Error("writing response", zap.Error(err))
|
2022-12-10 15:38:18 +00:00
|
|
|
metrics.RecordPeerExchangeError(ctx, "pxFailure")
|
|
|
|
return
|
|
|
|
}
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop unmounts the peer exchange protocol
|
|
|
|
func (wakuPX *WakuPeerExchange) Stop() {
|
2023-01-06 22:37:57 +00:00
|
|
|
if wakuPX.cancel == nil {
|
|
|
|
return
|
|
|
|
}
|
2022-12-10 15:38:18 +00:00
|
|
|
wakuPX.h.RemoveStreamHandler(PeerExchangeID_v20alpha1)
|
2023-01-13 23:58:22 +00:00
|
|
|
wakuPX.cancel()
|
2022-12-10 15:38:18 +00:00
|
|
|
wakuPX.wg.Wait()
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 17:36:52 +00:00
|
|
|
func (wakuPX *WakuPeerExchange) iterate(ctx context.Context) error {
|
2023-01-13 23:58:22 +00:00
|
|
|
iterator, err := wakuPX.disc.Iterator()
|
2022-10-23 13:13:43 +00:00
|
|
|
if err != nil {
|
2023-01-27 17:36:52 +00:00
|
|
|
return fmt.Errorf("obtaining iterator: %w", err)
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
2023-05-04 11:26:27 +00:00
|
|
|
// Closing iterator
|
|
|
|
defer iterator.Close()
|
2023-01-31 14:45:19 +00:00
|
|
|
|
2023-05-04 11:26:27 +00:00
|
|
|
for iterator.Next() {
|
2023-04-20 18:51:13 +00:00
|
|
|
_, addresses, err := enr.Multiaddress(iterator.Node())
|
2023-01-13 23:58:22 +00:00
|
|
|
if err != nil {
|
|
|
|
wakuPX.log.Error("extracting multiaddrs from enr", zap.Error(err))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(addresses) == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-03-31 12:44:01 +00:00
|
|
|
wakuPX.log.Debug("Discovered px peers via discv5")
|
2023-05-04 11:26:27 +00:00
|
|
|
wakuPX.enrCache.updateCache(iterator.Node())
|
2023-03-31 12:44:01 +00:00
|
|
|
|
2023-05-04 11:26:27 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return nil
|
|
|
|
default:
|
2023-01-13 23:58:22 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-27 17:36:52 +00:00
|
|
|
return nil
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
|
2022-12-10 15:38:18 +00:00
|
|
|
func (wakuPX *WakuPeerExchange) runPeerExchangeDiscv5Loop(ctx context.Context) {
|
2022-10-23 13:13:43 +00:00
|
|
|
defer wakuPX.wg.Done()
|
|
|
|
|
|
|
|
// Runs a discv5 loop adding new peers to the px peer cache
|
|
|
|
if wakuPX.disc == nil {
|
|
|
|
wakuPX.log.Warn("trying to run discovery v5 (for PX) while it's disabled")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
2023-05-04 11:26:27 +00:00
|
|
|
err := wakuPX.iterate(ctx)
|
|
|
|
if err != nil {
|
|
|
|
wakuPX.log.Debug("iterating peer exchange", zap.Error(err))
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
}
|
2022-10-23 13:13:43 +00:00
|
|
|
select {
|
2023-01-13 23:58:22 +00:00
|
|
|
case <-ctx.Done():
|
2023-05-04 11:26:27 +00:00
|
|
|
return
|
|
|
|
default:
|
2022-10-23 13:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|