mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
Change BootNode to use Discv5 instead of Kademlia (#3203)
* add new test * specify ecdsa keygen * skip test * fix ref * comment again * fix test and clean up * gaz * change to another format * Apply suggestions from code review Co-Authored-By: Preston Van Loon <preston@prysmaticlabs.com> * fix docker build * add close
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
|
||||
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")
|
||||
@@ -10,15 +10,10 @@ go_library(
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//shared/version:go_default_library",
|
||||
"@com_github_ipfs_go_datastore//:go_default_library",
|
||||
"@com_github_ipfs_go_datastore//sync:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
|
||||
"@com_github_ipfs_go_log//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_crypto//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_kad_dht//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_kad_dht//opts:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_protocol//:go_default_library",
|
||||
"@com_github_multiformats_go_multiaddr//:go_default_library",
|
||||
"@org_uber_go_automaxprocs//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -36,15 +31,10 @@ go_image(
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//shared/version:go_default_library",
|
||||
"@com_github_ipfs_go_datastore//:go_default_library",
|
||||
"@com_github_ipfs_go_datastore//sync:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//crypto:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
|
||||
"@com_github_ipfs_go_log//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_crypto//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_kad_dht//:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_kad_dht//opts:go_default_library",
|
||||
"@com_github_libp2p_go_libp2p_protocol//:go_default_library",
|
||||
"@com_github_multiformats_go_multiaddr//:go_default_library",
|
||||
"@org_uber_go_automaxprocs//:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -69,3 +59,14 @@ docker_push(
|
||||
bundle = ":image_bundle",
|
||||
tags = ["manual"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["bootnode_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//shared/iputils:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//p2p/discv5:go_default_library",
|
||||
"@org_uber_go_automaxprocs//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Bootnode
|
||||
*
|
||||
* A simple peer Kademlia distributed hash table (DHT) service for peer
|
||||
* A node which implements the DiscoveryV5 protocol for peer
|
||||
* discovery. The purpose of this service is to provide a starting point for
|
||||
* newly connected services to find other peers outside of their network.
|
||||
*
|
||||
@@ -10,19 +10,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
curve "github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
|
||||
ds "github.com/ipfs/go-datastore"
|
||||
dsync "github.com/ipfs/go-datastore/sync"
|
||||
logging "github.com/ipfs/go-log"
|
||||
libp2p "github.com/libp2p/go-libp2p"
|
||||
crypto "github.com/libp2p/go-libp2p-crypto"
|
||||
kaddht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
|
||||
protocol "github.com/libp2p/go-libp2p-protocol"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
_ "go.uber.org/automaxprocs"
|
||||
)
|
||||
@@ -35,7 +34,8 @@ var (
|
||||
log = logging.Logger("prysm-bootnode")
|
||||
)
|
||||
|
||||
const dhtProtocol = "/prysm/0.0.0/dht"
|
||||
// ECDSACurve is the default ecdsa curve used(secpk2561)
|
||||
var ECDSACurve = curve.S256()
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
@@ -46,56 +46,53 @@ func main() {
|
||||
logging.SetDebugLogging()
|
||||
}
|
||||
|
||||
listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *port))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to construct new multiaddress. %v", err)
|
||||
}
|
||||
defaultIP := "0.0.0.0"
|
||||
|
||||
opts := []libp2p.Option{
|
||||
libp2p.ListenAddrs(listen),
|
||||
}
|
||||
opts = addPrivateKeyOpt(opts)
|
||||
privKey := extractPrivateKey()
|
||||
listener := createListener(defaultIP, *port, privKey)
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
host, err := libp2p.New(ctx, opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create new host. %v", err)
|
||||
}
|
||||
|
||||
dopts := []dhtopts.Option{
|
||||
dhtopts.Datastore(dsync.MutexWrap(ds.NewMapDatastore())),
|
||||
dhtopts.Protocols(
|
||||
protocol.ID(dhtProtocol),
|
||||
),
|
||||
}
|
||||
|
||||
dht, err := kaddht.New(ctx, host, dopts...)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create new dht: %v", err)
|
||||
}
|
||||
if err := dht.Bootstrap(context.Background()); err != nil {
|
||||
log.Fatalf("Failed to bootstrap DHT. %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Running bootnode: /ip4/0.0.0.0/tcp/%d/p2p/%s\n", *port, host.ID().Pretty())
|
||||
node := listener.Self()
|
||||
fmt.Printf("Running bootnode: /ip4/%s/udp/%d/discv5/%s\n", node.IP.String(), node.UDP, node.ID.String())
|
||||
|
||||
select {}
|
||||
}
|
||||
|
||||
func addPrivateKeyOpt(opts []libp2p.Option) []libp2p.Option {
|
||||
func createListener(ipAddr string, port int, privKey *ecdsa.PrivateKey) *discv5.Network {
|
||||
udpAddr := &net.UDPAddr{
|
||||
IP: net.ParseIP(ipAddr),
|
||||
Port: port,
|
||||
}
|
||||
conn, err := net.ListenUDP("udp4", udpAddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
network, err := discv5.ListenUDP(privKey, conn, "", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return network
|
||||
}
|
||||
|
||||
func extractPrivateKey() *ecdsa.PrivateKey {
|
||||
var privKey *ecdsa.PrivateKey
|
||||
var err error
|
||||
if *privateKey != "" {
|
||||
b, err := crypto.ConfigDecodeKey(*privateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pk, err := crypto.UnmarshalPrivateKey(b)
|
||||
privKey, err = x509.ParseECPrivateKey(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
opts = append(opts, libp2p.Identity(pk))
|
||||
|
||||
} else {
|
||||
privKey, err = ecdsa.GenerateKey(ECDSACurve, rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.Warning("No private key was provided. Using default/random private key")
|
||||
}
|
||||
return opts
|
||||
return privKey
|
||||
}
|
||||
|
||||
55
tools/bootnode/bootnode_test.go
Normal file
55
tools/bootnode/bootnode_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
"github.com/prysmaticlabs/prysm/shared/iputils"
|
||||
_ "go.uber.org/automaxprocs"
|
||||
)
|
||||
|
||||
func TestBootnode_OK(t *testing.T) {
|
||||
ipAddr, err := iputils.ExternalIPv4()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
privKey := extractPrivateKey()
|
||||
listener := createListener(ipAddr, 4000, privKey)
|
||||
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()})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
||||
}
|
||||
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))
|
||||
|
||||
}
|
||||
if nodes[0].ID != listenerNode.ID {
|
||||
t.Errorf("Wanted node ID of %s but got %s", listenerNode.ID, nodes[1].ID)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user