Remove Deposit Command from Validator Client (#7379)

* remove deposit code
* Merge refs/heads/master into remove-deposit
This commit is contained in:
Raul Jordan
2020-09-30 01:42:16 -05:00
committed by GitHub
parent 3b5ef50733
commit 16cdcf5dec
4 changed files with 0 additions and 440 deletions

View File

@@ -7,7 +7,6 @@ go_library(
"accounts_backup.go",
"accounts_create.go",
"accounts_delete.go",
"accounts_deposit.go",
"accounts_exit.go",
"accounts_helper.go",
"accounts_import.go",
@@ -30,7 +29,6 @@ go_library(
"//shared/cmd:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/fileutil:go_default_library",
"//shared/params:go_default_library",
"//shared/petnames:go_default_library",
"//shared/promptutil:go_default_library",
"//validator/accounts/v2/prompt:go_default_library",
@@ -61,7 +59,6 @@ go_test(
"accounts_backup_test.go",
"accounts_create_test.go",
"accounts_delete_test.go",
"accounts_deposit_test.go",
"accounts_exit_test.go",
"accounts_import_test.go",
"accounts_list_test.go",

View File

@@ -1,207 +0,0 @@
package v2
import (
"fmt"
"os"
"strings"
"time"
"github.com/manifoldco/promptui"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/fileutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/promptutil"
"github.com/prysmaticlabs/prysm/validator/accounts/v2/prompt"
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
"github.com/prysmaticlabs/prysm/validator/flags"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
"github.com/urfave/cli/v2"
)
// SendDepositCli transaction for user specified accounts via an interactive
// CLI process or via command-line flags.
func SendDepositCli(cliCtx *cli.Context) error {
w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
return nil, errors.New(
"no wallet found, nothing to deposit",
)
})
if err != nil {
return errors.Wrap(err, "could not open wallet")
}
keymanager, err := w.InitializeKeymanager(
cliCtx.Context,
true, /* skip mnemonic confirm */
)
if err != nil && strings.Contains(err.Error(), "invalid checksum") {
return errors.New("wrong wallet password entered")
}
if err != nil {
return errors.Wrap(err, "could not initialize keymanager")
}
switch w.KeymanagerKind() {
case v2keymanager.Derived:
km, ok := keymanager.(*derived.Keymanager)
if !ok {
return errors.New("could not assert keymanager interface to concrete type")
}
depositConfig, err := createDepositConfig(cliCtx, km)
if err != nil {
return errors.Wrap(err, "could not initialize deposit config")
}
if err := km.SendDepositTx(depositConfig); err != nil {
return err
}
default:
return errors.New("only Prysm HD wallets support sending deposits at the moment")
}
return nil
}
func createDepositConfig(cliCtx *cli.Context, km *derived.Keymanager) (*derived.SendDepositConfig, error) {
pubKeysBytes, err := km.FetchValidatingPublicKeys(cliCtx.Context)
if err != nil {
return nil, errors.Wrap(err, "could not fetch validating public keys")
}
pubKeys := make([]bls.PublicKey, len(pubKeysBytes))
for i, pk := range pubKeysBytes {
pubKeys[i], err = bls.PublicKeyFromBytes(pk[:])
if err != nil {
return nil, errors.Wrap(err, "could not parse BLS public key")
}
}
// Allow the user to interactively select the accounts to deposit or optionally
// provide them via cli flags as a string of comma-separated, hex strings. If the user has
// selected to deposit all accounts, we skip this part.
if !cliCtx.IsSet(flags.DepositAllAccountsFlag.Name) {
pubKeys, err = filterPublicKeysFromUserInput(
cliCtx,
flags.DepositPublicKeysFlag,
pubKeysBytes,
prompt.SelectAccountsDepositPromptText,
)
if err != nil {
return nil, errors.Wrap(err, "could not filter validating public keys for deposit")
}
}
web3Provider := cliCtx.String(flags.HTTPWeb3ProviderFlag.Name)
// Enter the web3provider information.
if web3Provider == "" {
web3Provider, err = promptutil.DefaultAndValidatePrompt(
"Enter the HTTP address of your eth1 endpoint for the Goerli testnet",
cliCtx.String(flags.HTTPWeb3ProviderFlag.Name),
func(input string) error {
return nil
},
)
if err != nil {
return nil, errors.Wrap(err, "could not validate web3 provider endpoint")
}
}
depositDelaySeconds := cliCtx.Int(flags.DepositDelaySecondsFlag.Name)
config := &derived.SendDepositConfig{
DepositContractAddress: cliCtx.String(flags.DepositContractAddressFlag.Name),
DepositDelaySeconds: time.Duration(depositDelaySeconds) * time.Second,
DepositPublicKeys: pubKeys,
Web3Provider: web3Provider,
}
if !cliCtx.Bool(flags.SkipDepositConfirmationFlag.Name) {
confirmDepositPrompt := "You are about to send %d ETH into contract address %s for %d eth2 validator accounts. " +
"Are you sure you want to do this? Enter the words 'yes I do' to continue"
gweiPerEth := params.BeaconConfig().GweiPerEth
ethDepositTotal := uint64(len(pubKeys)) * params.BeaconConfig().MaxEffectiveBalance / gweiPerEth
if _, err := promptutil.ValidatePrompt(
os.Stdin,
fmt.Sprintf(confirmDepositPrompt, ethDepositTotal, config.DepositContractAddress, len(pubKeys)),
func(input string) error {
if input != "yes I do" {
return errors.New("please enter 'yes I do' or exit")
}
return nil
},
); err != nil {
return nil, errors.Wrap(err, "could not confirm deposit acknowledgement")
}
}
// If the user passes any of the specified flags, we read them and return the
// config struct directly, bypassing any CLI input.
hasPrivateKey := cliCtx.IsSet(flags.Eth1PrivateKeyFileFlag.Name)
hasEth1Keystore := cliCtx.IsSet(flags.Eth1KeystoreUTCPathFlag.Name)
if hasPrivateKey || hasEth1Keystore {
if hasPrivateKey {
fileBytes, err := fileutil.ReadFileAsBytes(cliCtx.String(flags.Eth1PrivateKeyFileFlag.Name))
if err != nil {
return nil, err
}
config.Eth1PrivateKey = strings.TrimRight(string(fileBytes), "\r\n")
} else {
config.Eth1KeystoreUTCFile = cliCtx.String(flags.Eth1KeystoreUTCPathFlag.Name)
if cliCtx.IsSet(flags.Eth1KeystorePasswordFileFlag.Name) {
config.Eth1KeystorePasswordFile = cliCtx.String(flags.Eth1KeystorePasswordFileFlag.Name)
} else {
config.Eth1KeystorePasswordFile, err = prompt.InputWeakPassword(
cliCtx,
flags.Eth1KeystorePasswordFileFlag,
"Enter the file path of a text file containing your eth1 keystore password",
)
if err != nil {
return nil, errors.Wrap(err, "could not read eth1 keystore password file path")
}
}
}
return config, nil
}
usePrivateKeyPrompt := "Inputting an eth1 private key hex string directly"
useEth1KeystorePrompt := "Using an encrypted eth1 keystore UTC file"
eth1Prompt := promptui.Select{
Label: "Select how you wish to sign your eth1 transaction",
Items: []string{
usePrivateKeyPrompt,
useEth1KeystorePrompt,
},
}
_, selection, err := eth1Prompt.Run()
if err != nil {
return nil, err
}
// If the user wants to proceed by inputting their private key directly, ask for it securely.
if selection == usePrivateKeyPrompt {
eth1PrivateKeyString, err := promptutil.PasswordPrompt(
"Enter the hex string value of your eth1 private key",
promptutil.NotEmpty,
)
if err != nil {
return nil, errors.Wrap(err, "could not read eth1 private key string")
}
config.Eth1PrivateKey = strings.TrimRight(eth1PrivateKeyString, "\r\n")
} else if selection == useEth1KeystorePrompt {
// Otherwise, ask the user for paths to their keystore UTC file and its password.
eth1KeystoreUTCFile, err := promptutil.DefaultAndValidatePrompt(
"Enter the file path for your encrypted, eth1 keystore-utc file",
cliCtx.String(flags.Eth1KeystoreUTCPathFlag.Name),
func(input string) error {
return nil
},
)
if err != nil {
return nil, errors.Wrap(err, "could not read eth1 keystore UTC path")
}
eth1KeystorePasswordFile, err := prompt.InputWeakPassword(
cliCtx,
flags.Eth1KeystorePasswordFileFlag,
"Enter the file path to a text file containing your eth1 keystore password",
)
if err != nil {
return nil, errors.Wrap(err, "could not read eth1 keystore password file path")
}
config.Eth1KeystoreUTCFile = eth1KeystoreUTCFile
config.Eth1KeystorePasswordFile = eth1KeystorePasswordFile
}
return config, nil
}

View File

@@ -1,202 +0,0 @@
package v2
import (
"encoding/hex"
"errors"
"flag"
"io/ioutil"
"os"
"strconv"
"strings"
"testing"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
"github.com/prysmaticlabs/prysm/validator/accounts/v2/wallet"
"github.com/prysmaticlabs/prysm/validator/flags"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
"github.com/urfave/cli/v2"
)
type depositTestWalletConfig struct {
walletDir string
walletPasswordFile string
eth1KeystoreFile string
eth1KeystorePasswordFile string
eth1PrivateKeyFile string
httpWeb3ProviderFlag string
publicKeysFlag string
depositAllAccountsFlag bool
skipDepositConfirmationFlag bool
keymanagerKind v2keymanager.Kind
}
func setupWalletCtxforDeposits(
t *testing.T,
cfg *depositTestWalletConfig,
) *cli.Context {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.WalletDirFlag.Name, cfg.walletDir, "")
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
set.String(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile, "")
set.String(flags.HTTPWeb3ProviderFlag.Name, cfg.httpWeb3ProviderFlag, "")
set.String(flags.Eth1KeystoreUTCPathFlag.Name, cfg.eth1KeystoreFile, "")
set.String(flags.Eth1KeystorePasswordFileFlag.Name, cfg.eth1KeystorePasswordFile, "")
set.String(flags.Eth1PrivateKeyFileFlag.Name, cfg.eth1PrivateKeyFile, "")
set.String(flags.DepositPublicKeysFlag.Name, cfg.publicKeysFlag, "")
set.Bool(flags.DepositAllAccountsFlag.Name, cfg.depositAllAccountsFlag, "")
set.Bool(flags.SkipDepositConfirmationFlag.Name, cfg.skipDepositConfirmationFlag, "")
assert.NoError(t, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
assert.NoError(t, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
assert.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile))
assert.NoError(t, set.Set(flags.HTTPWeb3ProviderFlag.Name, cfg.httpWeb3ProviderFlag))
if cfg.eth1KeystoreFile != "" {
assert.NoError(t, set.Set(flags.Eth1KeystoreUTCPathFlag.Name, cfg.eth1KeystoreFile))
assert.NoError(t, set.Set(flags.Eth1KeystorePasswordFileFlag.Name, cfg.eth1KeystorePasswordFile))
}
if cfg.eth1PrivateKeyFile != "" {
assert.NoError(t, set.Set(flags.Eth1PrivateKeyFileFlag.Name, cfg.eth1PrivateKeyFile))
}
if cfg.publicKeysFlag != "" {
assert.NoError(t, set.Set(flags.DepositPublicKeysFlag.Name, cfg.publicKeysFlag))
}
if cfg.depositAllAccountsFlag == true {
assert.NoError(t, set.Set(flags.DepositAllAccountsFlag.Name, strconv.FormatBool(cfg.depositAllAccountsFlag)))
}
assert.NoError(t, set.Set(flags.SkipDepositConfirmationFlag.Name, strconv.FormatBool(cfg.skipDepositConfirmationFlag)))
return cli.NewContext(&app, set, nil)
}
func TestCreateDepositConfig(t *testing.T) {
walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
// First, create the wallet and several accounts
cliCtx := setupWalletCtx(t, &testWalletConfig{
keymanagerKind: v2keymanager.Derived,
walletDir: walletDir,
walletPasswordFile: passwordFilePath,
skipDepositConfirm: true,
})
w, err := CreateAndSaveWalletCli(cliCtx)
require.NoError(t, err)
err = CreateAccount(cliCtx.Context, &CreateAccountConfig{
Wallet: w,
NumAccounts: 3,
})
require.NoError(t, err)
keymanager, err := w.InitializeKeymanager(
cliCtx.Context,
true, /* skip mnemonic confirm */
)
require.NoError(t, err)
// Save public keys for comparison and selection purposes later
pubkeys, err := keymanager.FetchValidatingPublicKeys(cliCtx.Context)
require.NoError(t, err)
var hexPubkeys []string
for _, pubkey := range pubkeys {
encoded := make([]byte, hex.EncodedLen(len(pubkey)))
hex.Encode(encoded, pubkey[:])
hexPubkeys = append(hexPubkeys, string(encoded))
}
// Remove the last key so that we can select a portion and not all of the accounts later
hexPubkeys = hexPubkeys[:len(hexPubkeys)-1]
hexPubkeysString := strings.Join(hexPubkeys, ",")
// Create a file holding the test ETH1 private key
eth1PrivateKeyFile, err := ioutil.TempFile("", "testing")
require.NoError(t, err)
defer func() {
err = eth1PrivateKeyFile.Close()
require.NoError(t, err)
err = os.Remove(eth1PrivateKeyFile.Name())
require.NoError(t, err)
}()
_, err = eth1PrivateKeyFile.WriteString("This should be an ETH1 private key")
require.NoError(t, err)
// First we test the behavior when depositAllAccountsFlag is set to true
depositConfig := createDepositConfigHelper(t, &depositTestWalletConfig{
keymanagerKind: v2keymanager.Derived,
walletDir: walletDir,
walletPasswordFile: passwordFilePath,
skipDepositConfirmationFlag: true,
depositAllAccountsFlag: true,
httpWeb3ProviderFlag: "http://localhost:8545",
eth1PrivateKeyFile: eth1PrivateKeyFile.Name(),
})
require.Equal(t, 3, len(depositConfig.DepositPublicKeys), "wrong number of public keys")
require.Equal(t, "This should be an ETH1 private key", depositConfig.Eth1PrivateKey, "eth1 private key does not match")
require.Equal(t, "http://localhost:8545", depositConfig.Web3Provider, "web3 provider does not match")
require.Equal(t, "", depositConfig.Eth1KeystoreUTCFile, "keystore file path should be empty")
require.Equal(t, "", depositConfig.Eth1KeystorePasswordFile, "keystore password file path should be empty")
// Test the case of providing the public keys via command-line. We also pass in the test eth1 private key file.
// hexPubkeysString holds 1 less than all the accounts.
depositConfig = createDepositConfigHelper(t, &depositTestWalletConfig{
keymanagerKind: v2keymanager.Derived,
walletDir: walletDir,
walletPasswordFile: passwordFilePath,
skipDepositConfirmationFlag: true,
publicKeysFlag: hexPubkeysString,
httpWeb3ProviderFlag: "http://localhost:8545",
eth1PrivateKeyFile: eth1PrivateKeyFile.Name(),
})
require.Equal(t, 2, len(depositConfig.DepositPublicKeys), "wrong number of public keys")
// Compare the keys in the config object with the keys we obtained earlier from the keymanager
for keyNum, configPubKey := range depositConfig.DepositPublicKeys {
for index, eachByte := range bytesutil.ToBytes48(configPubKey.Marshal()) {
if eachByte != pubkeys[keyNum][index] {
require.NoError(t, errors.New("public keys do not match"))
}
}
}
// Now we test when private key file is not provided but rather the keystore and keystore password files
depositConfig = createDepositConfigHelper(t, &depositTestWalletConfig{
keymanagerKind: v2keymanager.Derived,
walletDir: walletDir,
walletPasswordFile: passwordFilePath,
skipDepositConfirmationFlag: true,
depositAllAccountsFlag: true,
httpWeb3ProviderFlag: "http://localhost:8545",
eth1KeystoreFile: "This would be eth1 keystore file path",
eth1KeystorePasswordFile: "This would be eth1 keystore password file path",
})
require.Equal(t, 3, len(depositConfig.DepositPublicKeys), "wrong number of public keys")
require.Equal(t, "This would be eth1 keystore file path", depositConfig.Eth1KeystoreUTCFile,
"eth1 keystore file path incorrect")
require.Equal(t, "This would be eth1 keystore password file path", depositConfig.Eth1KeystorePasswordFile,
"eth1 keystore password file path incorrect")
require.Equal(t, "", depositConfig.Eth1PrivateKey, "eth1 private key should be empty string")
}
// createDepositConfigHelper returns a SendDepositConfig when given a particular wallet configuration.
func createDepositConfigHelper(t *testing.T, config *depositTestWalletConfig) *derived.SendDepositConfig {
cliCtx := setupWalletCtxforDeposits(t, config)
w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
err := errors.New("could not open wallet")
require.NoError(t, err)
return nil, err
})
require.NoError(t, err)
keymanager, err := w.InitializeKeymanager(
cliCtx.Context,
true, /* skip mnemonic confirm */
)
require.NoError(t, err)
km, ok := keymanager.(*derived.Keymanager)
require.Equal(t, true, ok, "keymanager must be derived type")
// Now we finally call the function we are testing.
depositConfig, err := createDepositConfig(cliCtx, km)
require.NoError(t, err)
return depositConfig
}

View File

@@ -151,33 +151,5 @@ this command outputs a deposit data string which is required to become a validat
return nil
},
},
{
Name: "deposit",
Description: "Submits a deposit to the eth2 deposit contract for a validator key by connecting " +
"to an eth1 endpoint to submit a transaction. Requires signing the transaction with an eth1 private key",
Flags: []cli.Flag{
flags.WalletDirFlag,
flags.WalletPasswordFileFlag,
flags.HTTPWeb3ProviderFlag,
flags.Eth1KeystoreUTCPathFlag,
flags.Eth1KeystorePasswordFileFlag,
flags.Eth1PrivateKeyFileFlag,
flags.DepositDelaySecondsFlag,
flags.DepositContractAddressFlag,
flags.DepositPublicKeysFlag,
flags.SkipDepositConfirmationFlag,
flags.DepositAllAccountsFlag,
featureconfig.AltonaTestnet,
featureconfig.OnyxTestnet,
featureconfig.SpadinaTestnet,
},
Action: func(cliCtx *cli.Context) error {
featureconfig.ConfigureValidator(cliCtx)
if err := SendDepositCli(cliCtx); err != nil {
log.Fatalf("Could not send validator deposit(s): %v", err)
}
return nil
},
},
},
}