2021-12-03 13:40:51 +00:00
package utils
import (
"crypto/ecdsa"
2021-12-10 14:26:38 +00:00
"encoding/binary"
"errors"
2021-12-03 13:40:51 +00:00
"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"
2022-01-18 18:17:06 +00:00
"go.uber.org/zap"
2021-12-03 13:40:51 +00:00
)
2022-04-25 19:31:26 +00:00
// WakuENRField is the name of the ENR field that contains information about which protocols are supported by the node
2021-12-03 13:40:51 +00:00
const WakuENRField = "waku2"
2022-04-25 19:31:26 +00:00
// MultiaddrENRField is the name of the ENR field that will contain multiaddresses that cannot be described using the
// already available ENR fields (i.e. in the case of websocket connections)
2021-12-10 14:26:38 +00:00
const MultiaddrENRField = "multiaddrs"
2021-12-03 13:40:51 +00:00
// 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
2022-04-25 19:31:26 +00:00
// NewWakuEnrBitfield creates a WakuEnrBitField whose value will depend on which protocols are enabled in the node
2021-12-03 13:40:51 +00:00
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
}
2022-04-25 19:31:26 +00:00
// GetENRandIP returns a enr Node and TCP address obtained from a multiaddress. priv key and protocols supported
2021-12-03 13:40:51 +00:00
func GetENRandIP ( addr ma . Multiaddr , wakuFlags WakuEnrBitfield , privK * ecdsa . PrivateKey ) ( * enode . Node , * net . TCPAddr , error ) {
2022-03-22 00:48:46 +00:00
var ip string
dns4 , err := addr . ValueForProtocol ( ma . P_DNS4 )
2021-12-03 13:40:51 +00:00
if err != nil {
2022-03-22 00:48:46 +00:00
ip , err = addr . ValueForProtocol ( ma . P_IP4 )
if err != nil {
return nil , nil , err
}
} else {
netIP , err := net . ResolveIPAddr ( "ip4" , dns4 )
if err != nil {
return nil , nil , err
}
ip = netIP . String ( )
2021-12-03 13:40:51 +00:00
}
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 )
}
2021-12-10 14:26:38 +00:00
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 {
2022-06-13 18:30:35 +00:00
return nil , nil , fmt . Errorf ( "could not create p2p addr: %w" , err )
2021-12-10 14:26:38 +00:00
}
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 ) )
}
2021-12-03 13:40:51 +00:00
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
}
2022-04-25 19:31:26 +00:00
// EnodeToMultiaddress converts an enode into a multiaddress
func enodeToMultiAddr ( node * enode . Node ) ( ma . Multiaddr , error ) {
2022-05-27 19:55:35 +00:00
pubKey := EcdsaPubKeyToSecp256k1PublicKey ( node . Pubkey ( ) )
2022-02-21 19:21:31 +00:00
peerID , err := peer . IDFromPublicKey ( pubKey )
2021-12-03 13:40:51 +00:00
if err != nil {
return nil , err
}
return ma . NewMultiaddr ( fmt . Sprintf ( "/ip4/%s/tcp/%d/p2p/%s" , node . IP ( ) , node . TCP ( ) , peerID ) )
}
2022-04-25 19:31:26 +00:00
// Multiaddress is used to extract all the multiaddresses that are part of a ENR record
2021-12-10 14:26:38 +00:00
func Multiaddress ( node * enode . Node ) ( [ ] ma . Multiaddr , error ) {
2022-05-27 19:55:35 +00:00
pubKey := EcdsaPubKeyToSecp256k1PublicKey ( node . Pubkey ( ) )
2022-02-21 19:21:31 +00:00
peerID , err := peer . IDFromPublicKey ( pubKey )
2021-12-10 14:26:38 +00:00
if err != nil {
return nil , err
}
var multiaddrRaw [ ] byte
if err := node . Record ( ) . Load ( enr . WithEntry ( MultiaddrENRField , & multiaddrRaw ) ) ; err != nil {
2022-03-08 12:58:32 +00:00
if enr . IsNotFound ( err ) {
2022-04-25 19:31:26 +00:00
Logger ( ) . Debug ( "trying to convert enode to multiaddress, since I could not retrieve multiaddress field for node " , zap . Any ( "enode" , node ) )
addr , err := enodeToMultiAddr ( node )
2022-03-08 12:58:32 +00:00
if err != nil {
return nil , err
}
return [ ] ma . Multiaddr { addr } , nil
2021-12-10 14:26:38 +00:00
}
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
}
2021-12-03 13:40:51 +00:00
func EnodeToPeerInfo ( node * enode . Node ) ( * peer . AddrInfo , error ) {
2022-04-25 19:31:26 +00:00
addresses , err := Multiaddress ( node )
if err != nil {
return nil , err
}
res , err := peer . AddrInfosFromP2pAddrs ( addresses ... )
2021-12-03 13:40:51 +00:00
if err != nil {
return nil , err
}
2022-04-25 19:31:26 +00:00
return & res [ 0 ] , nil
2021-12-03 13:40:51 +00:00
}