feat: supporting peer exchange with nwaku (#5983)
This commit is contained in:
parent
ed5a9aa46f
commit
8c4c876de6
|
@ -1 +1 @@
|
||||||
Subproject commit c5a825e206c1cb3e6e0cf8c01410527804cb76c4
|
Subproject commit de11e576f4b69b63b4135cfb9549ef15cdc1ad34
|
|
@ -208,6 +208,10 @@ package wakuv2
|
||||||
WAKU_CALL (waku_get_my_enr(ctx, (WakuCallBack) callback, resp) );
|
WAKU_CALL (waku_get_my_enr(ctx, (WakuCallBack) callback, resp) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cGoWakuGetMyPeerId(void* ctx, void* resp) {
|
||||||
|
WAKU_CALL (waku_get_my_peerid(ctx, (WakuCallBack) callback, resp) );
|
||||||
|
}
|
||||||
|
|
||||||
static void cGoWakuListPeersInMesh(void* ctx, char* pubSubTopic, void* resp) {
|
static void cGoWakuListPeersInMesh(void* ctx, char* pubSubTopic, void* resp) {
|
||||||
WAKU_CALL (waku_relay_get_num_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) callback, resp) );
|
WAKU_CALL (waku_relay_get_num_peers_in_mesh(ctx, pubSubTopic, (WakuCallBack) callback, resp) );
|
||||||
}
|
}
|
||||||
|
@ -216,6 +220,10 @@ package wakuv2
|
||||||
WAKU_CALL (waku_relay_get_num_connected_peers(ctx, pubSubTopic, (WakuCallBack) callback, resp) );
|
WAKU_CALL (waku_relay_get_num_connected_peers(ctx, pubSubTopic, (WakuCallBack) callback, resp) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cGoWakuGetPeerIdsFromPeerStore(void* wakuCtx, void* resp) {
|
||||||
|
WAKU_CALL (waku_get_peerids_from_peerstore(wakuCtx, (WakuCallBack) callback, resp) );
|
||||||
|
}
|
||||||
|
|
||||||
static void cGoWakuLightpushPublish(void* wakuCtx,
|
static void cGoWakuLightpushPublish(void* wakuCtx,
|
||||||
const char* pubSubTopic,
|
const char* pubSubTopic,
|
||||||
const char* jsonWakuMessage,
|
const char* jsonWakuMessage,
|
||||||
|
@ -380,8 +388,12 @@ type WakuConfig struct {
|
||||||
Staticnodes []string `json:"staticnodes,omitempty"`
|
Staticnodes []string `json:"staticnodes,omitempty"`
|
||||||
Discv5BootstrapNodes []string `json:"discv5BootstrapNodes,omitempty"`
|
Discv5BootstrapNodes []string `json:"discv5BootstrapNodes,omitempty"`
|
||||||
Discv5Discovery bool `json:"discv5Discovery,omitempty"`
|
Discv5Discovery bool `json:"discv5Discovery,omitempty"`
|
||||||
|
Discv5UdpPort uint16 `json:"discv5UdpPort,omitempty"`
|
||||||
ClusterID uint16 `json:"clusterId,omitempty"`
|
ClusterID uint16 `json:"clusterId,omitempty"`
|
||||||
Shards []uint16 `json:"shards,omitempty"`
|
Shards []uint16 `json:"shards,omitempty"`
|
||||||
|
PeerExchange bool `json:"peerExchange,omitempty"`
|
||||||
|
PeerExchangeNode string `json:"peerExchangeNode,omitempty"`
|
||||||
|
TcpPort uint16 `json:"tcpPort,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waku represents a dark communication interface through the Ethereum
|
// Waku represents a dark communication interface through the Ethereum
|
||||||
|
@ -497,9 +509,11 @@ func New(nodeKey *ecdsa.PrivateKey, fleet string, cfg *Config, nwakuCfg *WakuCon
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = node.WakuRelaySubscribe(defaultPubsubTopic)
|
if nwakuCfg.EnableRelay {
|
||||||
if err != nil {
|
err = node.WakuRelaySubscribe(defaultPubsubTopic)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node.WakuSetEventCallback()
|
node.WakuSetEventCallback()
|
||||||
|
@ -2191,10 +2205,23 @@ func (w *Waku) Clean() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO-nwaku
|
func (w *Waku) PeerID() (peer.ID, error) {
|
||||||
func (w *Waku) PeerID() peer.ID {
|
var resp = C.allocResp()
|
||||||
// return w.node.Host().ID()
|
defer C.freeResp(resp)
|
||||||
return ""
|
C.cGoWakuGetMyPeerId(w.wakuCtx, resp)
|
||||||
|
|
||||||
|
if C.getRet(resp) == C.RET_OK {
|
||||||
|
|
||||||
|
peerIdStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
|
id, err := peer.Decode(peerIdStr)
|
||||||
|
if err != nil {
|
||||||
|
errMsg := "WakuGetMyPeerId - decoding peerId: %w"
|
||||||
|
return "", fmt.Errorf(errMsg, err)
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
errMsg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
|
return "", fmt.Errorf("WakuGetMyPeerId: %s", errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatePrivateKey checks the format of the given private key.
|
// validatePrivateKey checks the format of the given private key.
|
||||||
|
@ -2609,18 +2636,21 @@ func wakuStoreQuery(
|
||||||
return "", errors.New(errMsg)
|
return "", errors.New(errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Waku) WakuPeerExchangeRequest(numPeers uint64) (string, error) {
|
func (self *Waku) WakuPeerExchangeRequest(numPeers uint64) (uint64, error) {
|
||||||
var resp = C.allocResp()
|
var resp = C.allocResp()
|
||||||
defer C.freeResp(resp)
|
defer C.freeResp(resp)
|
||||||
|
|
||||||
C.cGoWakuPeerExchangeQuery(self.wakuCtx, C.uint64_t(numPeers), resp)
|
C.cGoWakuPeerExchangeQuery(self.wakuCtx, C.uint64_t(numPeers), resp)
|
||||||
if C.getRet(resp) == C.RET_OK {
|
if C.getRet(resp) == C.RET_OK {
|
||||||
msg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
numRecvPeersStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
return msg, nil
|
numRecvPeers, err := strconv.ParseUint(numRecvPeersStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return numRecvPeers, nil
|
||||||
}
|
}
|
||||||
errMsg := "error WakuPeerExchangeRequest: " +
|
errMsg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
return 0, fmt.Errorf("WakuPeerExchangeRequest: %s", errMsg)
|
||||||
return "", errors.New(errMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Waku) WakuConnect(peerMultiAddr string, timeoutMs int) error {
|
func (self *Waku) WakuConnect(peerMultiAddr string, timeoutMs int) error {
|
||||||
|
@ -2753,6 +2783,34 @@ func (self *Waku) GetNumConnectedPeers(paramPubsubTopic ...string) (int, error)
|
||||||
return 0, errors.New(errMsg)
|
return 0, errors.New(errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *Waku) GetPeerIdsFromPeerStore() (peer.IDSlice, error) {
|
||||||
|
var resp = C.allocResp()
|
||||||
|
defer C.freeResp(resp)
|
||||||
|
C.cGoWakuGetPeerIdsFromPeerStore(self.wakuCtx, resp)
|
||||||
|
|
||||||
|
if C.getRet(resp) == C.RET_OK {
|
||||||
|
peersStr := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
|
if peersStr == "" {
|
||||||
|
return peer.IDSlice{}, nil
|
||||||
|
}
|
||||||
|
// peersStr contains a comma-separated list of peer ids
|
||||||
|
itemsPeerIds := strings.Split(peersStr, ",")
|
||||||
|
|
||||||
|
var peers peer.IDSlice
|
||||||
|
for _, peerId := range itemsPeerIds {
|
||||||
|
id, err := peer.Decode(peerId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("GetPeerIdsFromPeerStore - decoding peerId: %w", err)
|
||||||
|
}
|
||||||
|
peers = append(peers, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return peers, nil
|
||||||
|
}
|
||||||
|
errMsg := C.GoStringN(C.getMyCharPtr(resp), C.int(C.getMyCharLen(resp)))
|
||||||
|
return nil, fmt.Errorf("GetPeerIdsFromPeerStore: %s", errMsg)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *Waku) GetPeerIdsByProtocol(protocol string) (peer.IDSlice, error) {
|
func (self *Waku) GetPeerIdsByProtocol(protocol string) (peer.IDSlice, error) {
|
||||||
var resp = C.allocResp()
|
var resp = C.allocResp()
|
||||||
var cProtocol = C.CString(protocol)
|
var cProtocol = C.CString(protocol)
|
||||||
|
@ -2773,8 +2831,7 @@ func (self *Waku) GetPeerIdsByProtocol(protocol string) (peer.IDSlice, error) {
|
||||||
for _, p := range itemsPeerIds {
|
for _, p := range itemsPeerIds {
|
||||||
id, err := peer.Decode(p)
|
id, err := peer.Decode(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errMsg := "GetPeerIdsByProtocol - error converting string to int: " + err.Error()
|
return nil, fmt.Errorf("GetPeerIdsByProtocol - decoding peerId: %w", err)
|
||||||
return nil, errors.New(errMsg)
|
|
||||||
}
|
}
|
||||||
peers = append(peers, id)
|
peers = append(peers, id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"github.com/cenkalti/backoff/v3"
|
"github.com/cenkalti/backoff/v3"
|
||||||
"github.com/libp2p/go-libp2p/core/peer"
|
"github.com/libp2p/go-libp2p/core/peer"
|
||||||
"github.com/waku-org/go-waku/waku/v2/protocol/store"
|
"github.com/waku-org/go-waku/waku/v2/protocol/store"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
@ -155,7 +156,7 @@ func parseNodes(rec []string) []*enode.Node {
|
||||||
// IP_ADDRESS=$(hostname -I | awk '{print $1}');
|
// IP_ADDRESS=$(hostname -I | awk '{print $1}');
|
||||||
// docker run \
|
// docker run \
|
||||||
// -p 61000:61000/tcp -p 8000:8000/udp -p 8646:8646/tcp harbor.status.im/wakuorg/nwaku:v0.33.0 \
|
// -p 61000:61000/tcp -p 8000:8000/udp -p 8646:8646/tcp harbor.status.im/wakuorg/nwaku:v0.33.0 \
|
||||||
// --discv5-discovery=true --cluster-id=16 --log-level=DEBUG \
|
// --discv5-discovery=true --cluster-id=16 --log-level=DEBUG --shard=64 --tcp-port=61000 \
|
||||||
// --nat=extip:${IP_ADDRESS} --discv5-udp-port=8000 --rest-address=0.0.0.0 --store --rest-port=8646 \
|
// --nat=extip:${IP_ADDRESS} --discv5-udp-port=8000 --rest-address=0.0.0.0 --store --rest-port=8646 \
|
||||||
|
|
||||||
func TestBasicWakuV2(t *testing.T) {
|
func TestBasicWakuV2(t *testing.T) {
|
||||||
|
@ -195,7 +196,6 @@ func TestBasicWakuV2(t *testing.T) {
|
||||||
|
|
||||||
// Sanity check, not great, but it's probably helpful
|
// Sanity check, not great, but it's probably helpful
|
||||||
err = tt.RetryWithBackOff(func() error {
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
|
||||||
numConnected, err := w.GetNumConnectedPeers()
|
numConnected, err := w.GetNumConnectedPeers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -323,10 +323,151 @@ func makeTestTree(domain string, nodes []*enode.Node, links []string) (*ethdnsdi
|
||||||
return tree, url
|
return tree, url
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func TestPeerExchange(t *testing.T) {
|
func TestPeerExchange(t *testing.T) {
|
||||||
logger, err := zap.NewDevelopment()
|
logger, err := zap.NewDevelopment()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
discV5NodeConfig := Config{
|
||||||
|
UseThrottledPublish: true,
|
||||||
|
ClusterID: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// start node that will be discovered by PeerExchange
|
||||||
|
discV5NodeWakuConfig := WakuConfig{
|
||||||
|
EnableRelay: true,
|
||||||
|
LogLevel: "DEBUG",
|
||||||
|
Discv5Discovery: true,
|
||||||
|
ClusterID: 16,
|
||||||
|
Shards: []uint16{64},
|
||||||
|
PeerExchange: false,
|
||||||
|
Discv5UdpPort: 9001,
|
||||||
|
TcpPort: 60010,
|
||||||
|
}
|
||||||
|
|
||||||
|
discV5Node, err := New(nil, "", &discV5NodeConfig, &discV5NodeWakuConfig, logger.Named("discV5Node"), nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, discV5Node.Start())
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
discV5NodePeerId, err := discV5Node.PeerID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
discv5NodeEnr, err := discV5Node.ENR()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
pxServerConfig := Config{
|
||||||
|
UseThrottledPublish: true,
|
||||||
|
ClusterID: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// start node which serves as PeerExchange server
|
||||||
|
pxServerWakuConfig := WakuConfig{
|
||||||
|
EnableRelay: true,
|
||||||
|
LogLevel: "DEBUG",
|
||||||
|
Discv5Discovery: true,
|
||||||
|
ClusterID: 16,
|
||||||
|
Shards: []uint16{64},
|
||||||
|
PeerExchange: true,
|
||||||
|
Discv5UdpPort: 9000,
|
||||||
|
Discv5BootstrapNodes: []string{discv5NodeEnr.String()},
|
||||||
|
TcpPort: 60011,
|
||||||
|
}
|
||||||
|
|
||||||
|
pxServerNode, err := New(nil, "", &pxServerConfig, &pxServerWakuConfig, logger.Named("pxServerNode"), nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, pxServerNode.Start())
|
||||||
|
|
||||||
|
// Adding an extra second to make sure PX cache is not empty
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
serverNodeMa, err := pxServerNode.ListenAddresses()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, serverNodeMa)
|
||||||
|
|
||||||
|
// Sanity check, not great, but it's probably helpful
|
||||||
|
options := func(b *backoff.ExponentialBackOff) {
|
||||||
|
b.MaxElapsedTime = 30 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that pxServerNode has discV5Node in its Peer Store
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
peers, err := pxServerNode.GetPeerIdsFromPeerStore()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(peers, discV5NodePeerId) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("pxServer is missing the discv5 node in its peer store")
|
||||||
|
}, options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
pxClientConfig := Config{
|
||||||
|
UseThrottledPublish: true,
|
||||||
|
ClusterID: 16,
|
||||||
|
}
|
||||||
|
|
||||||
|
// start light node which uses PeerExchange to discover peers
|
||||||
|
pxClientWakuConfig := WakuConfig{
|
||||||
|
EnableRelay: false,
|
||||||
|
LogLevel: "DEBUG",
|
||||||
|
Discv5Discovery: false,
|
||||||
|
ClusterID: 16,
|
||||||
|
Shards: []uint16{64},
|
||||||
|
PeerExchange: true,
|
||||||
|
Discv5UdpPort: 9002,
|
||||||
|
TcpPort: 60012,
|
||||||
|
PeerExchangeNode: serverNodeMa[0].String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
lightNode, err := New(nil, "", &pxClientConfig, &pxClientWakuConfig, logger.Named("lightNode"), nil, nil, nil, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, lightNode.Start())
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
pxServerPeerId, err := pxServerNode.PeerID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check that the light node discovered the discV5Node and has both nodes in its peer store
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
peers, err := lightNode.GetPeerIdsFromPeerStore()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Contains(peers, discV5NodePeerId) && slices.Contains(peers, pxServerPeerId) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("lightnode is missing peers")
|
||||||
|
}, options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Now perform the PX request manually to see if it also works
|
||||||
|
err = tt.RetryWithBackOff(func() error {
|
||||||
|
numPeersReceived, err := lightNode.WakuPeerExchangeRequest(1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if numPeersReceived == 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("Peer Exchange is not returning peers")
|
||||||
|
}, options)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Stop nodes
|
||||||
|
require.NoError(t, lightNode.Stop())
|
||||||
|
require.NoError(t, pxServerNode.Stop())
|
||||||
|
require.NoError(t, discV5Node.Stop())
|
||||||
|
|
||||||
|
/* logger, err := zap.NewDevelopment()
|
||||||
|
require.NoError(t, err)
|
||||||
// start node which serve as PeerExchange server
|
// start node which serve as PeerExchange server
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
config.ClusterID = 16
|
config.ClusterID = 16
|
||||||
|
@ -401,9 +542,11 @@ func TestPeerExchange(t *testing.T) {
|
||||||
|
|
||||||
require.NoError(t, lightNode.Stop())
|
require.NoError(t, lightNode.Stop())
|
||||||
require.NoError(t, pxServerNode.Stop())
|
require.NoError(t, pxServerNode.Stop())
|
||||||
require.NoError(t, discV5Node.Stop())
|
require.NoError(t, discV5Node.Stop()) */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
func TestWakuV2Filter(t *testing.T) {
|
func TestWakuV2Filter(t *testing.T) {
|
||||||
t.Skip("flaky test")
|
t.Skip("flaky test")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue