mirror of
https://github.com/waku-org/test-discv5.git
synced 2025-01-11 21:44:34 +00:00
285 lines
6.3 KiB
Go
285 lines
6.3 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/p2p/dnsdisc"
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
"github.com/waku-org/go-discover/discover"
|
|
wenr "github.com/waku-org/go-waku/waku/v2/protocol/enr"
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/filter"
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/lightpush"
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/relay"
|
|
"github.com/waku-org/go-waku/waku/v2/protocol/store"
|
|
)
|
|
|
|
func main() {
|
|
var portFlag = flag.Int("port", 6000, "port number")
|
|
var bootnodeFlag = flag.String("bootnodes", "", "comma separated bootnodes")
|
|
var dnsdiscFlag = flag.String("dns-disc-url", "", "DNS discovery URL")
|
|
|
|
flag.Parse()
|
|
|
|
db, err := enode.OpenDB("")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ip := GetLocalIP()
|
|
|
|
priv, _ := crypto.GenerateKey()
|
|
localnode := enode.NewLocalNode(db, priv)
|
|
localnode.SetFallbackIP(ip)
|
|
|
|
var protocolID = [6]byte{'d', '5', 'w', 'a', 'k', 'u'}
|
|
|
|
bootnodesStr := strings.Split(*bootnodeFlag, ",")
|
|
var bootnodes []*enode.Node
|
|
|
|
for _, addr := range bootnodesStr {
|
|
if addr == "" {
|
|
continue
|
|
}
|
|
bootnode, err := enode.Parse(enode.ValidSchemes, addr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
bootnodes = append(bootnodes, bootnode)
|
|
}
|
|
|
|
if *dnsdiscFlag != "" {
|
|
c := dnsdisc.NewClient(dnsdisc.Config{})
|
|
tree, err := c.SyncTree(*dnsdiscFlag)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
bootnodes = append(bootnodes, tree.Nodes()...)
|
|
}
|
|
|
|
config := discover.Config{
|
|
PrivateKey: priv,
|
|
Bootnodes: bootnodes,
|
|
V5Config: discover.V5Config{
|
|
ProtocolID: &protocolID,
|
|
},
|
|
}
|
|
|
|
udpAddr := &net.UDPAddr{
|
|
IP: ip,
|
|
Port: *portFlag,
|
|
}
|
|
|
|
conn, err := net.ListenUDP("udp", udpAddr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
udpAddr = conn.LocalAddr().(*net.UDPAddr)
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
if !udpAddr.IP.IsLoopback() {
|
|
go func() {
|
|
nat.Map(nat.Any(), ctx.Done(), "udp", udpAddr.Port, udpAddr.Port, "test discv5 discovery")
|
|
}()
|
|
}
|
|
|
|
localnode.SetFallbackUDP(udpAddr.Port)
|
|
|
|
fmt.Println("Your node:")
|
|
fmt.Println(localnode.Node())
|
|
listener, err := discover.ListenV5(conn, localnode, config)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if len(bootnodes) > 0 {
|
|
fmt.Println("\nBootnodes:")
|
|
for i, b := range bootnodes {
|
|
fmt.Println(i+1, "-", b.String())
|
|
}
|
|
}
|
|
|
|
peerDelay := 50 * time.Millisecond
|
|
bucketSize := 15
|
|
|
|
fmt.Println("\nDiscovered peers:")
|
|
fmt.Println("===============================================================================")
|
|
|
|
go func() {
|
|
iterator := listener.RandomNodes()
|
|
seen := make(map[enode.ID]*enode.Node)
|
|
peerCnt := 0
|
|
for iterator.Next() {
|
|
|
|
start := time.Now()
|
|
hasNext := iterator.Next()
|
|
if !hasNext {
|
|
break
|
|
}
|
|
elapsed := time.Since(start)
|
|
|
|
if elapsed < peerDelay {
|
|
t := time.NewTimer(peerDelay - elapsed)
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-t.C:
|
|
t.Stop()
|
|
}
|
|
}
|
|
|
|
// Delay every 15 peers being returned
|
|
peerCnt++
|
|
if peerCnt == bucketSize {
|
|
peerCnt = 0
|
|
t := time.NewTimer(5 * time.Second)
|
|
fmt.Println("Waiting 5 secs...")
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-t.C:
|
|
t.Stop()
|
|
fmt.Println("Attempting to discover more peers")
|
|
}
|
|
}
|
|
|
|
node := iterator.Node()
|
|
_ = node
|
|
n, ok := seen[node.ID()]
|
|
|
|
recType := "NEW"
|
|
|
|
if ok {
|
|
if node.Seq() > n.Seq() {
|
|
seen[node.ID()] = node
|
|
recType = "UPDATE"
|
|
} else {
|
|
continue
|
|
}
|
|
} else {
|
|
seen[node.ID()] = node
|
|
}
|
|
|
|
fmt.Println(len(seen), "-", recType, "-", node.String())
|
|
|
|
peerID, multiaddresses, err := wenr.Multiaddress(node)
|
|
if err == nil {
|
|
fmt.Println("peerID", peerID)
|
|
if len(multiaddresses) > 0 {
|
|
fmt.Println("multiaddr:", multiaddresses)
|
|
} else {
|
|
fmt.Println("multiaddr: field contains no value")
|
|
}
|
|
} else {
|
|
fmt.Println("multiaddr:", err.Error())
|
|
}
|
|
|
|
fmt.Println(fmt.Sprintf("ip %s:%d", node.IP(), node.TCP()))
|
|
shards, err := wenr.RelaySharding(node.Record())
|
|
if err != nil {
|
|
fmt.Println("rs/rsv:", "field contains no value")
|
|
}
|
|
if shards != nil {
|
|
fmt.Println("cluster-id: ", shards.ClusterID)
|
|
fmt.Println("shards: ", shards.ShardIDs)
|
|
} else {
|
|
fmt.Println("cluster-id:", "not available")
|
|
fmt.Println("shards:", "not available")
|
|
}
|
|
DecodeWaku2ENRField(node.Record())
|
|
fmt.Println()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
}
|
|
}
|
|
iterator.Close()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
default:
|
|
}
|
|
}()
|
|
|
|
// Wait for a SIGINT or SIGTERM signal
|
|
ch := make(chan os.Signal, 1)
|
|
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
|
<-ch
|
|
fmt.Println("\n\n\nshutting down...")
|
|
|
|
cancel()
|
|
|
|
}
|
|
|
|
func ReadValue(record *enr.Record, name string) ([]byte, error) {
|
|
var field []byte
|
|
if err := record.Load(enr.WithEntry(name, &field)); err != nil {
|
|
if enr.IsNotFound(err) {
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
return field, nil
|
|
}
|
|
|
|
// GetLocalIP returns the non loopback local IP of the host
|
|
func GetLocalIP() net.IP {
|
|
addrs, err := net.InterfaceAddrs()
|
|
if err != nil {
|
|
return net.IPv4zero
|
|
}
|
|
for _, address := range addrs {
|
|
// check the address type and if it is not a loopback the display it
|
|
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
if ipnet.IP.To4() != nil {
|
|
return ipnet.IP
|
|
}
|
|
}
|
|
}
|
|
return net.IPv4zero
|
|
}
|
|
|
|
func DecodeWaku2ENRField(record *enr.Record) {
|
|
//Decoding Waku2 field
|
|
var enrField wenr.WakuEnrBitfield
|
|
var protosSupported []string
|
|
if err := record.Load(enr.WithEntry("waku2", &enrField)); err != nil {
|
|
if enr.IsNotFound(err) {
|
|
fmt.Println("waku2:", "field contains no value")
|
|
} else {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
if enrField&relay.WakuRelayENRField != 0 {
|
|
protosSupported = append(protosSupported, string(relay.WakuRelayID_v200))
|
|
}
|
|
if enrField&filter.FilterSubscribeENRField != 0 {
|
|
protosSupported = append(protosSupported, string(filter.FilterSubscribeID_v20beta1))
|
|
}
|
|
if enrField&lightpush.LightPushENRField != 0 {
|
|
protosSupported = append(protosSupported, string(lightpush.LightPushID_v20beta1))
|
|
}
|
|
if enrField&store.StoreENRField != 0 {
|
|
protosSupported = append(protosSupported, string(store.StoreID_v20beta4))
|
|
}
|
|
fmt.Println("Wakuv2 Protocols Supported:")
|
|
for _, proto := range protosSupported {
|
|
fmt.Println(proto)
|
|
}
|
|
}
|