mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
prysmctl: validator exit (#11515)
* moving voluntary exit command to prysmctl * fixing linting * fixing imports * removing unused import: * refactoring and adding a new unit test * rolling back some changes * fixing parameters * fixing tests * adding to main prysm ctl * refactoring how wallet function works and ux to validator exit * adding interop support * fixing bazel build * fixing if statement * fixing beaconcha.in printout * fixing web3signer bug, missing signing slot info * fixing deep source issues * fixing bazel package visibility for prysmctl * gaz Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
@@ -14,6 +14,7 @@ go_library(
|
||||
"//cmd/prysmctl/checkpointsync:go_default_library",
|
||||
"//cmd/prysmctl/deprecated:go_default_library",
|
||||
"//cmd/prysmctl/p2p:go_default_library",
|
||||
"//cmd/prysmctl/signing:go_default_library",
|
||||
"//cmd/prysmctl/testnet:go_default_library",
|
||||
"//cmd/prysmctl/weaksubjectivity:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/checkpointsync"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/deprecated"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/testnet"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/weaksubjectivity"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -33,4 +34,5 @@ func init() {
|
||||
prysmctlCommands = append(prysmctlCommands, p2p.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, testnet.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, weaksubjectivity.Commands...)
|
||||
prysmctlCommands = append(prysmctlCommands, signing.Commands...)
|
||||
}
|
||||
|
||||
17
cmd/prysmctl/signing/BUILD.bazel
Normal file
17
cmd/prysmctl/signing/BUILD.bazel
Normal file
@@ -0,0 +1,17 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["cmd.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/cmd/prysmctl/signing",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//cmd:go_default_library",
|
||||
"//cmd/validator/accounts:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//runtime/tos:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
],
|
||||
)
|
||||
63
cmd/prysmctl/signing/cmd.go
Normal file
63
cmd/prysmctl/signing/cmd.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package signing
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/tos"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var Commands = []*cli.Command{
|
||||
{
|
||||
Name: "sign",
|
||||
Usage: "signs a message and broadcasts it to the network through the beacon node",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "voluntary-exit",
|
||||
Description: "Performs a voluntary exit on selected accounts",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.AccountPasswordFileFlag,
|
||||
flags.VoluntaryExitPublicKeysFlag,
|
||||
flags.BeaconRPCProviderFlag,
|
||||
flags.Web3SignerURLFlag,
|
||||
flags.Web3SignerPublicValidatorKeysFlag,
|
||||
flags.InteropNumValidators,
|
||||
flags.InteropStartIndex,
|
||||
cmd.GrpcMaxCallRecvMsgSizeFlag,
|
||||
flags.CertFlag,
|
||||
flags.GrpcHeadersFlag,
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.ExitAllFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.RopstenTestnet,
|
||||
features.SepoliaTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tos.VerifyTosAcceptedOrPrompt(cliCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return features.ConfigureValidator(cliCtx)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := accounts.AccountsExit(cliCtx, os.Stdin); err != nil {
|
||||
log.WithError(err).Fatal("Could not perform voluntary exit")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -14,10 +14,12 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/cmd/validator/accounts",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//api/grpc:go_default_library",
|
||||
"//cmd:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/features:go_default_library",
|
||||
"//io/prompt:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//runtime/tos:go_default_library",
|
||||
"//validator/accounts:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
@@ -25,9 +27,14 @@ go_library(
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/client:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer:go_default_library",
|
||||
"//validator/node:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -38,6 +45,7 @@ go_test(
|
||||
"delete_test.go",
|
||||
"exit_test.go",
|
||||
"import_test.go",
|
||||
"wallet_utils_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
@@ -57,7 +65,9 @@ go_test(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/node:go_default_library",
|
||||
"//validator/testing:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_google_uuid//:go_default_library",
|
||||
"@com_github_urfave_cli_v2//:go_default_library",
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/features"
|
||||
@@ -150,42 +148,5 @@ var Commands = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "voluntary-exit",
|
||||
Description: "Performs a voluntary exit on selected accounts",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.AccountPasswordFileFlag,
|
||||
flags.VoluntaryExitPublicKeysFlag,
|
||||
flags.BeaconRPCProviderFlag,
|
||||
cmd.GrpcMaxCallRecvMsgSizeFlag,
|
||||
flags.CertFlag,
|
||||
flags.GrpcHeadersFlag,
|
||||
flags.GrpcRetriesFlag,
|
||||
flags.GrpcRetryDelayFlag,
|
||||
flags.ExitAllFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.RopstenTestnet,
|
||||
features.SepoliaTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tos.VerifyTosAcceptedOrPrompt(cliCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return features.ConfigureValidator(cliCtx)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := accountsExit(cliCtx, os.Stdin); err != nil {
|
||||
log.WithError(err).Fatal("Could not perform voluntary exit")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,19 +4,26 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/pkg/errors"
|
||||
grpcutil "github.com/prysmaticlabs/prysm/v3/api/grpc"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/local"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/node"
|
||||
"github.com/urfave/cli/v2"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func accountsExit(c *cli.Context, r io.Reader) error {
|
||||
w, km, err := walletWithKeymanager(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func AccountsExit(c *cli.Context, r io.Reader) error {
|
||||
var w *wallet.Wallet
|
||||
var km keymanager.IKeymanager
|
||||
var err error
|
||||
dialOpts := client.ConstructDialOptions(
|
||||
c.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name),
|
||||
c.String(flags.CertFlag.Name),
|
||||
@@ -24,15 +31,58 @@ func accountsExit(c *cli.Context, r io.Reader) error {
|
||||
c.Duration(flags.GrpcRetryDelayFlag.Name),
|
||||
)
|
||||
grpcHeaders := strings.Split(c.String(flags.GrpcHeadersFlag.Name), ",")
|
||||
beaconRPCProvider := c.String(flags.BeaconRPCProviderFlag.Name)
|
||||
if !c.IsSet(flags.Web3SignerURLFlag.Name) && !c.IsSet(flags.WalletDirFlag.Name) && !c.IsSet(flags.InteropNumValidators.Name) {
|
||||
return errors.Errorf("No validators found, please provide a prysm wallet directory via flag --%s "+
|
||||
"or a web3signer location with corresponding public keys via flags --%s and --%s ",
|
||||
flags.WalletDirFlag.Name,
|
||||
flags.Web3SignerURLFlag.Name,
|
||||
flags.Web3SignerPublicValidatorKeysFlag,
|
||||
)
|
||||
}
|
||||
if c.IsSet(flags.InteropNumValidators.Name) {
|
||||
km, err = local.NewInteropKeymanager(c.Context, c.Uint64(flags.InteropStartIndex.Name), c.Uint64(flags.InteropNumValidators.Name))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not generate interop keys for key manager")
|
||||
}
|
||||
w = &wallet.Wallet{}
|
||||
} else if c.IsSet(flags.Web3SignerURLFlag.Name) {
|
||||
ctx := grpcutil.AppendHeaders(c.Context, grpcHeaders)
|
||||
conn, err := grpc.DialContext(ctx, beaconRPCProvider, dialOpts...)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not dial endpoint %s", beaconRPCProvider)
|
||||
}
|
||||
nodeClient := ethpb.NewNodeClient(conn)
|
||||
resp, err := nodeClient.GetGenesis(c.Context, &empty.Empty{})
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get genesis info")
|
||||
}
|
||||
if err := conn.Close(); err != nil {
|
||||
log.WithError(err).Error("Failed to close connection")
|
||||
}
|
||||
config, err := node.Web3SignerConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not configure web3signer")
|
||||
}
|
||||
config.GenesisValidatorsRoot = resp.GenesisValidatorsRoot
|
||||
w, km, err = walletWithWeb3SignerKeymanager(c, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
w, km, err = walletWithKeymanager(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWallet(w),
|
||||
accounts.WithKeymanager(km),
|
||||
accounts.WithGRPCDialOpts(dialOpts),
|
||||
accounts.WithBeaconRPCProvider(c.String(flags.BeaconRPCProviderFlag.Name)),
|
||||
accounts.WithBeaconRPCProvider(beaconRPCProvider),
|
||||
accounts.WithGRPCHeaders(grpcHeaders),
|
||||
}
|
||||
|
||||
// Get full set of public keys from the keymanager.
|
||||
validatingPublicKeys, err := km.FetchValidatingPublicKeys(c.Context)
|
||||
if err != nil {
|
||||
@@ -48,7 +98,6 @@ func accountsExit(c *cli.Context, r io.Reader) error {
|
||||
}
|
||||
opts = append(opts, accounts.WithRawPubKeys(rawPubKey))
|
||||
opts = append(opts, accounts.WithFormattedPubKeys(formattedPubKeys))
|
||||
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/iface"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
remote_web3signer "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-web3signer"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -18,8 +19,6 @@ func walletWithKeymanager(c *cli.Context) (*wallet.Wallet, keymanager.IKeymanage
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not open wallet")
|
||||
}
|
||||
// TODO(#9883) - Remove this when we have a better way to handle this. this is fine.
|
||||
// genesis root is not set here which is used for sign function, but fetch keys should be fine.
|
||||
km, err := w.InitializeKeymanager(c.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
if err != nil && strings.Contains(err.Error(), keymanager.IncorrectPasswordErrMsg) {
|
||||
return nil, nil, errors.New("wrong wallet password entered")
|
||||
@@ -28,4 +27,14 @@ func walletWithKeymanager(c *cli.Context) (*wallet.Wallet, keymanager.IKeymanage
|
||||
return nil, nil, errors.Wrap(err, accounts.ErrCouldNotInitializeKeymanager)
|
||||
}
|
||||
return w, km, nil
|
||||
|
||||
}
|
||||
|
||||
func walletWithWeb3SignerKeymanager(c *cli.Context, config *remote_web3signer.SetupConfig) (*wallet.Wallet, keymanager.IKeymanager, error) {
|
||||
w := wallet.NewWalletForWeb3Signer()
|
||||
km, err := w.InitializeKeymanager(c.Context, iface.InitKeymanagerConfig{ListenForChanges: false, Web3SignerConfig: config})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return w, km, nil
|
||||
}
|
||||
|
||||
94
cmd/validator/accounts/wallet_utils_test.go
Normal file
94
cmd/validator/accounts/wallet_utils_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/local"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/node"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func TestWalletWithKeymanager(t *testing.T) {
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWalletDir(walletDir),
|
||||
accounts.WithKeymanagerType(keymanager.Local),
|
||||
accounts.WithWalletPassword(password),
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
require.NoError(t, err)
|
||||
w, err := acc.WalletCreate(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
newKm, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accNames, err := newKm.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(accNames), 0)
|
||||
|
||||
// Create 2 keys.
|
||||
createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
createKeystore(t, keysDir)
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
w, k, err := walletWithKeymanager(cliCtx)
|
||||
require.NoError(t, err)
|
||||
keys, err := k.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(keys), 2)
|
||||
require.Equal(t, w.KeymanagerKind(), keymanager.Local)
|
||||
}
|
||||
|
||||
func TestWalletWithKeymanager_web3signer(t *testing.T) {
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.Web3SignerURLFlag.Name, "http://localhost:12345", "web3signer")
|
||||
c := &cli.StringSliceFlag{
|
||||
Name: "validators-external-signer-public-keys",
|
||||
}
|
||||
err := c.Apply(set)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, set.Set(flags.Web3SignerURLFlag.Name, "http://localhost:12345"))
|
||||
require.NoError(t, set.Set(flags.Web3SignerPublicValidatorKeysFlag.Name, "0xa2b5aaad9c6efefe7bb9b1243a043404f3362937cfb6b31833929833173f476630ea2cfeb0d9ddf15f97ca8685948820"))
|
||||
ctx := cli.NewContext(&app, set, nil)
|
||||
bytes, err := hexutil.Decode("0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2")
|
||||
require.NoError(t, err)
|
||||
config, err := node.Web3SignerConfig(ctx)
|
||||
require.NoError(t, err)
|
||||
config.GenesisValidatorsRoot = bytes
|
||||
w, k, err := walletWithWeb3SignerKeymanager(ctx, config)
|
||||
require.NoError(t, err)
|
||||
keys, err := k.FetchValidatingPublicKeys(ctx.Context)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, len(keys), 1)
|
||||
require.Equal(t, w.KeymanagerKind(), keymanager.Web3Signer)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ go_library(
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/cmd/validator/flags",
|
||||
visibility = [
|
||||
"//cmd/prysmctl:__subpackages__",
|
||||
"//cmd/validator:__subpackages__",
|
||||
"//testing/endtoend:__subpackages__",
|
||||
"//validator:__subpackages__",
|
||||
|
||||
Reference in New Issue
Block a user