mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
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:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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 != "" {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
61
tools/enr-calculator/BUILD.bazel
Normal file
61
tools/enr-calculator/BUILD.bazel
Normal 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"],
|
||||
)
|
||||
16
tools/enr-calculator/README.md
Normal file
16
tools/enr-calculator/README.md
Normal 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
|
||||
|
||||
```
|
||||
64
tools/enr-calculator/main.go
Normal file
64
tools/enr-calculator/main.go
Normal 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())
|
||||
}
|
||||
Reference in New Issue
Block a user