Add Back Kademlia DHT to Prysm (#3557)

* serve nodes

* remove testing flag

* add back bootnode

* add dht

* add back dht

* gaz

* fix build

* bootnode works in runtime

* fix all references

* all tests pass

* remove feature flag

* separate out ports

* lint

* fix docker build

* use one error package
This commit is contained in:
Nishant Das
2019-09-23 22:54:16 +05:30
committed by Preston Van Loon
parent 5294a6c5af
commit b5b10a8d35
23 changed files with 265 additions and 97 deletions

View File

@@ -218,19 +218,21 @@ func (b *BeaconNode) startDB(ctx *cli.Context) error {
func (b *BeaconNode) registerP2P(ctx *cli.Context) error {
// Bootnode ENR may be a filepath to an ENR file.
bootnodeENR := ctx.GlobalString(cmd.BootstrapNode.Name)
if filepath.Ext(bootnodeENR) == ".enr" {
b, err := ioutil.ReadFile(bootnodeENR)
if err != nil {
return err
bootnodeAddrs := sliceutil.SplitCommaSeparated(ctx.GlobalStringSlice(cmd.BootstrapNode.Name))
for i, addr := range bootnodeAddrs {
if filepath.Ext(addr) == ".enr" {
b, err := ioutil.ReadFile(addr)
if err != nil {
return err
}
bootnodeAddrs[i] = string(b)
}
bootnodeENR = string(b)
}
svc, err := p2p.NewService(&p2p.Config{
NoDiscovery: ctx.GlobalBool(cmd.NoDiscovery.Name),
StaticPeers: sliceutil.SplitCommaSeparated(ctx.GlobalStringSlice(cmd.StaticPeers.Name)),
BootstrapNodeAddr: bootnodeENR,
BootstrapNodeAddr: bootnodeAddrs,
RelayNodeAddr: ctx.GlobalString(cmd.RelayNode.Name),
DataDir: ctx.GlobalString(cmd.DataDirFlag.Name),
HostAddress: ctx.GlobalString(cmd.P2PHost.Name),

View File

@@ -32,14 +32,20 @@ go_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_datastore//:go_default_library",
"@com_github_ipfs_go_datastore//sync:go_default_library",
"@com_github_ipfs_go_ipfs_addr//:go_default_library",
"@com_github_karlseguin_ccache//:go_default_library",
"@com_github_libp2p_go_libp2p//:go_default_library",
"@com_github_libp2p_go_libp2p//p2p/host/routed:go_default_library",
"@com_github_libp2p_go_libp2p_core//:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_libp2p_go_libp2p_core//host:go_default_library",
"@com_github_libp2p_go_libp2p_core//network:go_default_library",
"@com_github_libp2p_go_libp2p_core//peer:go_default_library",
"@com_github_libp2p_go_libp2p_core//protocol: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_pubsub//:go_default_library",
"@com_github_multiformats_go_multiaddr//:go_default_library",
"@com_github_pkg_errors//:go_default_library",

View File

@@ -3,17 +3,19 @@ package p2p
// Config for the p2p service. These parameters are set from application level flags
// to initialize the p2p service.
type Config struct {
NoDiscovery bool
StaticPeers []string
BootstrapNodeAddr string
RelayNodeAddr string
HostAddress string
PrivateKey string
DataDir string
TCPPort uint
UDPPort uint
MaxPeers uint
WhitelistCIDR string
EnableUPnP bool
Encoding string
NoDiscovery bool
StaticPeers []string
BootstrapNodeAddr []string
KademliaBootStrapAddr []string
Discv5BootStrapAddr []string
RelayNodeAddr string
HostAddress string
PrivateKey string
DataDir string
TCPPort uint
UDPPort uint
MaxPeers uint
WhitelistCIDR string
EnableUPnP bool
Encoding string
}

View File

@@ -1,6 +1,7 @@
package p2p
import (
"context"
"crypto/ecdsa"
"fmt"
"net"
@@ -9,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
iaddr "github.com/ipfs/go-ipfs-addr"
core "github.com/libp2p/go-libp2p-core"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
@@ -43,12 +45,13 @@ func createListener(ipAddr net.IP, privKey *ecdsa.PrivateKey, cfg *Config) *disc
dv5Cfg := discover.Config{
PrivateKey: privKey,
}
if cfg.BootstrapNodeAddr != "" {
bootNode, err := enode.Parse(enode.ValidSchemes, cfg.BootstrapNodeAddr)
dv5Cfg.Bootnodes = []*enode.Node{}
for _, addr := range cfg.Discv5BootStrapAddr {
bootNode, err := enode.Parse(enode.ValidSchemes, addr)
if err != nil {
log.Fatal(err)
}
dv5Cfg.Bootnodes = []*enode.Node{bootNode}
dv5Cfg.Bootnodes = append(dv5Cfg.Bootnodes, bootNode)
}
network, err := discover.ListenV5(conn, localNode, dv5Cfg)
@@ -81,6 +84,37 @@ func startDiscoveryV5(addr net.IP, privKey *ecdsa.PrivateKey, cfg *Config) (*dis
return listener, nil
}
// startDHTDiscovery supports discovery via DHT.
func startDHTDiscovery(host core.Host, bootstrapAddr string) error {
multiAddr, err := multiAddrFromString(bootstrapAddr)
if err != nil {
return err
}
peerInfo, err := peer.AddrInfoFromP2pAddr(multiAddr)
if err != nil {
return err
}
err = host.Connect(context.Background(), *peerInfo)
return err
}
func parseBootStrapAddrs(addrs []string) (discv5Nodes []string, kadDHTNodes []string) {
for _, addr := range addrs {
_, err := enode.Parse(enode.ValidSchemes, addr)
if err == nil {
discv5Nodes = append(discv5Nodes, addr)
continue
}
_, err = multiAddrFromString(addr)
if err == nil {
kadDHTNodes = append(kadDHTNodes, addr)
continue
}
log.Errorf("Invalid bootstrap address of %s provided", addr)
}
return discv5Nodes, kadDHTNodes
}
func convertToMultiAddr(nodes []*enode.Node) []ma.Multiaddr {
var multiAddrs []ma.Multiaddr
for _, node := range nodes {

View File

@@ -75,8 +75,8 @@ func TestStartDiscV5_DiscoverAllPeers(t *testing.T) {
bootNode := bootListener.Self()
cfg := &Config{
BootstrapNodeAddr: bootNode.String(),
Encoding: "ssz",
Discv5BootStrapAddr: []string{bootNode.String()},
Encoding: "ssz",
}
var listeners []*discover.UDPv5

View File

@@ -7,13 +7,18 @@ import (
"time"
"github.com/ethereum/go-ethereum/p2p/enode"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
"github.com/karlseguin/ccache"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/protocol"
kaddht "github.com/libp2p/go-libp2p-kad-dht"
dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
pubsub "github.com/libp2p/go-libp2p-pubsub"
rhost "github.com/libp2p/go-libp2p/p2p/host/routed"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/beacon-chain/p2p/encoder"
@@ -23,9 +28,10 @@ import (
var _ = shared.Service(&Service{})
var pollingPeriod = 1 * time.Second
var bootnodePingPeriod = 5 * time.Minute
var ttl = 1 * time.Hour
const prysmProtocolPrefix = "/prysm/0.0.0"
// Service for managing peer to peer (p2p) networking.
type Service struct {
ctx context.Context
@@ -53,6 +59,11 @@ func NewService(cfg *Config) (*Service, error) {
exclusionList: ccache.New(ccache.Configure()),
}
dv5Nodes, kadDHTNodes := parseBootStrapAddrs(s.cfg.BootstrapNodeAddr)
cfg.Discv5BootStrapAddr = dv5Nodes
cfg.KademliaBootStrapAddr = kadDHTNodes
ipAddr := ipAddr(s.cfg)
s.privKey, err = privKey(s.cfg)
if err != nil {
@@ -67,6 +78,23 @@ func NewService(cfg *Config) (*Service, error) {
log.WithError(err).Error("Failed to create p2p host")
return nil, err
}
if len(cfg.KademliaBootStrapAddr) != 0 {
dopts := []dhtopts.Option{
dhtopts.Datastore(dsync.MutexWrap(ds.NewMapDatastore())),
dhtopts.Protocols(
protocol.ID(prysmProtocolPrefix + "/dht"),
),
}
dht, err := kaddht.New(ctx, h, dopts...)
if err != nil {
return nil, err
}
// Wrap host with a routed host so that peers can be looked up in the
// distributed hash table by their peer ID.
h = rhost.Wrap(h, dht)
}
s.host = h
// TODO(3147): Add gossip sub options
@@ -95,7 +123,7 @@ func (s *Service) Start() {
return
}
if s.cfg.BootstrapNodeAddr != "" && !s.cfg.NoDiscovery {
if len(s.cfg.Discv5BootStrapAddr) != 0 && !s.cfg.NoDiscovery {
ipAddr := ipAddr(s.cfg)
listener, err := startDiscoveryV5(ipAddr, s.privKey, s.cfg)
if err != nil {
@@ -103,7 +131,7 @@ func (s *Service) Start() {
s.startupErr = err
return
}
err = s.addBootNodeToExclusionList()
err = s.addBootNodesToExclusionList()
if err != nil {
log.WithError(err).Error("Could not add bootnode to the exclusion list")
s.startupErr = err
@@ -112,7 +140,22 @@ func (s *Service) Start() {
s.dv5Listener = listener
go s.listenForNewNodes()
go s.maintainBootnode()
}
if len(s.cfg.KademliaBootStrapAddr) != 0 && !s.cfg.NoDiscovery {
for _, addr := range s.cfg.KademliaBootStrapAddr {
err := startDHTDiscovery(s.host, addr)
if err != nil {
log.WithError(err).Error("Could not connect to bootnode")
s.startupErr = err
return
}
if err := s.addKadDHTNodesToExclusionList(addr); err != nil {
s.startupErr = err
return
}
}
}
s.started = true
@@ -190,7 +233,7 @@ 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() {
ticker := time.NewTicker(pollingPeriod)
bootNode, err := enode.Parse(enode.ValidSchemes, s.cfg.BootstrapNodeAddr)
bootNode, err := enode.Parse(enode.ValidSchemes, s.cfg.Discv5BootStrapAddr[0])
if err != nil {
log.Fatal(err)
}
@@ -207,28 +250,6 @@ func (s *Service) listenForNewNodes() {
}
}
// maintainBootnode connection by infrequently pinging the bootnode ENR. If the bootnode server has
// restarted and this client pruned them from the local table, then a ping will reinsert this
// clients' ENR into the table of the bootnode again.
func (s *Service) maintainBootnode() {
if s.cfg.BootstrapNodeAddr == "" {
return
}
ticker := time.NewTicker(bootnodePingPeriod)
bootNode := enode.MustParse(s.cfg.BootstrapNodeAddr)
for {
select {
case <-ticker.C:
log.Debug("Pinging bootnode")
if err := s.dv5Listener.Ping(bootNode); err != nil {
log.WithError(err).Error("Failed to ping bootnode")
}
case <-s.ctx.Done():
return
}
}
}
func (s *Service) connectWithAllPeers(multiAddrs []ma.Multiaddr) {
addrInfos, err := peer.AddrInfosFromP2pAddrs(multiAddrs...)
if err != nil {
@@ -249,22 +270,38 @@ func (s *Service) connectWithAllPeers(multiAddrs []ma.Multiaddr) {
}
}
func (s *Service) addBootNodeToExclusionList() error {
bootNode, err := enode.Parse(enode.ValidSchemes, s.cfg.BootstrapNodeAddr)
if err != nil {
return err
func (s *Service) addBootNodesToExclusionList() error {
for _, addr := range s.cfg.Discv5BootStrapAddr {
bootNode, err := enode.Parse(enode.ValidSchemes, addr)
if err != nil {
return err
}
multAddr, err := convertToSingleMultiAddr(bootNode)
if err != nil {
return err
}
addrInfo, err := peer.AddrInfoFromP2pAddr(multAddr)
if err != nil {
return err
}
// bootnode is never dialled, so ttl is tentatively 1 year
s.exclusionList.Set(addrInfo.ID.String(), true, 365*24*time.Hour)
}
multAddr, err := convertToSingleMultiAddr(bootNode)
return nil
}
func (s *Service) addKadDHTNodesToExclusionList(addr string) error {
multiAddr, err := ma.NewMultiaddr(addr)
if err != nil {
return err
return errors.Wrap(err, "could not get multiaddr")
}
addrInfo, err := peer.AddrInfoFromP2pAddr(multAddr)
addrInfo, err := peer.AddrInfoFromP2pAddr(multiAddr)
if err != nil {
return err
}
// bootnode is never dialled, so ttl is tentatively 1 year
s.exclusionList.Set(addrInfo.ID.String(), true, 365*24*time.Hour)
return nil
}

View File

@@ -133,8 +133,9 @@ func TestListenForNewNodes(t *testing.T) {
bootNode := bootListener.Self()
cfg = &Config{
BootstrapNodeAddr: bootNode.String(),
Encoding: "ssz",
BootstrapNodeAddr: []string{bootNode.String()},
Discv5BootStrapAddr: []string{bootNode.String()},
Encoding: "ssz",
}
var listeners []*discover.UDPv5
var hosts []host.Host

View File

@@ -5,10 +5,11 @@ package ethereum_beacon_p2p_v1
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,12 +5,13 @@ package ethereum_beacon_p2p_v1
import (
fmt "fmt"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -7,14 +7,15 @@ import (
context "context"
encoding_binary "encoding/binary"
fmt "fmt"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -6,13 +6,14 @@ package ethereum_beacon_rpc_v1
import (
context "context"
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
empty "github.com/golang/protobuf/ptypes/empty"
_ "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options"
v1alpha1 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,10 +5,11 @@ package eth
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,11 +5,12 @@ package eth
import (
fmt "fmt"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
github_com_prysmaticlabs_go_bitfield "github.com/prysmaticlabs/go-bitfield"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,10 +5,11 @@ package eth
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -6,13 +6,14 @@ package eth
import (
context "context"
fmt "fmt"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -6,12 +6,13 @@ package eth
import (
context "context"
fmt "fmt"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -6,10 +6,11 @@ package eth
import (
context "context"
fmt "fmt"
math "math"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
grpc "google.golang.org/grpc"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -7,13 +7,14 @@ import (
context "context"
encoding_binary "encoding/binary"
fmt "fmt"
io "io"
math "math"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
types "github.com/gogo/protobuf/types"
_ "google.golang.org/genproto/googleapis/api/annotations"
grpc "google.golang.org/grpc"
io "io"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -5,9 +5,10 @@ package ethereum_sharding_p2p_v1
import (
fmt "fmt"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
proto "github.com/gogo/protobuf/proto"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@@ -64,10 +64,9 @@ var (
Usage: "Connect with this peer. This flag may be used multiple times.",
}
// BootstrapNode tells the beacon node which bootstrap node to connect to
BootstrapNode = cli.StringFlag{
BootstrapNode = cli.StringSliceFlag{
Name: "bootstrap-node",
Usage: "The address of bootstrap node. Beacon node will connect for peer discovery via DHT",
Value: "",
}
// RelayNode tells the beacon node which relay node to connect to.
RelayNode = cli.StringFlag{

View File

@@ -15,7 +15,15 @@ go_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_ipfs_go_datastore//:go_default_library",
"@com_github_ipfs_go_datastore//sync:go_default_library",
"@com_github_ipfs_go_log//:go_default_library",
"@com_github_libp2p_go_libp2p//:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_libp2p_go_libp2p_core//protocol: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_multiformats_go_multiaddr//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",
@@ -40,7 +48,15 @@ go_image(
"@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_ipfs_go_datastore//:go_default_library",
"@com_github_ipfs_go_datastore//sync:go_default_library",
"@com_github_ipfs_go_log//:go_default_library",
"@com_github_libp2p_go_libp2p//:go_default_library",
"@com_github_libp2p_go_libp2p_core//crypto:go_default_library",
"@com_github_libp2p_go_libp2p_core//protocol: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_multiformats_go_multiaddr//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@org_uber_go_automaxprocs//:go_default_library",

View File

@@ -10,6 +10,7 @@
package main
import (
"context"
"crypto/ecdsa"
"crypto/rand"
"encoding/hex"
@@ -24,7 +25,15 @@ import (
"github.com/ethereum/go-ethereum/p2p/discover"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
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"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/protocol"
kaddht "github.com/libp2p/go-libp2p-kad-dht"
dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/version"
"github.com/sirupsen/logrus"
@@ -32,15 +41,18 @@ import (
)
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")
metricsPort = flag.Int("metrics-port", 5000, "Port to listen for connections")
externalIP = flag.String("external-ip", "127.0.0.1", "External IP for the bootnode")
debug = flag.Bool("debug", false, "Enable debug logging")
privateKey = flag.String("private", "", "Private key to use for peer ID")
discv5port = flag.Int("discv5-port", 4000, "Port to listen for discv5 connections")
kademliaPort = flag.Int("kad-port", 4500, "Port to listen for connections to kad DHT")
metricsPort = flag.Int("metrics-port", 5000, "Port to listen for connections")
externalIP = flag.String("external-ip", "127.0.0.1", "External IP for the bootnode")
log = logrus.WithField("prefix", "bootnode")
)
const dhtProtocol = "/prysm/0.0.0/dht"
type handler struct {
listener *discover.UDPv5
}
@@ -60,14 +72,17 @@ func main() {
log.Debug("Debug logging enabled.")
}
privKey, interfacePrivKey := extractPrivateKey()
cfg := discover.Config{
PrivateKey: extractPrivateKey(),
PrivateKey: privKey,
}
listener := createListener(*externalIP, *port, cfg)
listener := createListener(*externalIP, *discv5port, cfg)
node := listener.Self()
log.Infof("Running bootnode: %s", node.String())
startKademliaDHT(interfacePrivKey)
handler := &handler{
listener: listener,
}
@@ -81,6 +96,46 @@ func main() {
select {}
}
func startKademliaDHT(privKey crypto.PrivKey) {
if *debug {
logging.SetDebugLogging()
}
listen, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", *externalIP, *kademliaPort))
if err != nil {
log.Fatalf("Failed to construct new multiaddress. %v", err)
}
opts := []libp2p.Option{
libp2p.ListenAddrs(listen),
}
opts = append(opts, libp2p.Identity(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 Kademlia DHT bootnode: /ip4/%s/tcp/%d/p2p/%s\n", *externalIP, *kademliaPort, host.ID().Pretty())
}
func createListener(ipAddr string, port int, cfg discover.Config) *discover.UDPv5 {
ip := net.ParseIP(ipAddr)
if ip.To4() == nil {
@@ -136,8 +191,9 @@ func createLocalNode(privKey *ecdsa.PrivateKey, ipAddr net.IP, port int) (*enode
return localNode, nil
}
func extractPrivateKey() *ecdsa.PrivateKey {
func extractPrivateKey() (*ecdsa.PrivateKey, crypto.PrivKey) {
var privKey *ecdsa.PrivateKey
var interfaceKey crypto.PrivKey
if *privateKey != "" {
dst, err := hex.DecodeString(*privateKey)
if err != nil {
@@ -147,6 +203,7 @@ func extractPrivateKey() *ecdsa.PrivateKey {
if err != nil {
panic(err)
}
interfaceKey = unmarshalledKey
privKey = (*ecdsa.PrivateKey)((*btcec.PrivateKey)(unmarshalledKey.(*crypto.Secp256k1PrivateKey)))
} else {
@@ -154,6 +211,7 @@ func extractPrivateKey() *ecdsa.PrivateKey {
if err != nil {
panic(err)
}
interfaceKey = privInterfaceKey
privKey = (*ecdsa.PrivateKey)((*btcec.PrivateKey)(privInterfaceKey.(*crypto.Secp256k1PrivateKey)))
log.Warning("No private key was provided. Using default/random private key")
b, err := privInterfaceKey.Raw()
@@ -163,5 +221,5 @@ func extractPrivateKey() *ecdsa.PrivateKey {
log.Debugf("Private key %x", b)
}
return privKey
return privKey, interfaceKey
}

View File

@@ -20,13 +20,14 @@ func TestBootnode_OK(t *testing.T) {
if err != nil {
t.Fatal(err)
}
privKey, _ := extractPrivateKey()
cfg := discover.Config{
PrivateKey: extractPrivateKey(),
PrivateKey: privKey,
}
listener := createListener(ipAddr, 4000, cfg)
defer listener.Close()
cfg.PrivateKey = extractPrivateKey()
cfg.PrivateKey, _ = extractPrivateKey()
bootNode, err := enode.Parse(enode.ValidSchemes, listener.Self().String())
if err != nil {
t.Fatal(err)
@@ -72,7 +73,7 @@ func TestPrivateKey_ParsesCorrectly(t *testing.T) {
}
*privateKey = fmt.Sprintf("%x", pk)
extractedKey := extractPrivateKey()
extractedKey, _ := extractPrivateKey()
rawKey := (*ecdsa.PrivateKey)((*btcec.PrivateKey)(privKey.(*crypto.Secp256k1PrivateKey)))