mirror of https://github.com/status-im/go-waku.git
131 lines
3.4 KiB
Go
131 lines
3.4 KiB
Go
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 {
|
|
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
|
|
}
|