Commit 0e7184b0 authored by Matthew Slipper's avatar Matthew Slipper Committed by GitHub

op-node: Add p2p utils (#3153)

* op-node: Add p2p utils

* Update op-node/flags/flags.go
Co-authored-by: default avatarDiederik Loerakker <proto@protolambda.com>
Co-authored-by: default avatarDiederik Loerakker <proto@protolambda.com>
parent 0c5ad1d4
...@@ -9,6 +9,8 @@ import ( ...@@ -9,6 +9,8 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/ethereum-optimism/optimism/op-node/cmd/p2p"
"github.com/ethereum-optimism/optimism/op-node/metrics" "github.com/ethereum-optimism/optimism/op-node/metrics"
opnode "github.com/ethereum-optimism/optimism/op-node" opnode "github.com/ethereum-optimism/optimism/op-node"
...@@ -53,13 +55,19 @@ func main() { ...@@ -53,13 +55,19 @@ func main() {
) )
app := cli.NewApp() app := cli.NewApp()
app.Flags = flags.Flags
app.Version = VersionWithMeta app.Version = VersionWithMeta
app.Flags = flags.Flags
app.Name = "opnode" app.Name = "opnode"
app.Usage = "Optimism Rollup Node" app.Usage = "Optimism Rollup Node"
app.Description = "The deposit only rollup node drives the L2 execution engine based on L1 deposits." app.Description = "The deposit only rollup node drives the L2 execution engine based on L1 deposits."
app.Action = RollupNodeMain app.Action = RollupNodeMain
app.Commands = []cli.Command{
{
Name: "p2p",
Subcommands: p2p.Subcommands,
},
}
err := app.Run(os.Args) err := app.Run(os.Args)
if err != nil { if err != nil {
log.Crit("Application failed", "message", err) log.Crit("Application failed", "message", err)
......
package p2p
import (
"crypto/rand"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/urfave/cli"
)
func Priv2PeerID(r io.Reader) (string, error) {
b, err := readHexData(r)
if err != nil {
return "", nil
}
p, err := crypto.UnmarshalSecp256k1PrivateKey(b)
if err != nil {
return "", fmt.Errorf("failed to parse priv key from %d bytes: %w", len(b), err)
}
pid, err := peer.IDFromPrivateKey(p)
if err != nil {
return "", fmt.Errorf("failed to parse peer ID from private key: %w", err)
}
return pid.String(), nil
}
func Pub2PeerID(r io.Reader) (string, error) {
b, err := readHexData(r)
if err != nil {
return "", nil
}
p, err := crypto.UnmarshalSecp256k1PublicKey(b)
if err != nil {
return "", fmt.Errorf("failed to parse pub key from %d bytes: %w", len(b), err)
}
pid, err := peer.IDFromPublicKey(p)
if err != nil {
return "", fmt.Errorf("failed to parse peer ID from public key: %w", err)
}
return pid.String(), nil
}
func readHexData(r io.Reader) ([]byte, error) {
data, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
rawStr := strings.TrimSpace(string(data))
rawStr = strings.TrimPrefix(rawStr, "0x")
b, err := hex.DecodeString(rawStr)
if err != nil {
return nil, fmt.Errorf("p2p key is not formatted in hex chars: %w", err)
}
return b, nil
}
var Subcommands = cli.Commands{
{
Name: "priv2id",
Usage: "Reads a private key from STDIN, and returns a peer ID",
Action: func(ctx *cli.Context) error {
key, err := Priv2PeerID(os.Stdin)
if err != nil {
return err
}
fmt.Println(key)
return nil
},
},
{
Name: "pub2id",
Usage: "Reads a public key from STDIN, and returns a peer ID",
Action: func(ctx *cli.Context) error {
key, err := Pub2PeerID(os.Stdin)
if err != nil {
return err
}
fmt.Println(key)
return nil
},
},
{
Name: "genkey",
Usage: "Generates a private key",
Action: func(ctx *cli.Context) error {
buf := make([]byte, 32)
if _, err := rand.Read(buf); err != nil {
return fmt.Errorf("failed to get entropy: %w", err)
}
fmt.Println(hex.EncodeToString(buf))
return nil
},
},
}
package p2p
import (
"bytes"
"encoding/hex"
"testing"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/stretchr/testify/require"
)
func TestPrivPub2PeerID(t *testing.T) {
priv, pub, err := crypto.GenerateKeyPair(crypto.Secp256k1, 32)
require.NoError(t, err)
privRaw, err := priv.Raw()
require.NoError(t, err)
pubRaw, err := pub.Raw()
require.NoError(t, err)
t.Run("with a private key", func(t *testing.T) {
privPidLib, err := peer.IDFromPrivateKey(priv)
require.NoError(t, err)
privPidImpl, err := Priv2PeerID(bytes.NewReader([]byte(hex.EncodeToString(privRaw))))
require.NoError(t, err)
require.Equal(t, privPidLib.String(), privPidImpl)
})
t.Run("with a public key", func(t *testing.T) {
pubPidLib, err := peer.IDFromPublicKey(pub)
require.NoError(t, err)
pubPidImpl, err := Pub2PeerID(bytes.NewReader([]byte(hex.EncodeToString(pubRaw))))
require.NoError(t, err)
require.Equal(t, pubPidLib.String(), pubPidImpl)
})
}
package flags package flags
import "github.com/urfave/cli" import (
"fmt"
"github.com/urfave/cli"
)
// Flags // Flags
...@@ -13,35 +17,30 @@ func prefixEnvVar(name string) string { ...@@ -13,35 +17,30 @@ func prefixEnvVar(name string) string {
var ( var (
/* Required Flags */ /* Required Flags */
L1NodeAddr = cli.StringFlag{ L1NodeAddr = cli.StringFlag{
Name: "l1", Name: "l1",
Usage: "Address of L1 User JSON-RPC endpoint to use (eth namespace required)", Usage: "Address of L1 User JSON-RPC endpoint to use (eth namespace required)",
Required: true, Value: "http://127.0.0.1:8545",
Value: "http://127.0.0.1:8545", EnvVar: prefixEnvVar("L1_ETH_RPC"),
EnvVar: prefixEnvVar("L1_ETH_RPC"),
} }
L2EngineAddr = cli.StringFlag{ L2EngineAddr = cli.StringFlag{
Name: "l2", Name: "l2",
Usage: "Address of L2 Engine JSON-RPC endpoints to use (engine and eth namespace required)", Usage: "Address of L2 Engine JSON-RPC endpoints to use (engine and eth namespace required)",
Required: true, EnvVar: prefixEnvVar("L2_ENGINE_RPC"),
EnvVar: prefixEnvVar("L2_ENGINE_RPC"),
} }
RollupConfig = cli.StringFlag{ RollupConfig = cli.StringFlag{
Name: "rollup.config", Name: "rollup.config",
Usage: "Rollup chain parameters", Usage: "Rollup chain parameters",
Required: true, EnvVar: prefixEnvVar("ROLLUP_CONFIG"),
EnvVar: prefixEnvVar("ROLLUP_CONFIG"),
} }
RPCListenAddr = cli.StringFlag{ RPCListenAddr = cli.StringFlag{
Name: "rpc.addr", Name: "rpc.addr",
Usage: "RPC listening address", Usage: "RPC listening address",
Required: true, EnvVar: prefixEnvVar("RPC_ADDR"),
EnvVar: prefixEnvVar("RPC_ADDR"),
} }
RPCListenPort = cli.IntFlag{ RPCListenPort = cli.IntFlag{
Name: "rpc.port", Name: "rpc.port",
Usage: "RPC listening port", Usage: "RPC listening port",
Required: true, EnvVar: prefixEnvVar("RPC_PORT"),
EnvVar: prefixEnvVar("RPC_PORT"),
} }
/* Optional Flags */ /* Optional Flags */
...@@ -164,3 +163,26 @@ var optionalFlags = append([]cli.Flag{ ...@@ -164,3 +163,26 @@ var optionalFlags = append([]cli.Flag{
// Flags contains the list of configuration options available to the binary. // Flags contains the list of configuration options available to the binary.
var Flags = append(requiredFlags, optionalFlags...) var Flags = append(requiredFlags, optionalFlags...)
func CheckRequired(ctx *cli.Context) error {
l1NodeAddr := ctx.GlobalString(L1NodeAddr.Name)
if l1NodeAddr == "" {
return fmt.Errorf("flag %s is required", L1NodeAddr.Name)
}
l2EngineAddr := ctx.GlobalString(L2EngineAddr.Name)
if l2EngineAddr == "" {
return fmt.Errorf("flag %s is required", L2EngineAddr.Name)
}
rollupConfig := ctx.GlobalString(RollupConfig.Name)
if rollupConfig == "" {
return fmt.Errorf("flag %s is required", RollupConfig.Name)
}
rpcListenAddr := ctx.GlobalString(RPCListenAddr.Name)
if rpcListenAddr == "" {
return fmt.Errorf("flag %s is required", RPCListenAddr.Name)
}
if !ctx.GlobalIsSet(RPCListenPort.Name) {
return fmt.Errorf("flag %s is required", RPCListenPort.Name)
}
return nil
}
...@@ -7,16 +7,6 @@ import ( ...@@ -7,16 +7,6 @@ import (
"github.com/urfave/cli" "github.com/urfave/cli"
) )
// TestRequiredFlagsSetRequired asserts that all flags deemed required properly
// have the Required field set to true.
func TestRequiredFlagsSetRequired(t *testing.T) {
for _, flag := range requiredFlags {
reqFlag, ok := flag.(cli.RequiredFlag)
require.True(t, ok)
require.True(t, reqFlag.IsRequired())
}
}
// TestOptionalFlagsDontSetRequired asserts that all flags deemed optional set // TestOptionalFlagsDontSetRequired asserts that all flags deemed optional set
// the Required field to false. // the Required field to false.
func TestOptionalFlagsDontSetRequired(t *testing.T) { func TestOptionalFlagsDontSetRequired(t *testing.T) {
......
...@@ -24,6 +24,10 @@ import ( ...@@ -24,6 +24,10 @@ import (
// NewConfig creates a Config from the provided flags or environment variables. // NewConfig creates a Config from the provided flags or environment variables.
func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) { func NewConfig(ctx *cli.Context, log log.Logger) (*node.Config, error) {
if err := flags.CheckRequired(ctx); err != nil {
return nil, err
}
rollupConfig, err := NewRollupConfig(ctx) rollupConfig, err := NewRollupConfig(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment