fix: wakuflag for ListenAddresses ENR (#171)

Also, reorganize code in utils package
This commit is contained in:
Richard Ramos 2021-12-03 09:40:51 -04:00 committed by GitHub
parent 23cbb24a94
commit ed91f47ff0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 145 deletions

View File

@ -61,11 +61,6 @@ type discV5Parameters struct {
advertiseAddr *net.IP
}
const WakuENRField = "waku2"
// WakuEnrBitfield is a8-bit flag field to indicate Waku capabilities. Only the 4 LSBs are currently defined according to RFC31 (https://rfc.vac.dev/spec/31/).
type WakuEnrBitfield = uint8
type DiscoveryV5Option func(*discV5Parameters)
func WithAutoUpdate(autoUpdate bool) DiscoveryV5Option {
@ -98,29 +93,7 @@ func DefaultOptions() []DiscoveryV5Option {
}
}
func NewWakuEnrBitfield(lightpush, filter, store, relay bool) WakuEnrBitfield {
var v uint8 = 0
if lightpush {
v |= (1 << 3)
}
if filter {
v |= (1 << 2)
}
if store {
v |= (1 << 1)
}
if relay {
v |= (1 << 0)
}
return v
}
func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.PrivateKey, wakuFlags WakuEnrBitfield, opts ...DiscoveryV5Option) (*DiscoveryV5, error) {
func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.PrivateKey, wakuFlags utils.WakuEnrBitfield, opts ...DiscoveryV5Option) (*DiscoveryV5, error) {
params := new(discV5Parameters)
optList := DefaultOptions()
optList = append(optList, opts...)
@ -161,7 +134,7 @@ func NewDiscoveryV5(host host.Host, ipAddr net.IP, tcpPort int, priv *ecdsa.Priv
}, nil
}
func newLocalnode(priv *ecdsa.PrivateKey, ipAddr net.IP, udpPort int, tcpPort int, wakuFlags WakuEnrBitfield, advertiseAddr *net.IP) (*enode.LocalNode, error) {
func newLocalnode(priv *ecdsa.PrivateKey, ipAddr net.IP, udpPort int, tcpPort int, wakuFlags utils.WakuEnrBitfield, advertiseAddr *net.IP) (*enode.LocalNode, error) {
db, err := enode.OpenDB("")
if err != nil {
return nil, err
@ -169,7 +142,7 @@ func newLocalnode(priv *ecdsa.PrivateKey, ipAddr net.IP, udpPort int, tcpPort in
localnode := enode.NewLocalNode(db, priv)
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
localnode.SetFallbackUDP(udpPort)
localnode.Set(enr.WithEntry(WakuENRField, wakuFlags))
localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags))
localnode.Set(enr.IP(ipAddr))
if udpPort > 0 && udpPort <= math.MaxUint16 {
@ -303,8 +276,8 @@ func (d *DiscoveryV5) UpdateAddr(addr net.IP) error {
}
func isWakuNode(node *enode.Node) bool {
enrField := new(WakuEnrBitfield)
if err := node.Record().Load(enr.WithEntry(WakuENRField, &enrField)); err != nil {
enrField := new(utils.WakuEnrBitfield)
if err := node.Record().Load(enr.WithEntry(utils.WakuENRField, &enrField)); err != nil {
if !enr.IsNotFound(err) {
log.Error("could not retrieve port for enr ", node)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/multiformats/go-multiaddr"
"github.com/status-im/go-waku/tests"
"github.com/status-im/go-waku/waku/v2/utils"
"github.com/stretchr/testify/require"
"github.com/libp2p/go-libp2p"
@ -48,19 +49,19 @@ func TestDiscV5(t *testing.T) {
host1, tcpPort1, prvKey1 := createHost(t)
udpPort1, err := tests.FindFreePort(t, "127.0.0.1", 3)
require.NoError(t, err)
d1, err := NewDiscoveryV5(host1, net.IPv4(127, 0, 0, 1), tcpPort1, prvKey1, NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort1))
d1, err := NewDiscoveryV5(host1, net.IPv4(127, 0, 0, 1), tcpPort1, prvKey1, utils.NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort1))
require.NoError(t, err)
host2, tcpPort2, prvKey2 := createHost(t)
udpPort2, err := tests.FindFreePort(t, "127.0.0.1", 3)
require.NoError(t, err)
d2, err := NewDiscoveryV5(host2, net.IPv4(127, 0, 0, 1), tcpPort2, prvKey2, NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort2), WithBootnodes([]*enode.Node{d1.localnode.Node()}))
d2, err := NewDiscoveryV5(host2, net.IPv4(127, 0, 0, 1), tcpPort2, prvKey2, utils.NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort2), WithBootnodes([]*enode.Node{d1.localnode.Node()}))
require.NoError(t, err)
host3, tcpPort3, prvKey3 := createHost(t)
udpPort3, err := tests.FindFreePort(t, "127.0.0.1", 3)
require.NoError(t, err)
d3, err := NewDiscoveryV5(host3, net.IPv4(127, 0, 0, 1), tcpPort3, prvKey3, NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort3), WithBootnodes([]*enode.Node{d2.localnode.Node()}))
d3, err := NewDiscoveryV5(host3, net.IPv4(127, 0, 0, 1), tcpPort3, prvKey3, utils.NewWakuEnrBitfield(true, true, true, true), WithUDPPort(udpPort3), WithBootnodes([]*enode.Node{d2.localnode.Node()}))
require.NoError(t, err)
defer d1.Stop()

View File

@ -55,6 +55,7 @@ type WakuNode struct {
lightPush *lightpush.WakuLightPush
rendezvous *rendezvous.RendezvousService
store *store.WakuStore
wakuFlag utils.WakuEnrBitfield
addrChan chan ma.Multiaddr
@ -132,6 +133,7 @@ func New(ctx context.Context, opts ...WakuNodeOption) (*WakuNode, error) {
w.wg = &sync.WaitGroup{}
w.addrChan = make(chan ma.Multiaddr, 1024)
w.keepAliveFails = make(map[peer.ID]int)
w.wakuFlag = utils.NewWakuEnrBitfield(w.opts.enableLightPush, w.opts.enableFilter, w.opts.enableStore, w.opts.enableRelay)
if w.protocolEventSub, err = host.EventBus().Subscribe(new(event.EvtPeerProtocolsUpdated)); err != nil {
return nil, err
@ -190,7 +192,7 @@ func (w *WakuNode) logAddress(addr ma.Multiaddr) {
// TODO: make this optional depending on DNS Disc being enabled
if w.opts.privKey != nil {
enr, ip, err := utils.GetENRandIP(addr, w.opts.privKey)
enr, ip, err := utils.GetENRandIP(addr, w.wakuFlag, w.opts.privKey)
if err != nil {
log.Error("could not obtain ENR record from multiaddress", err)
} else {
@ -388,8 +390,6 @@ func (w *WakuNode) mountRelay(opts ...pubsub.Option) error {
}
func (w *WakuNode) mountDiscV5() error {
wakuFlag := discv5.NewWakuEnrBitfield(w.opts.enableLightPush, w.opts.enableFilter, w.opts.enableStore, w.opts.enableRelay)
discV5Options := []discv5.DiscoveryV5Option{
discv5.WithBootnodes(w.opts.discV5bootnodes),
discv5.WithUDPPort(w.opts.udpPort),
@ -413,7 +413,7 @@ func (w *WakuNode) mountDiscV5() error {
return err
}
discoveryV5, err := discv5.NewDiscoveryV5(w.Host(), net.ParseIP(ipStr), port, w.opts.privKey, wakuFlag, discV5Options...)
discoveryV5, err := discv5.NewDiscoveryV5(w.Host(), net.ParseIP(ipStr), port, w.opts.privKey, w.wakuFlag, discV5Options...)
if err != nil {
return err
}

101
waku/v2/utils/enr.go Normal file
View File

@ -0,0 +1,101 @@
package utils
import (
"crypto/ecdsa"
"fmt"
"math"
"net"
"strconv"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
)
const WakuENRField = "waku2"
// WakuEnrBitfield is a8-bit flag field to indicate Waku capabilities. Only the 4 LSBs are currently defined according to RFC31 (https://rfc.vac.dev/spec/31/).
type WakuEnrBitfield = uint8
func NewWakuEnrBitfield(lightpush, filter, store, relay bool) WakuEnrBitfield {
var v uint8 = 0
if lightpush {
v |= (1 << 3)
}
if filter {
v |= (1 << 2)
}
if store {
v |= (1 << 1)
}
if relay {
v |= (1 << 0)
}
return v
}
func GetENRandIP(addr ma.Multiaddr, wakuFlags WakuEnrBitfield, privK *ecdsa.PrivateKey) (*enode.Node, *net.TCPAddr, error) {
ip, err := addr.ValueForProtocol(ma.P_IP4)
if err != nil {
return nil, nil, err
}
portStr, err := addr.ValueForProtocol(ma.P_TCP)
if err != nil {
return nil, nil, err
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, nil, err
}
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", ip, port))
if err != nil {
return nil, nil, err
}
r := &enr.Record{}
if port > 0 && port <= math.MaxUint16 {
r.Set(enr.TCP(uint16(port))) // lgtm [go/incorrect-integer-conversion]
} else {
return nil, nil, fmt.Errorf("could not set port %d", port)
}
r.Set(enr.IP(net.ParseIP(ip)))
r.Set(enr.WithEntry(WakuENRField, wakuFlags))
err = enode.SignV4(r, privK)
if err != nil {
return nil, nil, err
}
node, err := enode.New(enode.ValidSchemes, r)
return node, tcpAddr, err
}
func EnodeToMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
peerID, err := peer.IDFromPublicKey(&ECDSAPublicKey{node.Pubkey()})
if err != nil {
return nil, err
}
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", node.IP(), node.TCP(), peerID))
}
func EnodeToPeerInfo(node *enode.Node) (*peer.AddrInfo, error) {
address, err := EnodeToMultiAddr(node)
if err != nil {
return nil, err
}
return peer.AddrInfoFromP2pAddr(address)
}

47
waku/v2/utils/enr_test.go Normal file
View File

@ -0,0 +1,47 @@
package utils
import (
"fmt"
"net"
"testing"
gcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
crypto "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/stretchr/testify/require"
)
func TestEnodeToMultiAddr(t *testing.T) {
enr := "enr:-IS4QAmC_o1PMi5DbR4Bh4oHVyQunZblg4bTaottPtBodAhJZvxVlWW-4rXITPNg4mwJ8cW__D9FBDc9N4mdhyMqB-EBgmlkgnY0gmlwhIbRi9KJc2VjcDI1NmsxoQOevTdO6jvv3fRruxguKR-3Ge4bcFsLeAIWEDjrfaigNoN0Y3CCdl8"
parsedNode := enode.MustParse(enr)
expectedMultiAddr := "/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ"
actualMultiAddr, err := EnodeToMultiAddr(parsedNode)
require.NoError(t, err)
require.Equal(t, expectedMultiAddr, actualMultiAddr.String())
}
func TestGetENRandIP(t *testing.T) {
key, _ := gcrypto.GenerateKey()
privKey := crypto.PrivKey((*crypto.Secp256k1PrivateKey)(key))
id, _ := peer.IDFromPublicKey(privKey.GetPublic())
hostAddr := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 9999}
hostMultiAddr, _ := manet.FromNetAddr(hostAddr)
hostInfo, _ := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", id.Pretty()))
ogMultiaddress := hostMultiAddr.Encapsulate(hostInfo)
wakuFlag := NewWakuEnrBitfield(true, true, true, true)
node, resTCPAddr, err := GetENRandIP(ogMultiaddress, wakuFlag, key)
require.NoError(t, err)
require.Equal(t, hostAddr, resTCPAddr)
parsedNode := enode.MustParse(node.String())
resMultiaddress, err := EnodeToMultiAddr(parsedNode)
require.NoError(t, err)
require.Equal(t, ogMultiaddress.String(), resMultiaddress.String())
}

View File

@ -2,20 +2,11 @@ package utils
import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"math"
"math/rand"
"net"
"strconv"
"sync"
"time"
ma "github.com/multiformats/go-multiaddr"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
@ -122,62 +113,3 @@ func SelectPeerWithLowestRTT(ctx context.Context, host host.Host, protocolId str
return nil, ErrNoPeersAvailable
}
}
func EnodeToMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
peerID, err := peer.IDFromPublicKey(&ECDSAPublicKey{node.Pubkey()})
if err != nil {
return nil, err
}
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", node.IP(), node.TCP(), peerID))
}
func EnodeToPeerInfo(node *enode.Node) (*peer.AddrInfo, error) {
address, err := EnodeToMultiAddr(node)
if err != nil {
return nil, err
}
return peer.AddrInfoFromP2pAddr(address)
}
func GetENRandIP(addr ma.Multiaddr, privK *ecdsa.PrivateKey) (*enode.Node, *net.TCPAddr, error) {
ip, err := addr.ValueForProtocol(ma.P_IP4)
if err != nil {
return nil, nil, err
}
portStr, err := addr.ValueForProtocol(ma.P_TCP)
if err != nil {
return nil, nil, err
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, nil, err
}
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", ip, port))
if err != nil {
return nil, nil, err
}
r := &enr.Record{}
if port > 0 && port <= math.MaxUint16 {
r.Set(enr.TCP(uint16(port))) // lgtm [go/incorrect-integer-conversion]
} else {
return nil, nil, fmt.Errorf("could not set port %d", port)
}
r.Set(enr.IP(net.ParseIP(ip)))
err = enode.SignV4(r, privK)
if err != nil {
return nil, nil, err
}
node, err := enode.New(enode.ValidSchemes, r)
return node, tcpAddr, err
}

View File

@ -3,18 +3,10 @@ package utils
import (
"context"
"crypto/rand"
"fmt"
"net"
"testing"
"time"
gcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
crypto "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/peerstore"
ma "github.com/multiformats/go-multiaddr"
manet "github.com/multiformats/go-multiaddr/net"
"github.com/status-im/go-waku/tests"
"github.com/stretchr/testify/require"
)
@ -87,33 +79,3 @@ func TestSelectPeerWithLowestRTT(t *testing.T) {
_, err = SelectPeerWithLowestRTT(ctx, h1, proto)
require.NoError(t, err)
}
func TestEnodeToMultiAddr(t *testing.T) {
enr := "enr:-IS4QAmC_o1PMi5DbR4Bh4oHVyQunZblg4bTaottPtBodAhJZvxVlWW-4rXITPNg4mwJ8cW__D9FBDc9N4mdhyMqB-EBgmlkgnY0gmlwhIbRi9KJc2VjcDI1NmsxoQOevTdO6jvv3fRruxguKR-3Ge4bcFsLeAIWEDjrfaigNoN0Y3CCdl8"
parsedNode := enode.MustParse(enr)
expectedMultiAddr := "/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ"
actualMultiAddr, err := EnodeToMultiAddr(parsedNode)
require.NoError(t, err)
require.Equal(t, expectedMultiAddr, actualMultiAddr.String())
}
func TestGetENRandIP(t *testing.T) {
key, _ := gcrypto.GenerateKey()
privKey := crypto.PrivKey((*crypto.Secp256k1PrivateKey)(key))
id, _ := peer.IDFromPublicKey(privKey.GetPublic())
hostAddr := &net.TCPAddr{IP: net.ParseIP("192.168.0.1"), Port: 9999}
hostMultiAddr, _ := manet.FromNetAddr(hostAddr)
hostInfo, _ := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", id.Pretty()))
ogMultiaddress := hostMultiAddr.Encapsulate(hostInfo)
node, resTCPAddr, err := GetENRandIP(ogMultiaddress, key)
require.NoError(t, err)
require.Equal(t, hostAddr, resTCPAddr)
parsedNode := enode.MustParse(node.String())
resMultiaddress, err := EnodeToMultiAddr(parsedNode)
require.NoError(t, err)
require.Equal(t, ogMultiaddress.String(), resMultiaddress.String())
}