fix_: panic when enr exceeds 300 bytes (#5446)

This commit is contained in:
richΛrd 2024-07-02 05:37:17 -04:00 committed by GitHub
parent 131cfe7b3d
commit 0c470854ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 62 additions and 33 deletions

2
go.mod
View File

@ -93,7 +93,7 @@ require (
github.com/schollz/peerdiscovery v1.7.0
github.com/siphiuel/lc-proxy-wrapper v0.0.0-20230516150924-246507cee8c7
github.com/urfave/cli/v2 v2.27.2
github.com/waku-org/go-waku v0.8.1-0.20240626004844-19a47a1ac1f5
github.com/waku-org/go-waku v0.8.1-0.20240628140035-3604bf39ad28
github.com/wk8/go-ordered-map/v2 v2.1.7
github.com/yeqown/go-qrcode/v2 v2.2.1
github.com/yeqown/go-qrcode/writer/standard v1.2.1

4
go.sum
View File

@ -2137,8 +2137,8 @@ github.com/waku-org/go-discover v0.0.0-20240506173252-4912704efdc5 h1:4K3IS97Jry
github.com/waku-org/go-discover v0.0.0-20240506173252-4912704efdc5/go.mod h1:eBHgM6T4EG0RZzxpxKy+rGz/6Dw2Nd8DWxS0lm9ESDw=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0 h1:R4YYx2QamhBRl/moIxkDCNW+OP7AHbyWLBygDc/xIMo=
github.com/waku-org/go-libp2p-rendezvous v0.0.0-20240110193335-a67d1cc760a0/go.mod h1:EhZP9fee0DYjKH/IOQvoNSy1tSHp2iZadsHGphcAJgY=
github.com/waku-org/go-waku v0.8.1-0.20240626004844-19a47a1ac1f5 h1:9UyIIy/IvlJB2nHIXydne6OfNfOWPPL08+XmCI3iEBo=
github.com/waku-org/go-waku v0.8.1-0.20240626004844-19a47a1ac1f5/go.mod h1:biffO55kWbvfO8jdu/aAPiWcmozrfFKPum4EMFDib+k=
github.com/waku-org/go-waku v0.8.1-0.20240628140035-3604bf39ad28 h1:7BqEcKgJs9QNzrLlC4jn1opCjGKZxNX2B/AVqhsvwzw=
github.com/waku-org/go-waku v0.8.1-0.20240628140035-3604bf39ad28/go.mod h1:fHQ6WCSAlTollYHvAeZeO+d7lOYwcvQxHk+DyGLeoMI=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59 h1:jisj+OCI6QydLtFq3Pyhu49wl9ytPN7oAHjMfepHDrA=
github.com/waku-org/go-zerokit-rln v0.1.14-0.20240102145250-fa738c0bdf59/go.mod h1:1PdBdPzyTaKt3VnpAHk3zj+r9dXPFOr3IHZP9nFle6E=
github.com/waku-org/go-zerokit-rln-apple v0.0.0-20230916172309-ee0ee61dde2b h1:KgZVhsLkxsj5gb/FfndSCQu6VYwALrCOgYI3poR95yE=

View File

@ -23,6 +23,12 @@ func (w *WakuNode) updateLocalNode(localnode *enode.LocalNode, multiaddrs []ma.M
options = append(options, wenr.WithUDPPort(udpPort))
options = append(options, wenr.WithWakuBitfield(wakuFlags))
// Reset ENR fields
wenr.DeleteField(localnode, wenr.MultiaddrENRField)
wenr.DeleteField(localnode, enr.TCP(0).ENRKey())
wenr.DeleteField(localnode, enr.IPv4{}.ENRKey())
wenr.DeleteField(localnode, enr.IPv6{}.ENRKey())
if advertiseAddr != nil {
// An advertised address disables libp2p address updates
// and discv5 predictions
@ -245,7 +251,6 @@ func selectCircuitRelayListenAddresses(ctx context.Context, addresses []ma.Multi
return result, nil
}
func filter0Port(addresses []ma.Multiaddr) ([]ma.Multiaddr, error) {
var result []ma.Multiaddr
for _, addr := range addresses {

View File

@ -270,7 +270,7 @@ func New(opts ...WakuNodeOption) (*WakuNode, error) {
}
}
w.peerExchange, err = peer_exchange.NewWakuPeerExchange(w.DiscV5(), w.peerConnector, w.peermanager, w.opts.prometheusReg, w.log)
w.peerExchange, err = peer_exchange.NewWakuPeerExchange(w.DiscV5(), w.opts.clusterID, w.peerConnector, w.peermanager, w.opts.prometheusReg, w.log)
if err != nil {
return nil, err
}

View File

@ -8,6 +8,7 @@ import (
"math/rand"
"net"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/multiformats/go-multiaddr"
@ -26,16 +27,32 @@ type ENROption func(*enode.LocalNode) error
func WithMultiaddress(multiaddrs ...multiaddr.Multiaddr) ENROption {
return func(localnode *enode.LocalNode) (err error) {
// Randomly shuffle multiaddresses
rand.Shuffle(len(multiaddrs), func(i, j int) { multiaddrs[i], multiaddrs[j] = multiaddrs[j], multiaddrs[i] })
// Testing how many multiaddresses we can write before we exceed the limit
// By simulating what the localnode does when signing the enr, but without
// causing a panic
privk, err := crypto.GenerateKey()
if err != nil {
return err
}
// Adding extra multiaddresses. Should probably not exceed the enr max size of 300bytes
failedOnceWritingENR := false
couldWriteENRatLeastOnce := false
successIdx := -1
for i := len(multiaddrs); i > 0; i-- {
err = writeMultiaddressField(localnode, multiaddrs[0:i])
cpy := localnode.Node().Record() // Record() creates a copy for the current iteration
// Copy all the entries that might not have been written in the ENR record due to the
// async nature of localnode.Set
for _, entry := range localnode.Entries() {
cpy.Set(entry)
}
cpy.Set(enr.WithEntry(MultiaddrENRField, marshalMultiaddress(multiaddrs[0:i])))
cpy.SetSeq(localnode.Seq() + 1)
err = enode.SignV4(cpy, privk)
if err == nil {
couldWriteENRatLeastOnce = true
successIdx = i
@ -46,10 +63,7 @@ func WithMultiaddress(multiaddrs ...multiaddr.Multiaddr) ENROption {
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")
}
writeMultiaddressField(localnode, multiaddrs[0:successIdx])
}
return nil
@ -110,15 +124,7 @@ func Update(logger *zap.Logger, localnode *enode.LocalNode, enrOptions ...ENROpt
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")
}
}()
func marshalMultiaddress(addrAggr []multiaddr.Multiaddr) []byte {
var fieldRaw []byte
for _, addr := range addrAggr {
maRaw := addr.Bytes()
@ -128,11 +134,14 @@ func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []multiaddr.Mul
fieldRaw = append(fieldRaw, maSize...)
fieldRaw = append(fieldRaw, maRaw...)
}
localnode.Set(enr.WithEntry(MultiaddrENRField, fieldRaw))
// This is to trigger the signing record err due to exceeding 300bytes limit
_ = localnode.Node()
return nil
return fieldRaw
}
func writeMultiaddressField(localnode *enode.LocalNode, addrAggr []multiaddr.Multiaddr) {
fieldRaw := marshalMultiaddress(addrAggr)
localnode.Set(enr.WithEntry(MultiaddrENRField, fieldRaw))
}
func DeleteField(localnode *enode.LocalNode, field string) {
localnode.Delete(enr.WithEntry(field, struct{}{}))
}

View File

@ -6,25 +6,40 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
wenr "github.com/waku-org/go-waku/waku/v2/protocol/enr"
"github.com/waku-org/go-waku/waku/v2/protocol/peer_exchange/pb"
)
// simpleLRU internal uses container/list, which is ring buffer(double linked list)
type enrCache struct {
// using lru, saves us from periodically cleaning the cache to mauintain a certain size
data *shardLRU
data *shardLRU
clusterID uint16
}
// err on negative size
func newEnrCache(size int) *enrCache {
func newEnrCache(size int, clusterID uint16) *enrCache {
inner := newShardLRU(int(size))
return &enrCache{
data: inner,
data: inner,
clusterID: clusterID,
}
}
// updating cache
func (c *enrCache) updateCache(node *enode.Node) error {
if c.clusterID != 0 {
rs, err := wenr.RelaySharding(node.Record())
if err != nil || rs == nil {
// Node does not contain valid shard information, ignoring...
return nil
}
if rs.ClusterID != c.clusterID {
return nil
}
}
currNode := c.data.Get(node.ID())
if currNode == nil || node.Seq() > currNode.Seq() {
return c.data.Add(node)

View File

@ -54,12 +54,12 @@ type WakuPeerExchange struct {
// NewWakuPeerExchange returns a new instance of WakuPeerExchange struct
// Takes an optional peermanager if WakuPeerExchange is being created along with WakuNode.
// If using libp2p host, then pass peermanager as nil
func NewWakuPeerExchange(disc *discv5.DiscoveryV5, peerConnector PeerConnector, pm *peermanager.PeerManager, reg prometheus.Registerer, log *zap.Logger, opts ...Option) (*WakuPeerExchange, error) {
func NewWakuPeerExchange(disc *discv5.DiscoveryV5, clusterID uint16, peerConnector PeerConnector, pm *peermanager.PeerManager, reg prometheus.Registerer, log *zap.Logger, opts ...Option) (*WakuPeerExchange, error) {
wakuPX := new(WakuPeerExchange)
wakuPX.disc = disc
wakuPX.metrics = newMetrics(reg)
wakuPX.log = log.Named("wakupx")
wakuPX.enrCache = newEnrCache(MaxCacheSize)
wakuPX.enrCache = newEnrCache(MaxCacheSize, clusterID)
wakuPX.peerConnector = peerConnector
wakuPX.pm = pm
wakuPX.CommonService = service.NewCommonService()

2
vendor/modules.txt vendored
View File

@ -1015,7 +1015,7 @@ github.com/waku-org/go-discover/discover/v5wire
github.com/waku-org/go-libp2p-rendezvous
github.com/waku-org/go-libp2p-rendezvous/db
github.com/waku-org/go-libp2p-rendezvous/pb
# github.com/waku-org/go-waku v0.8.1-0.20240626004844-19a47a1ac1f5
# github.com/waku-org/go-waku v0.8.1-0.20240628140035-3604bf39ad28
## explicit; go 1.21
github.com/waku-org/go-waku/logging
github.com/waku-org/go-waku/tests