Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Commit

Permalink
Merge pull request #188 from primevprotocol/feature/private-key-manag…
Browse files Browse the repository at this point in the history
…ement

Feature/private key management
  • Loading branch information
Mikelle authored Feb 8, 2024
2 parents 44a5f26 + 6008ebc commit 0c3aeca
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 75 deletions.
104 changes: 91 additions & 13 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import (
"strings"
"time"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/crypto"
contracts "github.com/primevprotocol/contracts-abi/config"
mevcommit "github.com/primevprotocol/mev-commit"
ks "github.com/primevprotocol/mev-commit/pkg/keysigner"
"github.com/primevprotocol/mev-commit/pkg/node"
"github.com/primevprotocol/mev-commit/pkg/p2p/libp2p"
"github.com/urfave/cli/v2"
Expand All @@ -28,6 +31,7 @@ const (
defaultConfigDir = "~/.mev-commit"
defaultKeyFile = "key"
defaultSecret = "secret"
defaultKeystore = "keystore"
)

var (
Expand Down Expand Up @@ -64,6 +68,19 @@ var (
Value: filepath.Join(defaultConfigDir, defaultKeyFile),
})

optionKeystorePassword = altsrc.NewStringFlag(&cli.StringFlag{
Name: "keystore-password",
Usage: "use to access keystore",
EnvVars: []string{"MEV_COMMIT_KEYSTORE_PASSWORD"},
})

optionKeystorePath = altsrc.NewStringFlag(&cli.StringFlag{
Name: "keystore-path",
Usage: "path to keystore location",
EnvVars: []string{"MEV_COMMIT_KEYSTORE_PATH"},
Value: filepath.Join(defaultConfigDir, defaultKeystore),
})

optionPeerType = altsrc.NewStringFlag(&cli.StringFlag{
Name: "peer-type",
Usage: "peer type to use, options are 'bidder', 'provider' or 'bootnode'",
Expand Down Expand Up @@ -193,6 +210,8 @@ func main() {
optionConfig,
optionPeerType,
optionPrivKeyFile,
optionKeystorePassword,
optionKeystorePath,
optionP2PPort,
optionP2PAddr,
optionHTTPPort,
Expand All @@ -217,7 +236,7 @@ func main() {
Version: mevcommit.Version(),
Flags: flags,
Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc(optionConfig.Name)),
Action: start,
Action: initializeApplication,
}

if err := app.Run(os.Args); err != nil {
Expand Down Expand Up @@ -282,14 +301,30 @@ func resolveFilePath(path string) (string, error) {
return path, nil
}

func start(c *cli.Context) error {
privKeyFile, err := resolveFilePath(c.String(optionPrivKeyFile.Name))
if err != nil {
return fmt.Errorf("failed to get private key file path: %w", err)
func initializeApplication(c *cli.Context) error {
if err := verifyKeystorePasswordPresence(c); err != nil {
return err
}
if err := launchNodeWithConfig(c); err != nil {
return err
}
return nil
}

if err := createKeyIfNotExists(c, privKeyFile); err != nil {
return fmt.Errorf("failed to create private key: %w", err)
// verifyKeystorePasswordPresence checks for the presence of a keystore password.
// it returns error, if keystore path is set and keystore password is not
func verifyKeystorePasswordPresence(c *cli.Context) error {
if c.IsSet(optionKeystorePath.Name) && !c.IsSet(optionKeystorePassword.Name) {
return cli.Exit("Password for encrypted keystore is missing", 1)
}
return nil
}

// launchNodeWithConfig configures and starts the p2p node based on the CLI context.
func launchNodeWithConfig(c *cli.Context) error {
keysigner, err := setupKeySigner(c)
if err != nil {
return err
}

logger, err := newLogger(
Expand All @@ -301,11 +336,6 @@ func start(c *cli.Context) error {
return fmt.Errorf("failed to create logger: %w", err)
}

privKey, err := crypto.LoadECDSA(privKeyFile)
if err != nil {
return fmt.Errorf("failed to load private key from file '%s': %w", privKeyFile, err)
}

httpAddr := fmt.Sprintf("%s:%d", c.String(optionHTTPAddr.Name), c.Int(optionHTTPPort.Name))
rpcAddr := fmt.Sprintf("%s:%d", c.String(optionRPCAddr.Name), c.Int(optionRPCPort.Name))
natAddr := ""
Expand All @@ -314,7 +344,7 @@ func start(c *cli.Context) error {
}

nd, err := node.NewNode(&node.Options{
PrivKey: privKey,
KeySigner: keysigner,
Secret: c.String(optionSecret.Name),
PeerType: c.String(optionPeerType.Name),
P2PPort: c.Int(optionP2PPort.Name),
Expand Down Expand Up @@ -387,3 +417,51 @@ func newLogger(lvl, logFmt string, sink io.Writer) (*slog.Logger, error) {

return slog.New(handler), nil
}

func setupKeySigner(c *cli.Context) (ks.KeySigner, error) {
if c.IsSet(optionKeystorePath.Name) {
return setupKeystoreSigner(c)
}
return setupPrivateKeySigner(c)
}

func setupPrivateKeySigner(c *cli.Context) (ks.KeySigner, error) {
privKeyFile, err := resolveFilePath(c.String(optionPrivKeyFile.Name))
if err != nil {
return nil, fmt.Errorf("failed to get private key file path: %w", err)
}

if err := createKeyIfNotExists(c, privKeyFile); err != nil {
return nil, fmt.Errorf("failed to create private key: %w", err)
}

privKey, err := crypto.LoadECDSA(privKeyFile)
if err != nil {
return nil, fmt.Errorf("failed to load private key from file '%s': %w", privKeyFile, err)
}

return ks.NewPrivateKeySigner(privKey), nil
}

func setupKeystoreSigner(c *cli.Context) (ks.KeySigner, error) {
// lightscripts are using 4MB memory and taking approximately 100ms CPU time on a modern processor to decrypt
keystore := keystore.NewKeyStore(c.String(optionKeystorePath.Name), keystore.LightScryptN, keystore.LightScryptP)
password := c.String(optionKeystorePassword.Name)
ksAccounts := keystore.Accounts()

var account accounts.Account
if len(ksAccounts) == 0 {
var err error
account, err = keystore.NewAccount(password)
if err != nil {
return nil, fmt.Errorf("failed to create account: %w", err)
}
} else {
account = ksAccounts[0]
}

fmt.Fprintf(c.App.Writer, "Public address of the key: %s\n", account.Address.Hex())
fmt.Fprintf(c.App.Writer, "Path of the secret key file: %s\n", account.URL.Path)

return ks.NewKeystoreSigner(keystore, password, account), nil
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21.1
require (
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.32.0-20231115204500-e097f827e652.1
github.com/bufbuild/protovalidate-go v0.5.0
github.com/ethereum/go-ethereum v1.13.10
github.com/ethereum/go-ethereum v1.13.11
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/libp2p/go-libp2p v0.31.0
Expand Down Expand Up @@ -52,7 +52,7 @@ require (
github.com/flynn/noise v1.0.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/ethereum/go-ethereum v1.13.10 h1:Ppdil79nN+Vc+mXfge0AuUgmKWuVv4eMqzoIVSdqZek=
github.com/ethereum/go-ethereum v1.13.10/go.mod h1:sc48XYQxCzH3fG9BcrXCOOgQk2JfZzNAmIKnceogzsA=
github.com/ethereum/go-ethereum v1.13.11 h1:b51Dsm+rEg7anFRUMGB8hODXHvNfcRKzz9vcj8wSdUs=
github.com/ethereum/go-ethereum v1.13.11/go.mod h1:gFtlVORuUcT+UUIcJ/veCNjkuOSujCi338uSHJrYAew=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
Expand All @@ -122,6 +124,8 @@ github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand Down Expand Up @@ -532,6 +536,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
19 changes: 9 additions & 10 deletions pkg/evmclient/evmclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package evmclient

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"log/slog"
Expand All @@ -14,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/primevprotocol/mev-commit/pkg/keysigner"
"github.com/prometheus/client_golang/prometheus"
)

Expand Down Expand Up @@ -50,7 +50,7 @@ type EvmClient struct {
chainID *big.Int
ethClient EVM
owner common.Address
signer *ecdsa.PrivateKey
keySigner keysigner.KeySigner
logger *slog.Logger
nonce uint64
metrics *metrics
Expand All @@ -64,8 +64,7 @@ type txnDetails struct {
}

func New(
owner common.Address,
signer *ecdsa.PrivateKey,
keySigner keysigner.KeySigner,
ethClient EVM,
logger *slog.Logger,
) (*EvmClient, error) {
Expand All @@ -75,9 +74,9 @@ func New(
}

m := newMetrics()

address := keySigner.GetAddress()
monitor := newTxMonitor(
owner,
address,
ethClient,
logger.With("component", "evmclient/txmonitor"),
m,
Expand All @@ -86,8 +85,8 @@ func New(
return &EvmClient{
chainID: chainID,
ethClient: ethClient,
owner: owner,
signer: signer,
owner: address,
keySigner: keySigner,
logger: logger,
metrics: m,
sentTxs: make(map[common.Hash]txnDetails),
Expand Down Expand Up @@ -200,7 +199,7 @@ func (c *EvmClient) Send(ctx context.Context, tx *TxRequest) (common.Hash, error
return common.Hash{}, err
}

signedTx, err := types.SignTx(txnData, types.NewLondonSigner(c.chainID), c.signer)
signedTx, err := c.keySigner.SignTx(txnData, c.chainID)
if err != nil {
c.logger.Error("failed to sign tx", "err", err)
return common.Hash{}, fmt.Errorf("failed to sign tx: %w", err)
Expand Down Expand Up @@ -363,7 +362,7 @@ func (c *EvmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.H
Data: []byte{},
})

signedTx, err := types.SignTx(tx, types.NewLondonSigner(c.chainID), c.signer)
signedTx, err := c.keySigner.SignTx(tx, c.chainID)
if err != nil {
c.logger.Error("failed to sign cancel tx", "err", err)
return common.Hash{}, fmt.Errorf("failed to sign cancel tx: %w", err)
Expand Down
9 changes: 7 additions & 2 deletions pkg/evmclient/evmclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/primevprotocol/mev-commit/pkg/evmclient"
"github.com/primevprotocol/mev-commit/pkg/evmclient/mockevm"
mockkeysigner "github.com/primevprotocol/mev-commit/pkg/keysigner/mock"
"github.com/primevprotocol/mev-commit/pkg/util"
)

Expand All @@ -34,6 +35,8 @@ func TestSendCall(t *testing.T) {
t.Fatal(err)
}

ks := mockkeysigner.NewMockKeySigner(pk, owner)

evm := mockevm.NewMockEvm(
chainID.Uint64(),
mockevm.WithPendingNonceAtFunc(
Expand Down Expand Up @@ -137,7 +140,7 @@ func TestSendCall(t *testing.T) {
),
)

client, err := evmclient.New(owner, pk, evm, util.NewTestLogger(os.Stdout))
client, err := evmclient.New(ks, evm, util.NewTestLogger(os.Stdout))
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -211,6 +214,8 @@ func TestCancel(t *testing.T) {
t.Fatal(err)
}

ks := mockkeysigner.NewMockKeySigner(pk, owner)

evm := mockevm.NewMockEvm(
chainID.Uint64(),
mockevm.WithPendingNonceAtFunc(
Expand Down Expand Up @@ -280,7 +285,7 @@ func TestCancel(t *testing.T) {
),
)

client, err := evmclient.New(owner, pk, evm, util.NewTestLogger(os.Stdout))
client, err := evmclient.New(ks, evm, util.NewTestLogger(os.Stdout))
if err != nil {
t.Fatal(err)
}
Expand Down
Loading

0 comments on commit 0c3aeca

Please sign in to comment.