fix: enr exceeds 300 bytes

This commit is contained in:
Richard Ramos 2023-02-07 09:45:06 -04:00 committed by RichΛrd
parent c3b5ab95ab
commit cce85913e6
3 changed files with 114 additions and 68 deletions

View File

@ -6,8 +6,10 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"math" "math"
"math/rand"
"net" "net"
"strconv" "strconv"
"time"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr" "github.com/ethereum/go-ethereum/p2p/enr"
@ -24,6 +26,33 @@ func (w *WakuNode) newLocalnode(priv *ecdsa.PrivateKey) (*enode.LocalNode, error
return enode.NewLocalNode(db, priv), nil return enode.NewLocalNode(db, priv), nil
} }
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(utils.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 utils.WakuEnrBitfield, advertiseAddr *net.IP, shouldAutoUpdate bool, log *zap.Logger) error { func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAddr *net.TCPAddr, udpPort uint, wakuFlags utils.WakuEnrBitfield, advertiseAddr *net.IP, shouldAutoUpdate bool, log *zap.Logger) error {
localnode.SetFallbackUDP(int(udpPort)) localnode.SetFallbackUDP(int(udpPort))
localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags)) localnode.Set(enr.WithEntry(utils.WakuENRField, wakuFlags))
@ -67,47 +96,37 @@ func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.M
} }
} }
// Adding extra multiaddresses. It will to add as many multiaddresses as possible // Randomly shuffle multiaddresses
// without exceeding the enr max size of 300bytes rand.Seed(time.Now().UnixNano())
var addrAggr []ma.Multiaddr 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 var err error
failedOnceWritingENR := false
couldWriteENRatLeastOnce := false
successIdx := -1
for i := len(multiaddrs) - 1; i >= 0; i-- { for i := len(multiaddrs) - 1; i >= 0; i-- {
addrAggr = append(addrAggr, multiaddrs[0:i]...) err = writeMultiaddressField(localnode, multiaddrs[0:i])
err = func() (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(utils.MultiaddrENRField, fieldRaw))
}
// This is to trigger the signing record err due to exceeding 300bytes limit
_ = localnode.Node()
return nil
}()
if err == nil { if err == nil {
couldWriteENRatLeastOnce = true
successIdx = i
break break
} else {
failedOnceWritingENR = true
} }
} }
// In case multiaddr could not be populated at all if failedOnceWritingENR {
if err != nil { if !couldWriteENRatLeastOnce {
localnode.Delete(enr.WithEntry(utils.MultiaddrENRField, struct{}{})) // In case multiaddr could not be populated at all
localnode.Delete(enr.WithEntry(utils.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 nil

View File

@ -91,6 +91,7 @@ type WakuNode struct {
protocolEventSub event.Subscription protocolEventSub event.Subscription
identificationEventSub event.Subscription identificationEventSub event.Subscription
addressChangesSub event.Subscription addressChangesSub event.Subscription
enrChangeCh chan struct{}
keepAliveMutex sync.Mutex keepAliveMutex sync.Mutex
keepAliveFails map[peer.ID]int keepAliveFails map[peer.ID]int
@ -234,6 +235,8 @@ func New(opts ...WakuNodeOption) (*WakuNode, error) {
return nil, err return nil, err
} }
w.enrChangeCh = make(chan struct{}, 10)
if params.connStatusC != nil { if params.connStatusC != nil {
w.connStatusChan = params.connStatusC w.connStatusChan = params.connStatusC
} }
@ -253,6 +256,7 @@ func (w *WakuNode) watchMultiaddressChanges(ctx context.Context) {
return return
case <-first: case <-first:
w.log.Info("listening", logging.MultiAddrs("multiaddr", addrs...)) w.log.Info("listening", logging.MultiAddrs("multiaddr", addrs...))
w.enrChangeCh <- struct{}{}
case <-w.addressChangesSub.Out(): case <-w.addressChangesSub.Out():
newAddrs := w.ListenAddresses() newAddrs := w.ListenAddresses()
diff := false diff := false
@ -270,6 +274,7 @@ func (w *WakuNode) watchMultiaddressChanges(ctx context.Context) {
addrs = newAddrs addrs = newAddrs
w.log.Info("listening addresses update received", logging.MultiAddrs("multiaddr", addrs...)) w.log.Info("listening addresses update received", logging.MultiAddrs("multiaddr", addrs...))
_ = w.setupENR(ctx, addrs) _ = w.setupENR(ctx, addrs)
w.enrChangeCh <- struct{}{}
} }
} }
} }
@ -403,6 +408,8 @@ func (w *WakuNode) Stop() {
w.host.Close() w.host.Close()
close(w.enrChangeCh)
w.wg.Wait() w.wg.Wait()
} }
@ -419,13 +426,12 @@ func (w *WakuNode) ID() string {
func (w *WakuNode) watchENRChanges(ctx context.Context) { func (w *WakuNode) watchENRChanges(ctx context.Context) {
defer w.wg.Done() defer w.wg.Done()
timer := time.NewTicker(1 * time.Second)
var prevNodeVal string var prevNodeVal string
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
case <-timer.C: case <-w.enrChangeCh:
if w.localNode != nil { if w.localNode != nil {
currNodeVal := w.localNode.Node().String() currNodeVal := w.localNode.Node().String()
if prevNodeVal != currNodeVal { if prevNodeVal != currNodeVal {

View File

@ -4,8 +4,10 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"math" "math"
"math/rand"
"net" "net"
"testing" "testing"
"time"
gcrypto "github.com/ethereum/go-ethereum/crypto" gcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/p2p/enode"
@ -25,6 +27,33 @@ func TestEnodeToMultiAddr(t *testing.T) {
require.Equal(t, expectedMultiAddr, actualMultiAddr.String()) 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 // 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 { 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.SetFallbackUDP(int(udpPort))
@ -69,45 +98,37 @@ func updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.Multiaddr, ipAd
} }
} }
var addrAggr []ma.Multiaddr // 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 var err error
failedOnceWritingENR := false
couldWriteENRatLeastOnce := false
successIdx := -1
for i := len(multiaddrs) - 1; i >= 0; i-- { for i := len(multiaddrs) - 1; i >= 0; i-- {
addrAggr = append(addrAggr, multiaddrs[0:i]...) err = writeMultiaddressField(localnode, multiaddrs[0:i])
err = func() (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
}()
if err == nil { if err == nil {
couldWriteENRatLeastOnce = true
successIdx = i
break break
} else {
failedOnceWritingENR = true
} }
} }
// In case multiaddr could not be populated at all if failedOnceWritingENR {
if err != nil { if !couldWriteENRatLeastOnce {
localnode.Delete(enr.WithEntry(MultiaddrENRField, struct{}{})) // 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 nil