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:
Nishant Das
2019-08-19 01:24:20 +05:30
committed by GitHub
parent a26ef9b44f
commit 16c5d96e6a
3 changed files with 113 additions and 60 deletions

View File

@@ -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",
],
)

View File

@@ -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
}

View 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)
}
}