Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd: add auto-p2pkey to bootnode command #350

Merged
merged 3 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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