Update Discv5 to the Latest Version (#3392)

* update workspace

* change to new version

* gaz

* set keys

* try more things

* finally fixed all tests

* fix bootnode

* Update beacon-chain/p2p/discovery.go

Co-Authored-By: Preston Van Loon <preston@prysmaticlabs.com>

* preston's and raul's review

* add http server

* add tool

* add image

* change comment

* add multiaddr comment

* lint

* cosmetic changes

* fix docker

* remove dep

* preston's requested changes
This commit is contained in:
Nishant Das
2019-09-07 00:50:20 +05:30
committed by GitHub
parent 56a395a297
commit 171e5007c5
12 changed files with 310 additions and 116 deletions

View File

@@ -192,7 +192,7 @@ protobuf_deps()
go_repository(
name = "com_github_ethereum_go_ethereum",
commit = "981f27aaf9bdce45391d0cd8bb522df514e0b566",
commit = "8839d2f3b900530fbab26154740e8bded3932a86",
importpath = "github.com/ethereum/go-ethereum",
# Note: go-ethereum is not bazel-friendly with regards to cgo. We have a
# a fork that has resolved these issues by disabling HID/USB support and

View File

@@ -29,7 +29,9 @@ go_library(
"//shared/iputils:go_default_library",
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_ipfs_go_ipfs_addr//:go_default_library",
"@com_github_karlseguin_ccache//:go_default_library",
@@ -59,6 +61,7 @@ go_test(
"service_test.go",
],
embed = [":go_default_library"],
flaky = True,
tags = ["block-network"],
deps = [
"//beacon-chain/p2p/testing:go_default_library",
@@ -66,7 +69,8 @@ go_test(
"//shared/iputils:go_default_library",
"//shared/testutil:go_default_library",
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_gogo_protobuf//proto:go_default_library",
"@com_github_libp2p_go_libp2p//:go_default_library",
"@com_github_libp2p_go_libp2p_core//host:go_default_library",

View File

@@ -4,9 +4,10 @@ import (
"crypto/ecdsa"
"fmt"
"net"
"time"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
iaddr "github.com/ipfs/go-ipfs-addr"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
@@ -16,48 +17,69 @@ import (
// Listener defines the discovery V5 network interface that is used
// to communicate with other peers.
type Listener interface {
Self() *discv5.Node
Self() *enode.Node
Close()
Lookup(discv5.NodeID) []*discv5.Node
ReadRandomNodes([]*discv5.Node) int
SetFallbackNodes([]*discv5.Node) error
Resolve(discv5.NodeID) *discv5.Node
RegisterTopic(discv5.Topic, <-chan struct{})
SearchTopic(discv5.Topic, <-chan time.Duration, chan<- *discv5.Node, chan<- bool)
Lookup(enode.ID) []*enode.Node
ReadRandomNodes([]*enode.Node) int
Resolve(*enode.Node) *enode.Node
LookupRandom() []*enode.Node
Ping(*enode.Node) error
RequestENR(*enode.Node) (*enode.Node, error)
}
func createListener(ipAddr net.IP, port int, privKey *ecdsa.PrivateKey) *discv5.Network {
func createListener(ipAddr net.IP, privKey *ecdsa.PrivateKey, cfg *Config) *discover.UDPv5 {
udpAddr := &net.UDPAddr{
IP: ipAddr,
Port: port,
Port: int(cfg.Port),
}
conn, err := net.ListenUDP("udp4", udpAddr)
if err != nil {
log.Fatal(err)
}
localNode, err := createLocalNode(privKey, ipAddr, int(cfg.Port))
if err != nil {
log.Fatal(err)
}
dv5Cfg := discover.Config{
PrivateKey: privKey,
}
if cfg.BootstrapNodeAddr != "" {
bootNode, err := enode.Parse(enode.ValidSchemes, cfg.BootstrapNodeAddr)
if err != nil {
log.Fatal(err)
}
dv5Cfg.Bootnodes = []*enode.Node{bootNode}
}
network, err := discv5.ListenUDP(privKey, conn, "", nil)
network, err := discover.ListenV5(conn, localNode, dv5Cfg)
if err != nil {
log.Fatal(err)
}
return network
}
func startDiscoveryV5(addr net.IP, privKey *ecdsa.PrivateKey, cfg *Config) (*discv5.Network, error) {
listener := createListener(addr, int(cfg.Port), privKey)
bootNode, err := discv5.ParseNode(cfg.BootstrapNodeAddr)
func createLocalNode(privKey *ecdsa.PrivateKey, ipAddr net.IP, port int) (*enode.LocalNode, error) {
db, err := enode.OpenDB("")
if err != nil {
return nil, err
}
if err := listener.SetFallbackNodes([]*discv5.Node{bootNode}); err != nil {
return nil, err
return nil, errors.Wrap(err, "could not open node's peer database")
}
localNode := enode.NewLocalNode(db, privKey)
ipEntry := enr.IP(ipAddr)
udpEntry := enr.UDP(port)
localNode.Set(ipEntry)
localNode.Set(udpEntry)
return localNode, nil
}
func startDiscoveryV5(addr net.IP, privKey *ecdsa.PrivateKey, cfg *Config) (*discover.UDPv5, error) {
listener := createListener(addr, privKey, cfg)
node := listener.Self()
log.Infof("Started Discovery: %s", node.String())
log.Infof("Started Discovery: %s", node.ID())
return listener, nil
}
func convertToMultiAddr(nodes []*discv5.Node) []ma.Multiaddr {
func convertToMultiAddr(nodes []*enode.Node) []ma.Multiaddr {
var multiAddrs []ma.Multiaddr
for _, node := range nodes {
multiAddr, err := convertToSingleMultiAddr(node)
@@ -70,21 +92,21 @@ func convertToMultiAddr(nodes []*discv5.Node) []ma.Multiaddr {
return multiAddrs
}
func convertToSingleMultiAddr(node *discv5.Node) (ma.Multiaddr, error) {
ip4 := node.IP.To4()
func convertToSingleMultiAddr(node *enode.Node) (ma.Multiaddr, error) {
ip4 := node.IP().To4()
if ip4 == nil {
return nil, errors.New("node doesn't have an ip4 address")
}
pubkey, err := node.ID.Pubkey()
if err != nil {
return nil, errors.Wrap(err, "could not get pubkey from node ID")
}
pubkey := node.Pubkey()
assertedKey := convertToInterfacePubkey(pubkey)
id, err := peer.IDFromPublicKey(assertedKey)
if err != nil {
return nil, errors.Wrap(err, "could not get peer id")
}
multiAddrString := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ip4.String(), node.TCP, id)
// we use the udp port for now, since all udp and tcp connections occur from the same
// port. This will be changed to the node's TCP port in the future, when we allow a
// beacon node to provide separate TCP and UDP ports.
multiAddrString := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", ip4.String(), node.UDP(), id)
multiAddr, err := ma.NewMultiaddr(multiAddrString)
if err != nil {
return nil, errors.Wrap(err, "could not get multiaddr")

View File

@@ -2,20 +2,21 @@ package p2p
import (
"crypto/ecdsa"
"crypto/rand"
"fmt"
"net"
"testing"
"time"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/libp2p/go-libp2p-core/host"
"github.com/prysmaticlabs/prysm/shared/iputils"
"github.com/prysmaticlabs/prysm/shared/testutil"
logTest "github.com/sirupsen/logrus/hooks/test"
)
var discoveryWaitTime = 1 * time.Second
func createAddrAndPrivKey(t *testing.T) (net.IP, *ecdsa.PrivateKey) {
ip, err := iputils.ExternalIPv4()
if err != nil {
@@ -32,20 +33,17 @@ func createAddrAndPrivKey(t *testing.T) (net.IP, *ecdsa.PrivateKey) {
func TestCreateListener(t *testing.T) {
port := 1024
ipAddr, pkey := createAddrAndPrivKey(t)
listener := createListener(ipAddr, port, pkey)
listener := createListener(ipAddr, pkey, &Config{Port: uint(port)})
defer listener.Close()
if !listener.Self().IP.Equal(ipAddr) {
t.Errorf("Ip address is not the expected type, wanted %s but got %s", ipAddr.String(), listener.Self().IP.String())
if !listener.Self().IP().Equal(ipAddr) {
t.Errorf("Ip address is not the expected type, wanted %s but got %s", ipAddr.String(), listener.Self().IP().String())
}
if port != int(listener.Self().UDP) {
t.Errorf("In correct port number, wanted %d but got %d", port, listener.Self().UDP)
}
pubkey, err := listener.Self().ID.Pubkey()
if err != nil {
t.Error(err)
if port != int(listener.Self().UDP()) {
t.Errorf("In correct port number, wanted %d but got %d", port, listener.Self().UDP())
}
pubkey := listener.Self().Pubkey()
XisSame := pkey.PublicKey.X.Cmp(pubkey.X) == 0
YisSame := pkey.PublicKey.Y.Cmp(pubkey.Y) == 0
@@ -57,20 +55,19 @@ func TestCreateListener(t *testing.T) {
func TestStartDiscV5_DiscoverAllPeers(t *testing.T) {
port := 2000
ipAddr, pkey := createAddrAndPrivKey(t)
bootListener := createListener(ipAddr, port, pkey)
bootListener := createListener(ipAddr, pkey, &Config{Port: uint(port)})
defer bootListener.Close()
bootNode := bootListener.Self()
cfg := &Config{
BootstrapNodeAddr: bootNode.String(),
Encoding: "ssz",
}
var listeners []*discv5.Network
var listeners []*discover.UDPv5
for i := 1; i <= 5; i++ {
port = 2000 + i
cfg.UDPPort = uint(port)
port = 3000 + i
cfg.Port = uint(port)
ipAddr, pkey := createAddrAndPrivKey(t)
listener, err := startDiscoveryV5(ipAddr, pkey, cfg)
if err != nil {
@@ -80,13 +77,13 @@ func TestStartDiscV5_DiscoverAllPeers(t *testing.T) {
}
// Wait for the nodes to have their local routing tables to be populated with the other nodes
time.Sleep(100 * time.Millisecond)
time.Sleep(discoveryWaitTime)
lastListener := listeners[len(listeners)-1]
nodes := lastListener.Lookup(bootNode.ID)
if len(nodes) != 6 {
nodes := lastListener.Lookup(bootNode.ID())
if len(nodes) < 4 {
t.Errorf("The node's local table doesn't have the expected number of nodes. "+
"Expected %d but got %d", 6, len(nodes))
"Expected more than or equal to %d but got %d", 4, len(nodes))
}
// Close all ports
@@ -98,24 +95,21 @@ func TestStartDiscV5_DiscoverAllPeers(t *testing.T) {
func TestMultiAddrsConversion_InvalidIPAddr(t *testing.T) {
hook := logTest.NewGlobal()
ipAddr := net.IPv6zero
pkey, err := ecdsa.GenerateKey(crypto.S256(), rand.Reader)
_, pkey := createAddrAndPrivKey(t)
node, err := createLocalNode(pkey, ipAddr, 0)
if err != nil {
t.Fatalf("Could not generate key %v", err)
t.Fatal(err)
}
nodeID := discv5.PubkeyID(&pkey.PublicKey)
node := discv5.NewNode(nodeID, ipAddr, 0, 0)
_ = convertToMultiAddr([]*discv5.Node{node})
_ = convertToMultiAddr([]*enode.Node{node.Node()})
testutil.AssertLogsContain(t, hook, "node doesn't have an ip4 address")
}
func TestMultiAddrConversion_OK(t *testing.T) {
hook := logTest.NewGlobal()
port := 1024
ipAddr, pkey := createAddrAndPrivKey(t)
listener := createListener(ipAddr, port, pkey)
listener := createListener(ipAddr, pkey, &Config{})
_ = convertToMultiAddr([]*discv5.Node{listener.Self()})
_ = convertToMultiAddr([]*enode.Node{listener.Self()})
testutil.AssertLogsDoNotContain(t, hook, "Node doesn't have an ip4 address")
testutil.AssertLogsDoNotContain(t, hook, "Invalid port, the tcp port of the node is a reserved port")
testutil.AssertLogsDoNotContain(t, hook, "Could not get multiaddr")

View File

@@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/karlseguin/ccache"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/host"
@@ -92,7 +92,6 @@ func (s *Service) Start() {
if s.cfg.BootstrapNodeAddr != "" && !s.cfg.NoDiscovery {
ipAddr := ipAddr(s.cfg)
listener, err := startDiscoveryV5(ipAddr, s.privKey, s.cfg)
if err != nil {
log.WithError(err).Error("Failed to start discovery")
@@ -184,13 +183,12 @@ func (s *Service) Disconnect(pid peer.ID) error {
// listen for new nodes watches for new nodes in the network and adds them to the peerstore.
func (s *Service) listenForNewNodes() {
nodes := make([]*discv5.Node, 10)
ticker := time.NewTicker(pollingPeriod)
for {
select {
case <-ticker.C:
num := s.dv5Listener.ReadRandomNodes(nodes)
multiAddresses := convertToMultiAddr(nodes[:num])
nodes := s.dv5Listener.LookupRandom()
multiAddresses := convertToMultiAddr(nodes)
s.connectWithAllPeers(multiAddresses)
case <-s.ctx.Done():
log.Debug("p2p context is closed, exiting routine")
@@ -221,7 +219,7 @@ func (s *Service) connectWithAllPeers(multiAddrs []ma.Multiaddr) {
}
func (s *Service) addBootNodeToExclusionList() error {
bootNode, err := discv5.ParseNode(s.cfg.BootstrapNodeAddr)
bootNode, err := enode.Parse(enode.ValidSchemes, s.cfg.BootstrapNodeAddr)
if err != nil {
return err
}

View File

@@ -8,7 +8,8 @@ import (
"testing"
"time"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
libp2p "github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
@@ -19,35 +20,35 @@ import (
type mockListener struct{}
func (m *mockListener) Self() *discv5.Node {
func (mockListener) Self() *enode.Node {
panic("implement me")
}
func (m *mockListener) Close() {
func (mockListener) Close() {
//no-op
}
func (m *mockListener) Lookup(discv5.NodeID) []*discv5.Node {
func (mockListener) Lookup(enode.ID) []*enode.Node {
panic("implement me")
}
func (m *mockListener) ReadRandomNodes([]*discv5.Node) int {
func (mockListener) ReadRandomNodes([]*enode.Node) int {
panic("implement me")
}
func (m *mockListener) SetFallbackNodes([]*discv5.Node) error {
func (mockListener) Resolve(*enode.Node) *enode.Node {
panic("implement me")
}
func (m *mockListener) Resolve(discv5.NodeID) *discv5.Node {
func (mockListener) LookupRandom() []*enode.Node {
panic("implement me")
}
func (m *mockListener) RegisterTopic(discv5.Topic, <-chan struct{}) {
func (mockListener) Ping(*enode.Node) error {
panic("implement me")
}
func (m *mockListener) SearchTopic(discv5.Topic, <-chan time.Duration, chan<- *discv5.Node, chan<- bool) {
func (mockListener) RequestENR(*enode.Node) (*enode.Node, error) {
panic("implement me")
}
@@ -121,24 +122,26 @@ func TestService_Status_NotRunning(t *testing.T) {
func TestListenForNewNodes(t *testing.T) {
// setup bootnode
cfg := &Config{}
port := 2000
cfg.Port = uint(port)
_, pkey := createAddrAndPrivKey(t)
ipAddr := net.ParseIP("127.0.0.1")
bootListener := createListener(ipAddr, port, pkey)
bootListener := createListener(ipAddr, pkey, cfg)
defer bootListener.Close()
bootNode := bootListener.Self()
cfg := &Config{
cfg = &Config{
BootstrapNodeAddr: bootNode.String(),
Encoding: "ssz",
}
var listeners []*discv5.Network
var listeners []*discover.UDPv5
var hosts []host.Host
// setup other nodes
for i := 1; i <= 5; i++ {
listener, h := createPeer(t, cfg, port+i)
listeners = append(listeners, listener.(*discv5.Network))
listeners = append(listeners, listener.(*discover.UDPv5))
hosts = append(hosts, h)
}
@@ -160,7 +163,7 @@ func TestListenForNewNodes(t *testing.T) {
s.Start()
defer s.Stop()
time.Sleep(2 * time.Second)
time.Sleep(4 * time.Second)
peers := s.host.Network().Peers()
if len(peers) != 5 {
t.Errorf("Not all peers added to peerstore, wanted %d but got %d", 5, len(peers))

View File

@@ -11,8 +11,11 @@ go_library(
deps = [
"//shared/version:go_default_library",
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
],
@@ -32,8 +35,11 @@ go_image(
deps = [
"//shared/version:go_default_library",
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
],
@@ -64,10 +70,12 @@ go_test(
name = "go_default_test",
srcs = ["bootnode_test.go"],
embed = [":go_default_library"],
flaky = True,
deps = [
"//shared/iputils:go_default_library",
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/discover:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
],

View File

@@ -17,8 +17,11 @@ import (
"net"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/version"
"github.com/sirupsen/logrus"
_ "go.uber.org/automaxprocs"
@@ -28,7 +31,7 @@ var (
debug = flag.Bool("debug", false, "Enable debug logging")
privateKey = flag.String("private", "", "Private key to use for peer ID")
port = flag.Int("port", 4000, "Port to listen for connections")
externalIP = flag.String("external-ip", "0.0.0.0", "External IP for the bootnode")
externalIP = flag.String("external-ip", "127.0.0.1", "External IP for the bootnode")
log = logrus.WithField("prefix", "bootnode")
)
@@ -41,37 +44,57 @@ func main() {
if *debug {
logrus.SetLevel(logrus.DebugLevel)
}
privKey := extractPrivateKey()
listener := createListener(*externalIP, *port, privKey)
cfg := discover.Config{
PrivateKey: extractPrivateKey(),
}
listener := createListener(*externalIP, *port, cfg)
node := listener.Self()
log.Infof("Running bootnode, url: %s", node.String())
log.Infof("Running bootnode: %s", node.String())
select {}
}
func createListener(ipAddr string, port int, privKey *ecdsa.PrivateKey) *discv5.Network {
func createListener(ipAddr string, port int, cfg discover.Config) *discover.UDPv5 {
ip := net.ParseIP(ipAddr)
if ip.To4() == nil {
log.Fatalf("IPV4 address not provided instead %s was provided", ipAddr)
}
udpAddr := &net.UDPAddr{
IP: net.ParseIP(ipAddr),
IP: ip,
Port: port,
}
conn, err := net.ListenUDP("udp4", udpAddr)
if err != nil {
log.Fatal(err)
}
localNode, err := createLocalNode(cfg.PrivateKey, ip, port)
if err != nil {
log.Fatal(err)
}
network, err := discv5.ListenUDP(privKey, conn, "", nil)
network, err := discover.ListenV5(conn, localNode, cfg)
if err != nil {
log.Fatal(err)
}
return network
}
func createLocalNode(privKey *ecdsa.PrivateKey, ipAddr net.IP, port int) (*enode.LocalNode, error) {
db, err := enode.OpenDB("")
if err != nil {
return nil, errors.Wrap(err, "Could not open node's peer database")
}
localNode := enode.NewLocalNode(db, privKey)
ipEntry := enr.IP(ipAddr)
udpEntry := enr.UDP(port)
localNode.Set(ipEntry)
localNode.Set(udpEntry)
return localNode, nil
}
func extractPrivateKey() *ecdsa.PrivateKey {
var privKey *ecdsa.PrivateKey
if *privateKey != "" {

View File

@@ -4,9 +4,11 @@ import (
"crypto/ecdsa"
"crypto/rand"
"testing"
"time"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/prysmaticlabs/prysm/shared/iputils"
_ "go.uber.org/automaxprocs"
@@ -17,44 +19,43 @@ func TestBootnode_OK(t *testing.T) {
if err != nil {
t.Fatal(err)
}
privKey := extractPrivateKey()
listener := createListener(ipAddr, 4000, privKey)
cfg := discover.Config{
PrivateKey: extractPrivateKey(),
}
listener := createListener(ipAddr, 4000, cfg)
defer listener.Close()
privKey = extractPrivateKey()
listener2 := createListener(ipAddr, 4001, privKey)
defer listener.Close()
err = listener.SetFallbackNodes([]*discv5.Node{listener2.Self()})
if err != nil {
t.Fatal(err)
}
err = listener2.SetFallbackNodes([]*discv5.Node{listener.Self()})
cfg.PrivateKey = extractPrivateKey()
bootNode, err := enode.Parse(enode.ValidSchemes, listener.Self().String())
if err != nil {
t.Fatal(err)
}
cfg.Bootnodes = []*enode.Node{bootNode}
listener2 := createListener(ipAddr, 4001, cfg)
defer listener2.Close()
// test that both the nodes have the other peer stored in their local table.
listenerNode := listener.Self()
listenerNode2 := listener2.Self()
nodes := listener.Lookup(listenerNode2.ID)
if len(nodes) != 2 {
t.Errorf("Length of nodes stored in table is not expected. Wanted %d but got %d", 2, len(nodes))
time.Sleep(1 * time.Second)
nodes := listener.Lookup(listenerNode2.ID())
if len(nodes) == 0 {
t.Fatalf("Length of nodes stored in table is not expected. Wanted to be more than %d but got %d", 0, len(nodes))
}
if nodes[0].ID != listenerNode2.ID {
t.Errorf("Wanted node ID of %s but got %s", listenerNode2.ID, nodes[1].ID)
if nodes[0].ID() != listenerNode2.ID() {
t.Errorf("Wanted node ID of %s but got %s", listenerNode2.ID(), nodes[1].ID())
}
nodes = listener2.Lookup(listenerNode.ID)
if len(nodes) != 2 {
t.Errorf("Length of nodes stored in table is not expected. Wanted %d but got %d", 2, len(nodes))
nodes = listener2.Lookup(listenerNode.ID())
if len(nodes) == 0 {
t.Errorf("Length of nodes stored in table is not expected. Wanted to be more than %d but got %d", 0, len(nodes))
}
if nodes[0].ID != listenerNode.ID {
t.Errorf("Wanted node ID of %s but got %s", listenerNode.ID, nodes[1].ID)
if nodes[0].ID() != listenerNode.ID() {
t.Errorf("Wanted node ID of %s but got %s", listenerNode.ID(), nodes[1].ID())
}
}

View File

@@ -0,0 +1,61 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
load("@io_bazel_rules_docker//container:container.bzl", "container_bundle")
load("@io_bazel_rules_docker//contrib:push-all.bzl", "docker_push")
go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "github.com/prysmaticlabs/prysm/tools/enr-calculator",
visibility = ["//visibility:private"],
deps = [
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
],
)
go_binary(
name = "enr-calculator",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
go_image(
name = "image",
srcs = ["main.go"],
goarch = "amd64",
goos = "linux",
importpath = "github.com/prysmaticlabs/prysm/tools/enr-calculator",
pure = "on",
race = "off",
static = "on",
tags = ["manual"],
visibility = ["//visibility:private"],
deps = [
"@com_github_btcsuite_btcd//btcec:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enode:go_default_library",
"@com_github_ethereum_go_ethereum//p2p/enr:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
],
)
container_bundle(
name = "image_bundle",
images = {
"gcr.io/prysmaticlabs/prysm/enr-calculator:latest": ":image",
"gcr.io/prysmaticlabs/prysm/enr-calculator:{DOCKER_TAG}": ":image",
},
tags = ["manual"],
)
docker_push(
name = "push_images",
bundle = ":image_bundle",
tags = ["manual"],
)

View File

@@ -0,0 +1,16 @@
# ENR Calculator
To generate the ENR of a node
```
bazel run //tools/enr-calculator:enr-calculator -- --private CAISIJXSWjkbgprwuo01QCRegULoNIOZ0yTl1fLz5N0SsJCS --ipAddress 127.0.0.1 --port 2000
```
This will deterministically generate an ENR from given inputs of private key, ip address and udp port.
Output of the above command:
```
INFO[0000] enr:-IS4QKk3gX9EqxA3x83AbCiyAnSuPDMvK52dC50Hm1XGDd5tEyQhM3VcJL-4b8kDg5APz_povv0Syqk0nancoNW-cq0BgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQM1E5yUsp9vDQj1tv3ZWXCvaFBvrPNdz8KPI1NhxfQWzIN1ZHCCB9A
```

View File

@@ -0,0 +1,64 @@
// This binary is a simple rest API endpoint to calculate
// the ENR value of a node given its private key,ip address and port.
package main
import (
"crypto/ecdsa"
"flag"
"net"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/libp2p/go-libp2p-core/crypto"
log "github.com/sirupsen/logrus"
_ "go.uber.org/automaxprocs"
)
var (
privateKey = flag.String("private", "", "Base-64 encoded Private key to use for calculation of ENR")
port = flag.Int("port", 0, "Port to use for calculation of ENR")
ipAddr = flag.String("ipAddress", "", "IP to use in calculation of ENR")
)
func main() {
flag.Parse()
if len(*privateKey) == 0 {
log.Fatal("No private key given")
}
decodedKey, err := crypto.ConfigDecodeKey(*privateKey)
if err != nil {
log.Fatalf("Unable to decode private key: %v\n", err)
}
privatekey, err := crypto.UnmarshalPrivateKey(decodedKey)
if err != nil {
log.Fatalf("Unable to unmarshal private key: %v\n", err)
}
ecdsaPrivKey := (*ecdsa.PrivateKey)((*btcec.PrivateKey)(privatekey.(*crypto.Secp256k1PrivateKey)))
if net.ParseIP(*ipAddr).To4() == nil {
log.Fatalf("Invalid ipv4 address given: %v\n", err)
}
if *port == 0 {
log.Fatalf("Invalid udp port given: %v\n", err)
return
}
db, err := enode.OpenDB("")
defer db.Close()
if err != nil {
log.Fatalf("Could not open node's peer database: %v\n", err)
return
}
localNode := enode.NewLocalNode(db, ecdsaPrivKey)
ipEntry := enr.IP(net.ParseIP(*ipAddr))
udpEntry := enr.UDP(*port)
localNode.Set(ipEntry)
localNode.Set(udpEntry)
log.Info(localNode.Node().String())
}