mirror of
https://github.com/logos-messaging/logos-messaging-go.git
synced 2026-02-06 15:03:13 +00:00
refactor: enr builder
This commit is contained in:
parent
d9a12bf079
commit
e14c55c263
@ -2,14 +2,9 @@ package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
@ -18,71 +13,25 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (w *WakuNode) newLocalnode(priv *ecdsa.PrivateKey) (*enode.LocalNode, error) {
|
||||
db, err := enode.OpenDB("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enode.NewLocalNode(db, priv), nil
|
||||
}
|
||||
|
||||
func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []ma.Multiaddr) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
// Deleting the multiaddr entry, as we could not write it succesfully
|
||||
localnode.Delete(enr.WithEntry(wenr.MultiaddrENRField, struct{}{}))
|
||||
err = errors.New("could not write enr record")
|
||||
}
|
||||
}()
|
||||
|
||||
var fieldRaw []byte
|
||||
for _, addr := range addrAggr {
|
||||
maRaw := addr.Bytes()
|
||||
maSize := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(maSize, uint16(len(maRaw)))
|
||||
|
||||
fieldRaw = append(fieldRaw, maSize...)
|
||||
fieldRaw = append(fieldRaw, maRaw...)
|
||||
}
|
||||
|
||||
if len(fieldRaw) != 0 && len(fieldRaw) <= 100 { // Max length for multiaddr field before triggering the 300 bytes limit
|
||||
localnode.Set(enr.WithEntry(wenr.MultiaddrENRField, fieldRaw))
|
||||
}
|
||||
|
||||
// This is to trigger the signing record err due to exceeding 300bytes limit
|
||||
_ = localnode.Node()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags wenr.WakuEnrBitfield, advertiseAddr []ma.Multiaddr, shouldAutoUpdate bool, log *zap.Logger) error {
|
||||
localnode.SetFallbackUDP(int(udpPort))
|
||||
localnode.Set(enr.WithEntry(wenr.WakuENRField, wakuFlags))
|
||||
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||
|
||||
if udpPort > math.MaxUint16 {
|
||||
return errors.New("invalid udp port number")
|
||||
}
|
||||
var options []wenr.ENROption
|
||||
options = append(options, wenr.WithUDPPort(udpPort))
|
||||
options = append(options, wenr.WithWakuBitfield(wakuFlags))
|
||||
options = append(options, wenr.WithMultiaddress(multiaddrs...))
|
||||
|
||||
if advertiseAddr != nil {
|
||||
// An advertised address disables libp2p address updates
|
||||
// and discv5 predictions
|
||||
|
||||
ipAddr, err := selectMostExternalAddress(advertiseAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
localnode.SetStaticIP(ipAddr.IP)
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
|
||||
|
||||
return writeMultiaddresses(localnode, multiaddrs)
|
||||
options = append(options, wenr.WithIP(ipAddr))
|
||||
} else if !shouldAutoUpdate {
|
||||
// We received a libp2p address update. Autoupdate is disabled
|
||||
// Using a static ip will disable endpoint prediction.
|
||||
localnode.SetStaticIP(ipAddr.IP)
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
|
||||
return writeMultiaddresses(localnode, multiaddrs)
|
||||
options = append(options, wenr.WithIP(ipAddr))
|
||||
} else {
|
||||
// We received a libp2p address update, but we should still
|
||||
// allow discv5 to update the enr record. We set the localnode
|
||||
@ -105,42 +54,9 @@ func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.M
|
||||
localnode.Delete(enr.IPv6{})
|
||||
localnode.Delete(enr.TCP6(0))
|
||||
}
|
||||
|
||||
return writeMultiaddresses(localnode, multiaddrs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func writeMultiaddresses(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr) error {
|
||||
// Randomly shuffle multiaddresses
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] })
|
||||
|
||||
// Adding extra multiaddresses. Should probably not exceed the enr max size of 300bytes
|
||||
var err error
|
||||
failedOnceWritingENR := false
|
||||
couldWriteENRatLeastOnce := false
|
||||
successIdx := -1
|
||||
for i := len(multiaddrs) - 1; i >= 0; i-- {
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:i])
|
||||
if err == nil {
|
||||
couldWriteENRatLeastOnce = true
|
||||
successIdx = i
|
||||
break
|
||||
} else {
|
||||
failedOnceWritingENR = true
|
||||
}
|
||||
}
|
||||
|
||||
if failedOnceWritingENR && couldWriteENRatLeastOnce {
|
||||
// Could write a subset of multiaddresses but not all
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:successIdx])
|
||||
if err != nil {
|
||||
return errors.New("could not write new ENR")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return wenr.Update(localnode, options...)
|
||||
}
|
||||
|
||||
func isPrivate(addr *net.TCPAddr) bool {
|
||||
|
||||
@ -184,7 +184,7 @@ func New(opts ...WakuNodeOption) (*WakuNode, error) {
|
||||
w.timesource = timesource.NewDefaultClock()
|
||||
}
|
||||
|
||||
w.localNode, err = w.newLocalnode(w.opts.privKey)
|
||||
w.localNode, err = enr.NewLocalnode(w.opts.privKey)
|
||||
if err != nil {
|
||||
w.log.Error("creating localnode", zap.Error(err))
|
||||
}
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
package enr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
gcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
@ -28,53 +23,26 @@ func TestEnodeToMultiAddr(t *testing.T) {
|
||||
require.Equal(t, expectedMultiAddr, actualMultiAddr.String())
|
||||
}
|
||||
|
||||
func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []ma.Multiaddr) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = errors.New("could not write enr record")
|
||||
}
|
||||
}()
|
||||
|
||||
var fieldRaw []byte
|
||||
for _, addr := range addrAggr {
|
||||
maRaw := addr.Bytes()
|
||||
maSize := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(maSize, uint16(len(maRaw)))
|
||||
|
||||
fieldRaw = append(fieldRaw, maSize...)
|
||||
fieldRaw = append(fieldRaw, maRaw...)
|
||||
}
|
||||
|
||||
if len(fieldRaw) != 0 {
|
||||
localnode.Set(enr.WithEntry(MultiaddrENRField, fieldRaw))
|
||||
}
|
||||
|
||||
// This is to trigger the signing record err due to exceeding 300bytes limit
|
||||
_ = localnode.Node()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: this function is duplicated in localnode.go. Remove duplication
|
||||
func updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags WakuEnrBitfield, advertiseAddr *net.IP, shouldAutoUpdate bool, log *zap.Logger) error {
|
||||
localnode.SetFallbackUDP(int(udpPort))
|
||||
localnode.Set(enr.WithEntry(WakuENRField, wakuFlags))
|
||||
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||
|
||||
if udpPort > math.MaxUint16 {
|
||||
return errors.New("invalid udp port number")
|
||||
}
|
||||
func updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags WakuEnrBitfield, advertiseAddr *net.IP, shouldAutoUpdate bool, log *zap.Logger) error {
|
||||
var options []ENROption
|
||||
options = append(options, WithUDPPort(udpPort))
|
||||
options = append(options, WithWakuBitfield(wakuFlags))
|
||||
options = append(options, WithMultiaddress(multiaddrs...))
|
||||
|
||||
if advertiseAddr != nil {
|
||||
// An advertised address disables libp2p address updates
|
||||
// and discv5 predictions
|
||||
localnode.SetStaticIP(*advertiseAddr)
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
|
||||
nip := &net.TCPAddr{
|
||||
IP: *advertiseAddr,
|
||||
Port: ipAddr.Port,
|
||||
}
|
||||
options = append(options, WithIP(nip))
|
||||
} else if !shouldAutoUpdate {
|
||||
// We received a libp2p address update. Autoupdate is disabled
|
||||
// Using a static ip will disable endpoint prediction.
|
||||
localnode.SetStaticIP(ipAddr.IP)
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
|
||||
options = append(options, WithIP(ipAddr))
|
||||
} else {
|
||||
// We received a libp2p address update, but we should still
|
||||
// allow discv5 to update the enr record. We set the localnode
|
||||
@ -90,7 +58,7 @@ func updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAd
|
||||
localnode.Delete(enr.TCP(0))
|
||||
}
|
||||
|
||||
if ip6 != nil && !ip6.IsUnspecified() {
|
||||
if ip4 == nil && ip6 != nil && !ip6.IsUnspecified() {
|
||||
localnode.Set(enr.IPv6(ip6))
|
||||
localnode.Set(enr.TCP6(ipAddr.Port))
|
||||
} else {
|
||||
@ -99,40 +67,7 @@ func updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAd
|
||||
}
|
||||
}
|
||||
|
||||
// Randomly shuffle multiaddresses
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] })
|
||||
|
||||
// Adding a single extra multiaddress. Should probably not exceed the enr max size of 300bytes
|
||||
var err error
|
||||
failedOnceWritingENR := false
|
||||
couldWriteENRatLeastOnce := false
|
||||
successIdx := -1
|
||||
for i := len(multiaddrs) - 1; i >= 0; i-- {
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:i])
|
||||
if err == nil {
|
||||
couldWriteENRatLeastOnce = true
|
||||
successIdx = i
|
||||
break
|
||||
} else {
|
||||
failedOnceWritingENR = true
|
||||
}
|
||||
}
|
||||
|
||||
if failedOnceWritingENR {
|
||||
if !couldWriteENRatLeastOnce {
|
||||
// In case multiaddr could not be populated at all
|
||||
localnode.Delete(enr.WithEntry(MultiaddrENRField, struct{}{}))
|
||||
} else {
|
||||
// Could write a subset of multiaddresses but not all
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:successIdx])
|
||||
if err != nil {
|
||||
return errors.New("could not write new ENR")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return Update(localnode, options...)
|
||||
}
|
||||
|
||||
func TestMultiaddr(t *testing.T) {
|
||||
|
||||
131
waku/v2/protocol/enr/localnode.go
Normal file
131
waku/v2/protocol/enr/localnode.go
Normal file
@ -0,0 +1,131 @@
|
||||
package enr
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func NewLocalnode(priv *ecdsa.PrivateKey) (*enode.LocalNode, error) {
|
||||
db, err := enode.OpenDB("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enode.NewLocalNode(db, priv), nil
|
||||
}
|
||||
|
||||
type ENROption func(*enode.LocalNode) error
|
||||
|
||||
func WithMultiaddress(multiaddrs ...multiaddr.Multiaddr) ENROption {
|
||||
return func(localnode *enode.LocalNode) (err error) {
|
||||
|
||||
// Randomly shuffle multiaddresses
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] })
|
||||
|
||||
// Adding extra multiaddresses. Should probably not exceed the enr max size of 300bytes
|
||||
failedOnceWritingENR := false
|
||||
couldWriteENRatLeastOnce := false
|
||||
successIdx := -1
|
||||
for i := len(multiaddrs) - 1; i >= 0; i-- {
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:i])
|
||||
if err == nil {
|
||||
couldWriteENRatLeastOnce = true
|
||||
successIdx = i
|
||||
break
|
||||
} else {
|
||||
failedOnceWritingENR = true
|
||||
}
|
||||
}
|
||||
|
||||
if failedOnceWritingENR && couldWriteENRatLeastOnce {
|
||||
// Could write a subset of multiaddresses but not all
|
||||
err = writeMultiaddressField(localnode, multiaddrs[0:successIdx])
|
||||
if err != nil {
|
||||
return errors.New("could not write new ENR")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithCapabilities(lightpush, filter, store, relay bool) ENROption {
|
||||
return func(localnode *enode.LocalNode) (err error) {
|
||||
wakuflags := NewWakuEnrBitfield(lightpush, filter, store, relay)
|
||||
return WithWakuBitfield(wakuflags)(localnode)
|
||||
}
|
||||
}
|
||||
|
||||
func WithWakuBitfield(flags WakuEnrBitfield) ENROption {
|
||||
return func(localnode *enode.LocalNode) (err error) {
|
||||
localnode.Set(enr.WithEntry(WakuENRField, flags))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithIP(ipAddr *net.TCPAddr) ENROption {
|
||||
return func(localnode *enode.LocalNode) (err error) {
|
||||
localnode.SetStaticIP(ipAddr.IP)
|
||||
localnode.Set(enr.TCP(uint16(ipAddr.Port))) // TODO: ipv6?
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithUDPPort(udpPort uint) ENROption {
|
||||
return func(localnode *enode.LocalNode) (err error) {
|
||||
if udpPort > math.MaxUint16 {
|
||||
return errors.New("invalid udp port number")
|
||||
}
|
||||
localnode.SetFallbackUDP(int(udpPort))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Update(localnode *enode.LocalNode, enrOptions ...ENROption) error {
|
||||
localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
|
||||
for _, opt := range enrOptions {
|
||||
err := opt(localnode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []multiaddr.Multiaddr) (err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
// Deleting the multiaddr entry, as we could not write it succesfully
|
||||
localnode.Delete(enr.WithEntry(MultiaddrENRField, struct{}{}))
|
||||
err = errors.New("could not write enr record")
|
||||
}
|
||||
}()
|
||||
|
||||
var fieldRaw []byte
|
||||
for _, addr := range addrAggr {
|
||||
maRaw := addr.Bytes()
|
||||
maSize := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(maSize, uint16(len(maRaw)))
|
||||
|
||||
fieldRaw = append(fieldRaw, maSize...)
|
||||
fieldRaw = append(fieldRaw, maRaw...)
|
||||
}
|
||||
|
||||
if len(fieldRaw) != 0 && len(fieldRaw) <= 100 { // Max length for multiaddr field before triggering the 300 bytes limit
|
||||
localnode.Set(enr.WithEntry(MultiaddrENRField, fieldRaw))
|
||||
}
|
||||
|
||||
// This is to trigger the signing record err due to exceeding 300bytes limit
|
||||
_ = localnode.Node()
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -6,25 +6,31 @@ import (
|
||||
"github.com/waku-org/go-waku/waku/v2/protocol"
|
||||
)
|
||||
|
||||
func SetWakuRelayShardingIndicesList(localnode *enode.LocalNode, rs protocol.RelayShards) error {
|
||||
value, err := rs.IndicesList()
|
||||
if err != nil {
|
||||
return err
|
||||
func WithWakuRelayShardingIndicesList(rs protocol.RelayShards) ENROption {
|
||||
return func(localnode *enode.LocalNode) error {
|
||||
value, err := rs.IndicesList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localnode.Set(enr.WithEntry(ShardingIndicesListEnrField, value))
|
||||
return nil
|
||||
}
|
||||
localnode.Set(enr.WithEntry(ShardingIndicesListEnrField, value))
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetWakuRelayShardingBitVector(localnode *enode.LocalNode, rs protocol.RelayShards) error {
|
||||
localnode.Set(enr.WithEntry(ShardingBitVectorEnrField, rs.BitVector()))
|
||||
return nil
|
||||
func WithWakuRelayShardingBitVector(rs protocol.RelayShards) ENROption {
|
||||
return func(localnode *enode.LocalNode) error {
|
||||
localnode.Set(enr.WithEntry(ShardingBitVectorEnrField, rs.BitVector()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func SetWakuRelaySharding(localnode *enode.LocalNode, rs protocol.RelayShards) error {
|
||||
if len(rs.Indices) >= 64 {
|
||||
return SetWakuRelayShardingBitVector(localnode, rs)
|
||||
} else {
|
||||
return SetWakuRelayShardingIndicesList(localnode, rs)
|
||||
func WithtWakuRelaySharding(rs protocol.RelayShards) ENROption {
|
||||
return func(localnode *enode.LocalNode) error {
|
||||
if len(rs.Indices) >= 64 {
|
||||
return WithWakuRelayShardingBitVector(rs)(localnode)
|
||||
} else {
|
||||
return WithWakuRelayShardingIndicesList(rs)(localnode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user