mirror of https://github.com/status-im/go-waku.git
feat: add support for RFC31 ENR (#180)
This commit is contained in:
parent
0de19253da
commit
1b0e03c07b
|
@ -2,6 +2,8 @@ package utils
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
|
@ -14,6 +16,7 @@ import (
|
|||
)
|
||||
|
||||
const WakuENRField = "waku2"
|
||||
const MultiaddrENRField = "multiaddrs"
|
||||
|
||||
// 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
|
||||
|
@ -69,6 +72,44 @@ func GetENRandIP(addr ma.Multiaddr, wakuFlags WakuEnrBitfield, privK *ecdsa.Priv
|
|||
return nil, nil, fmt.Errorf("could not set port %d", port)
|
||||
}
|
||||
|
||||
var multiaddrItems []ma.Multiaddr
|
||||
|
||||
// 31/WAKU2-ENR
|
||||
|
||||
_, err = addr.ValueForProtocol(ma.P_WS)
|
||||
if err == nil {
|
||||
multiaddrItems = append(multiaddrItems, addr)
|
||||
}
|
||||
|
||||
_, err = addr.ValueForProtocol(ma.P_WSS)
|
||||
if err == nil {
|
||||
multiaddrItems = append(multiaddrItems, addr)
|
||||
}
|
||||
|
||||
p2p, err := addr.ValueForProtocol(ma.P_P2P)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
p2pAddr, err := ma.NewMultiaddr("/p2p/" + p2p)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Could not create p2p addr: %w", err)
|
||||
}
|
||||
|
||||
var fieldRaw []byte
|
||||
for _, ma := range multiaddrItems {
|
||||
maRaw := ma.Decapsulate(p2pAddr).Bytes()
|
||||
maSize := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(maSize, uint16(len(maRaw)))
|
||||
|
||||
fieldRaw = append(fieldRaw, maSize...)
|
||||
fieldRaw = append(fieldRaw, maRaw...)
|
||||
}
|
||||
|
||||
if len(fieldRaw) != 0 {
|
||||
r.Set(enr.WithEntry(MultiaddrENRField, fieldRaw))
|
||||
}
|
||||
|
||||
r.Set(enr.IP(net.ParseIP(ip)))
|
||||
r.Set(enr.WithEntry(WakuENRField, wakuFlags))
|
||||
|
||||
|
@ -91,6 +132,53 @@ func EnodeToMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
|
|||
return ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", node.IP(), node.TCP(), peerID))
|
||||
}
|
||||
|
||||
func Multiaddress(node *enode.Node) ([]ma.Multiaddr, error) {
|
||||
peerID, err := peer.IDFromPublicKey(&ECDSAPublicKey{node.Pubkey()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var multiaddrRaw []byte
|
||||
if err := node.Record().Load(enr.WithEntry(MultiaddrENRField, &multiaddrRaw)); err != nil {
|
||||
if !enr.IsNotFound(err) {
|
||||
log.Error("could not retrieve multiaddress field for node ", node)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(multiaddrRaw) < 2 {
|
||||
return nil, errors.New("invalid multiaddress field length")
|
||||
}
|
||||
|
||||
hostInfo, err := ma.NewMultiaddr(fmt.Sprintf("/p2p/%s", peerID.Pretty()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []ma.Multiaddr
|
||||
offset := 0
|
||||
for {
|
||||
maSize := binary.BigEndian.Uint16(multiaddrRaw[offset : offset+2])
|
||||
if len(multiaddrRaw) < offset+2+int(maSize) {
|
||||
return nil, errors.New("invalid multiaddress field length")
|
||||
}
|
||||
maRaw := multiaddrRaw[offset+2 : offset+2+int(maSize)]
|
||||
addr, err := ma.NewMultiaddrBytes(maRaw)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid multiaddress field length")
|
||||
}
|
||||
|
||||
result = append(result, addr.Encapsulate(hostInfo))
|
||||
|
||||
offset += 2 + int(maSize)
|
||||
if offset >= len(multiaddrRaw) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func EnodeToPeerInfo(node *enode.Node) (*peer.AddrInfo, error) {
|
||||
address, err := EnodeToMultiAddr(node)
|
||||
if err != nil {
|
||||
|
|
|
@ -45,3 +45,19 @@ func TestGetENRandIP(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, ogMultiaddress.String(), resMultiaddress.String())
|
||||
}
|
||||
|
||||
func TestMultiaddr(t *testing.T) {
|
||||
key, _ := gcrypto.GenerateKey()
|
||||
privKey := crypto.PrivKey((*crypto.Secp256k1PrivateKey)(key))
|
||||
id, _ := peer.IDFromPublicKey(privKey.GetPublic())
|
||||
ogMultiaddress, _ := ma.NewMultiaddr("/ip4/10.0.0.241/tcp/60001/ws/p2p/" + id.Pretty())
|
||||
wakuFlag := NewWakuEnrBitfield(true, true, true, true)
|
||||
|
||||
node, _, err := GetENRandIP(ogMultiaddress, wakuFlag, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
multiaddresses, err := Multiaddress(node)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, multiaddresses, 1)
|
||||
require.True(t, ogMultiaddress.Equal(multiaddresses[0]))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue