Skip to content

Commit

Permalink
cmd: add auto-p2pkey to bootnode command (#350)
Browse files Browse the repository at this point in the history
As requested in #317, add support for automatically generating a p2pkey if not found. I decided to enable this default since bootnode.

category: bug
ticket: #317
  • Loading branch information
corverroos committed Apr 4, 2022
1 parent 90abf45 commit a2d294d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 13 deletions.
31 changes: 25 additions & 6 deletions cmd/bootnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import (
"context"
"fmt"
"net/http"
"os"
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"

"github.com/obolnetwork/charon/app/errors"
"github.com/obolnetwork/charon/app/log"
Expand All @@ -29,10 +31,11 @@ import (
)

type bootnodeConfig struct {
DataDir string
HTTPAddr string
P2PConfig p2p.Config
LogConfig log.Config
DataDir string
HTTPAddr string
P2PConfig p2p.Config
LogConfig log.Config
AutoP2PKey bool
}

func newBootnodeCmd(runFunc func(context.Context, bootnodeConfig) error) *cobra.Command {
Expand All @@ -49,13 +52,18 @@ func newBootnodeCmd(runFunc func(context.Context, bootnodeConfig) error) *cobra.
}

bindDataDirFlag(cmd.Flags(), &config.DataDir)
bindBootnodeFlag(cmd.Flags(), &config.HTTPAddr)
bindBootnodeFlag(cmd.Flags(), &config.HTTPAddr, &config.AutoP2PKey)
bindP2PFlags(cmd.Flags(), &config.P2PConfig)
bindLogFlags(cmd.Flags(), &config.LogConfig)

return cmd
}

func bindBootnodeFlag(flags *pflag.FlagSet, httpAddr *string, autoP2PKey *bool) {
flags.StringVar(httpAddr, "bootnode-http-address", "127.0.0.1:8088", "Listening address for the bootnode http server serving runtime ENR")
flags.BoolVar(autoP2PKey, "auto-p2pkey", true, "Automatically create a p2pkey (ecdsa private key used for p2p authentication and ENR) if none found in data directory")
}

// runBootnode starts a p2p-udp discv5 bootnode.
func runBootnode(ctx context.Context, config bootnodeConfig) error {
ctx = log.WithTopic(ctx, "bootnode")
Expand All @@ -65,7 +73,18 @@ func runBootnode(ctx context.Context, config bootnodeConfig) error {
}

key, err := p2p.LoadPrivKey(config.DataDir)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
if !config.AutoP2PKey {
return errors.New("p2pkey not found in data dir (run with --auto-p2pkey to auto generate)")
}

log.Info(ctx, "Automatically creating p2pkey", z.Str("path", p2p.KeyPath(config.DataDir)))

key, err = p2p.NewSavedPrivKey(config.DataDir)
if err != nil {
return err
}
} else if err != nil {
return err
}

Expand Down
24 changes: 24 additions & 0 deletions cmd/bootnode_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,27 @@ func TestRunBootnode(t *testing.T) {
testutil.SkipIfBindErr(t, err)
require.NoError(t, err)
}

func TestRunBootnodeAutoP2P(t *testing.T) {
temp, err := os.MkdirTemp("", "")
require.NoError(t, err)

config := bootnodeConfig{
DataDir: temp,
LogConfig: log.DefaultConfig(),
P2PConfig: p2p.Config{UDPAddr: testutil.AvailableAddr(t).String()},
HTTPAddr: testutil.AvailableAddr(t).String(),
}

ctx, cancel := context.WithCancel(context.Background())
cancel()

err = runBootnode(ctx, config)
testutil.SkipIfBindErr(t, err)
require.Error(t, err)

config.AutoP2PKey = true
err = runBootnode(ctx, config)
testutil.SkipIfBindErr(t, err)
require.NoError(t, err)
}
4 changes: 0 additions & 4 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ func bindDataDirFlag(flags *pflag.FlagSet, dataDir *string) {
flags.StringVar(dataDir, "data-dir", "./charon/data", "The directory where charon will store all its internal data")
}

func bindBootnodeFlag(flags *pflag.FlagSet, httpAddr *string) {
flags.StringVar(httpAddr, "bootnode-http-address", "127.0.0.1:8088", "Listening address for the bootnode http server serving runtime ENR")
}

func bindP2PFlags(flags *pflag.FlagSet, config *p2p.Config) {
flags.StringVar(&config.DBPath, "p2p-peerdb", "", "Path to store a discv5 peer database. Empty default results in in-memory database.")
flags.StringSliceVar(&config.UDPBootnodes, "p2p-bootnodes", nil, "Comma-separated list of discv5 bootnode URLs or ENRs. Manifest ENRs are used if empty. Example URL: enode://<hex node id>@10.3.58.6:30303?discport=30301.")
Expand Down
7 changes: 4 additions & 3 deletions p2p/k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ import (
"github.com/obolnetwork/charon/app/errors"
)

func p2pKeyPath(datadir string) string {
// KeyPath returns the p2pkey path relative to the data dir.
func KeyPath(datadir string) string {
return path.Join(datadir, "p2pkey")
}

// LoadPrivKey returns the ecdsa k1 key saved in the directory.
func LoadPrivKey(dataDir string) (*ecdsa.PrivateKey, error) {
key, err := crypto.LoadECDSA(p2pKeyPath(dataDir))
key, err := crypto.LoadECDSA(KeyPath(dataDir))
if err != nil {
return nil, errors.Wrap(err, "load key")
}
Expand All @@ -49,7 +50,7 @@ func NewSavedPrivKey(datadir string) (*ecdsa.PrivateKey, error) {
return nil, errors.Wrap(err, "gen key")
}

err = crypto.SaveECDSA(p2pKeyPath(datadir), key)
err = crypto.SaveECDSA(KeyPath(datadir), key)
if err != nil {
return nil, errors.Wrap(err, "save key")
}
Expand Down

0 comments on commit a2d294d

Please sign in to comment.