From fc9c4cfe0c0a7420e9c4e40ccd53d0ba4906d511 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Mon, 20 Jul 2020 13:38:51 +0100 Subject: [PATCH] Tidy-ups --- cmd/accountcreate.go | 61 +++++--- cmd/accountimport.go | 27 +++- cmd/accountinfo.go | 71 +++++---- cmd/accountkey.go | 38 +++-- cmd/accountlock.go | 40 ++--- cmd/accountunlock.go | 36 +++-- cmd/accountwithdrawalcredentials.go | 83 ++++++++++ cmd/blockinfo.go | 51 ++++--- cmd/chaininfo.go | 16 +- cmd/chainstatus.go | 15 +- cmd/depositverify.go | 2 +- cmd/nodeinfo.go | 12 +- cmd/root.go | 229 ++++++++++++---------------- cmd/signature.go | 25 ++- cmd/signatureaggregate.go | 110 +++++++++++++ cmd/signaturesign.go | 72 ++++----- cmd/signatureverify.go | 64 ++++---- cmd/signing.go | 160 +++++++++++++++++++ cmd/validatordepositdata.go | 63 ++++---- cmd/validatorexit.go | 37 +++-- cmd/validatorinfo.go | 23 ++- cmd/version.go | 2 +- cmd/wallet.go | 16 +- cmd/walletaccounts.go | 61 +++----- cmd/walletcreate.go | 33 ++-- cmd/walletdelete.go | 7 +- cmd/walletexport.go | 13 +- cmd/walletimport.go | 5 +- cmd/walletinfo.go | 13 +- cmd/walletlist.go | 16 +- cmd/walletseed.go | 25 ++- go.mod | 27 ++-- go.sum | 150 +++++++++--------- grpc/beaconchain.go | 59 +++++-- grpc/beaconnode.go | 22 ++- util/bls.go | 31 ++++ 36 files changed, 1146 insertions(+), 569 deletions(-) create mode 100644 cmd/accountwithdrawalcredentials.go create mode 100644 cmd/signatureaggregate.go create mode 100644 cmd/signing.go create mode 100644 util/bls.go diff --git a/cmd/accountcreate.go b/cmd/accountcreate.go index b9fba81..cb6f69e 100644 --- a/cmd/accountcreate.go +++ b/cmd/accountcreate.go @@ -1,4 +1,4 @@ -// Copyright © 2019 Weald Technology Trading +// Copyright © 2019, 2020 Weald Technology Trading // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -14,10 +14,12 @@ package cmd import ( + "context" "fmt" "os" "github.com/spf13/cobra" + "github.com/spf13/viper" e2wallet "github.com/wealdtech/go-eth2-wallet" e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) @@ -31,31 +33,48 @@ var accountCreateCmd = &cobra.Command{ In quiet mode this will return 0 if the account is created successfully, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "account create not available with remote wallets") - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - wallet, err := walletFromPath(rootAccount) + wallet, err := openWallet() errCheck(err, "Failed to access wallet") - + outputIf(debug, fmt.Sprintf("Opened wallet %q of type %s", wallet.Name(), wallet.Type())) if wallet.Type() == "hierarchical deterministic" { - assert(getWalletPassphrase() != "", "--walletpassphrase is required to create new accounts with hierarchical deterministic wallets") + assert(getWalletPassphrase() != "", "walletpassphrase is required to create new accounts with hierarchical deterministic wallets") + } + locker, isLocker := wallet.(e2wtypes.WalletLocker) + if isLocker { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet") } - _, err = accountFromPath(rootAccount) - assert(err != nil, "Account already exists") - err = wallet.Unlock([]byte(getWalletPassphrase())) - errCheck(err, "Failed to unlock wallet") - - _, accountName, err := e2wallet.WalletAndAccountNames(rootAccount) + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) errCheck(err, "Failed to obtain account name") - walletAccountCreator, ok := wallet.(e2wtypes.WalletAccountCreator) - assert(ok, "wallet does not allow account creation") - - account, err := walletAccountCreator.CreateAccount(accountName, []byte(getPassphrase())) + var account e2wtypes.Account + if viper.GetUint("participants") > 0 { + // Want a distributed account. + distributedCreator, isDistributedCreator := wallet.(e2wtypes.WalletDistributedAccountCreator) + assert(isDistributedCreator, "Wallet does not support distributed account creation") + outputIf(debug, fmt.Sprintf("Distributed account has %d/%d threshold", viper.GetUint32("signing-threshold"), viper.GetUint32("participants"))) + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + account, err = distributedCreator.CreateDistributedAccount(ctx, accountName, viper.GetUint32("participants"), viper.GetUint32("signing-threshold"), []byte(getPassphrase())) + } else { + creator, isCreator := wallet.(e2wtypes.WalletAccountCreator) + assert(isCreator, "Wallet does not support account creation") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + account, err = creator.CreateAccount(ctx, accountName, []byte(getPassphrase())) + } errCheck(err, "Failed to create account") - outputIf(verbose, fmt.Sprintf("0x%048x", account.PublicKey().Marshal())) + if pubKeyProvider, ok := account.(e2wtypes.AccountCompositePublicKeyProvider); ok { + outputIf(verbose, fmt.Sprintf("%#x", pubKeyProvider.CompositePublicKey().Marshal())) + } else if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + outputIf(verbose, fmt.Sprintf("%#x", pubKeyProvider.PublicKey().Marshal())) + } + os.Exit(_exitSuccess) }, } @@ -63,4 +82,12 @@ In quiet mode this will return 0 if the account is created successfully, otherwi func init() { accountCmd.AddCommand(accountCreateCmd) accountFlags(accountCreateCmd) + accountCreateCmd.Flags().Uint32("participants", 0, "Number of participants (for distributed accounts)") + if err := viper.BindPFlag("participants", accountCreateCmd.Flags().Lookup("participants")); err != nil { + panic(err) + } + accountCreateCmd.Flags().Uint32("signing-threshold", 0, "Signing threshold (for distributed accounts)") + if err := viper.BindPFlag("signing-threshold", accountCreateCmd.Flags().Lookup("signing-threshold")); err != nil { + panic(err) + } } diff --git a/cmd/accountimport.go b/cmd/accountimport.go index a51de82..2108c15 100644 --- a/cmd/accountimport.go +++ b/cmd/accountimport.go @@ -14,10 +14,12 @@ package cmd import ( + "context" "fmt" "os" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/wealdtech/go-bytesutil" e2wallet "github.com/wealdtech/go-eth2-wallet" e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" @@ -35,32 +37,41 @@ var accountImportCmd = &cobra.Command{ In quiet mode this will return 0 if the account is imported successfully, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { assert(!remote, "account import not available with remote wallets") - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") passphrase := getPassphrase() assert(accountImportKey != "", "--key is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + key, err := bytesutil.FromHexString(accountImportKey) errCheck(err, "Invalid key") - w, err := walletFromPath(rootAccount) + w, err := walletFromPath(viper.GetString("account")) errCheck(err, "Failed to access wallet") _, ok := w.(e2wtypes.WalletAccountImporter) assert(ok, fmt.Sprintf("wallets of type %q do not allow importing accounts", w.Type())) - _, err = accountFromPath(rootAccount) + _, err = accountFromPath(ctx, viper.GetString("account")) assert(err != nil, "Account already exists") - err = w.Unlock([]byte(getWalletPassphrase())) - errCheck(err, "Failed to unlock wallet") + locker, isLocker := w.(e2wtypes.WalletLocker) + if isLocker { + errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet") + } - _, accountName, err := e2wallet.WalletAndAccountNames(rootAccount) + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) errCheck(err, "Failed to obtain account name") - account, err := w.(e2wtypes.WalletAccountImporter).ImportAccount(accountName, key, []byte(passphrase)) + account, err := w.(e2wtypes.WalletAccountImporter).ImportAccount(ctx, accountName, key, []byte(passphrase)) errCheck(err, "Failed to create account") - outputIf(verbose, fmt.Sprintf("0x%048x", account.PublicKey().Marshal())) + pubKey, err := bestPublicKey(account) + if err == nil { + outputIf(verbose, fmt.Sprintf("%#x", pubKey.Marshal())) + } + os.Exit(_exitSuccess) }, } diff --git a/cmd/accountinfo.go b/cmd/accountinfo.go index d6ed89c..a62f190 100644 --- a/cmd/accountinfo.go +++ b/cmd/accountinfo.go @@ -19,8 +19,11 @@ import ( "os" "github.com/spf13/cobra" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" + "github.com/spf13/viper" + e2types "github.com/wealdtech/go-eth2-types/v2" util "github.com/wealdtech/go-eth2-util" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var accountInfoCmd = &cobra.Command{ @@ -32,33 +35,49 @@ var accountInfoCmd = &cobra.Command{ In quiet mode this will return 0 if the account exists, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - var withdrawalCredentials []byte - if remote { - listerClient := pb.NewListerClient(remoteGRPCConn) - listAccountsReq := &pb.ListAccountsRequest{ - Paths: []string{ - rootAccount, - }, + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + + // Disallow wildcards (for now) + assert(fmt.Sprintf("%s/%s", wallet.Name(), account.Name()) == viper.GetString("account"), "Mismatched account name") + + if quiet { + os.Exit(_exitSuccess) + } + + outputIf(verbose, fmt.Sprintf("UUID: %v", account.ID())) + var withdrawalPubKey e2types.PublicKey + if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + fmt.Printf("Public key: %#x\n", pubKeyProvider.PublicKey().Marshal()) + // May be overwritten later, but grab it for now. + withdrawalPubKey = pubKeyProvider.PublicKey() + } + if distributedAccount, ok := account.(e2wtypes.DistributedAccount); ok { + fmt.Printf("Composite public key: %#x\n", distributedAccount.CompositePublicKey().Marshal()) + fmt.Printf("Signing threshold: %d/%d\n", distributedAccount.SigningThreshold(), len(distributedAccount.Participants())) + withdrawalPubKey = distributedAccount.CompositePublicKey() + } + if verbose { + withdrawalCredentials := util.SHA256(withdrawalPubKey.Marshal()) + withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX + fmt.Printf("Withdrawal credentials: %#x\n", withdrawalCredentials) + } + if pathProvider, ok := account.(e2wtypes.AccountPathProvider); ok { + if pathProvider.Path() != "" { + fmt.Printf("Path: %s\n", pathProvider.Path()) } - resp, err := listerClient.ListAccounts(context.Background(), listAccountsReq) - errCheck(err, "Failed to access account") - assert(resp.State == pb.ResponseState_SUCCEEDED, "No such account") - assert(len(resp.Accounts) == 1, "No such account") - fmt.Printf("Public key: %#x\n", resp.Accounts[0].PublicKey) - withdrawalCredentials = util.SHA256(resp.Accounts[0].PublicKey) - withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX - outputIf(verbose, fmt.Sprintf("Withdrawal credentials: %#x", withdrawalCredentials)) - } else { - account, err := accountFromPath(rootAccount) - errCheck(err, "Failed to access wallet") - outputIf(verbose, fmt.Sprintf("UUID: %v", account.ID())) - outputIf(!quiet, fmt.Sprintf("Public key: %#x", account.PublicKey().Marshal())) - withdrawalCredentials = util.SHA256(account.PublicKey().Marshal()) - withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX - outputIf(verbose, fmt.Sprintf("Withdrawal credentials: %#x", withdrawalCredentials)) - outputIf(verbose && account.Path() != "", fmt.Sprintf("Path: %s", account.Path())) } os.Exit(_exitSuccess) diff --git a/cmd/accountkey.go b/cmd/accountkey.go index 9b73133..bf76693 100644 --- a/cmd/accountkey.go +++ b/cmd/accountkey.go @@ -14,11 +14,13 @@ package cmd import ( + "context" "fmt" "os" "github.com/spf13/cobra" - types "github.com/wealdtech/go-eth2-wallet-types/v2" + "github.com/spf13/viper" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) // accountKeyCmd represents the account key command @@ -32,29 +34,33 @@ var accountKeyCmd = &cobra.Command{ In quiet mode this will return 0 if the key can be obtained, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { assert(!remote, "account keys not available with remote wallets") - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - account, err := accountFromPath(rootAccount) + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + account, err := accountFromPath(ctx, viper.GetString("account")) errCheck(err, "Failed to access account") - _, ok := account.(types.AccountPrivateKeyProvider) - assert(ok, fmt.Sprintf("account %q does not provide its private key", rootAccount)) + privateKeyProvider, isPrivateKeyProvider := account.(e2wtypes.AccountPrivateKeyProvider) + assert(isPrivateKeyProvider, fmt.Sprintf("account %q does not provide its private key", viper.GetString("account"))) - unlocked := false - for _, passphrase := range getPassphrases() { - err = account.Unlock([]byte(passphrase)) - if err == nil { - unlocked = true - break + if locker, isLocker := account.(e2wtypes.AccountLocker); isLocker { + unlocked := false + for _, passphrase := range getPassphrases() { + err = locker.Unlock(ctx, []byte(passphrase)) + if err == nil { + unlocked = true + break + } } + assert(unlocked, "Failed to unlock account to obtain private key") + defer errCheck(locker.Lock(context.Background()), "failed to re-lock account") } - assert(unlocked, "Failed to unlock account to obtain private key") - defer account.Lock() - privateKey, err := account.(types.AccountPrivateKeyProvider).PrivateKey() + privateKey, err := privateKeyProvider.PrivateKey(ctx) errCheck(err, "Failed to obtain private key") - account.Lock() - outputIf(!quiet, fmt.Sprintf("%#064x", privateKey.Marshal())) + outputIf(!quiet, fmt.Sprintf("%#x", privateKey.Marshal())) os.Exit(_exitSuccess) }, } diff --git a/cmd/accountlock.go b/cmd/accountlock.go index 7f7e99f..8daebcb 100644 --- a/cmd/accountlock.go +++ b/cmd/accountlock.go @@ -15,11 +15,11 @@ package cmd import ( "context" - "os" "github.com/spf13/cobra" "github.com/spf13/viper" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var accountLockCmd = &cobra.Command{ @@ -31,26 +31,28 @@ var accountLockCmd = &cobra.Command{ In quiet mode this will return 0 if the account is locked, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(remote, "account lock only works with remote wallets") - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - client := pb.NewAccountManagerClient(remoteGRPCConn) - lockReq := &pb.LockAccountRequest{ - Account: rootAccount, - } + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() - resp, err := client.Lock(ctx, lockReq) - errCheck(err, "Failed in attempt to lock account") - switch resp.State { - case pb.ResponseState_DENIED: - die("Lock request denied") - case pb.ResponseState_FAILED: - die("Lock request failed") - case pb.ResponseState_SUCCEEDED: - outputIf(!quiet, "Lock request succeeded") - os.Exit(_exitSuccess) - } + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + + locker, isLocker := account.(e2wtypes.AccountLocker) + assert(isLocker, "Account does not support locking") + + ctx, cancel = context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + err = locker.Lock(ctx) + cancel() + errCheck(err, "Failed to lock account") }, } diff --git a/cmd/accountunlock.go b/cmd/accountunlock.go index c539a12..232518f 100644 --- a/cmd/accountunlock.go +++ b/cmd/accountunlock.go @@ -19,7 +19,8 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var accountUnlockCmd = &cobra.Command{ @@ -31,25 +32,36 @@ var accountUnlockCmd = &cobra.Command{ In quiet mode this will return 0 if the account is unlocked, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(remote, "account unlock only works with remote wallets") - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - client := pb.NewAccountManagerClient(remoteGRPCConn) - unlocked := false + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + + locker, isLocker := account.(e2wtypes.AccountLocker) + assert(isLocker, "Account does not support unlocking") + + unlocked := false for _, passphrase := range getPassphrases() { - unlockReq := &pb.UnlockAccountRequest{ - Account: rootAccount, - Passphrase: []byte(passphrase), - } - resp, err := client.Unlock(ctx, unlockReq) - errCheck(err, "Failed in attempt to unlock account") - if resp.State == pb.ResponseState_SUCCEEDED { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + err := locker.Unlock(ctx, []byte(passphrase)) + cancel() + if err == nil { + // Success. unlocked = true break } } + assert(unlocked, "Failed to unlock account") os.Exit(_exitSuccess) }, diff --git a/cmd/accountwithdrawalcredentials.go b/cmd/accountwithdrawalcredentials.go new file mode 100644 index 0000000..9d408bd --- /dev/null +++ b/cmd/accountwithdrawalcredentials.go @@ -0,0 +1,83 @@ +// Copyright © 2019, 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + util "github.com/wealdtech/go-eth2-util" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" +) + +var accountWithdrawalCredentialsCmd = &cobra.Command{ + Use: "withdrawalcredentials", + Short: "Provide withdrawal credentials for an account", + Long: `Provide withdrawal credentials for an account. For example: + + ethdo account withdrawalcredentials --account="Validators/1" + +In quiet mode this will return 0 if the account exists, otherwise 1.`, + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("account") != "" || viper.GetString("pubkey") != "", "account or pubkey is required") + + var pubKey []byte + if viper.GetString("pubkey") != "" { + var err error + pubKey, err = hex.DecodeString(strings.TrimPrefix(viper.GetString("pubkey"), "0x")) + errCheck(err, "Failed to decode supplied public key") + } else { + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + + key, err := bestPublicKey(account) + errCheck(err, "Account does not provide a public key") + pubKey = key.Marshal() + } + + if quiet { + os.Exit(_exitSuccess) + } + + withdrawalCredentials := util.SHA256(pubKey) + withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX + fmt.Printf("%#x\n", withdrawalCredentials) + }, +} + +func init() { + accountCmd.AddCommand(accountWithdrawalCredentialsCmd) + accountFlags(accountWithdrawalCredentialsCmd) + accountWithdrawalCredentialsCmd.Flags().String("pubkey", "", "Public key (overrides account)") + if err := viper.BindPFlag("pubkey", accountCreateCmd.Flags().Lookup("pubkey")); err != nil { + panic(err) + } +} diff --git a/cmd/blockinfo.go b/cmd/blockinfo.go index 4919dba..fcb7767 100644 --- a/cmd/blockinfo.go +++ b/cmd/blockinfo.go @@ -20,6 +20,7 @@ import ( "os" "sort" "strings" + "time" "unicode/utf8" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" @@ -48,44 +49,49 @@ In quiet mode this will return 0 if the block information is present and not ski config, err := grpc.FetchChainConfig(eth2GRPCConn) errCheck(err, "Failed to obtain beacon chain configuration") slotsPerEpoch := config["SlotsPerEpoch"].(uint64) + secondsPerSlot := config["SecondsPerSlot"].(uint64) + + genesisTime, err := grpc.FetchGenesisTime(eth2GRPCConn) + errCheck(err, "Failed to obtain beacon chain genesis") + + assert(blockInfoStream || blockInfoSlot != 0, "--slot or --stream is required") + assert(!blockInfoStream || blockInfoSlot == -1, "--slot and --stream are not supported together") + + var slot uint64 + if blockInfoSlot < 0 { + slot, err = grpc.FetchLatestFilledSlot(eth2GRPCConn) + errCheck(err, "Failed to obtain slot of latest block") + } else { + slot = uint64(blockInfoSlot) + } + assert(slot > 0, "slot must be greater than 0") + + signedBlock, err := grpc.FetchBlock(eth2GRPCConn, slot) + errCheck(err, "Failed to obtain block") + if signedBlock == nil { + outputIf(!quiet, "No block at that slot") + os.Exit(_exitFailure) + } + outputBlock(signedBlock, genesisTime, secondsPerSlot, slotsPerEpoch) if blockInfoStream { stream, err := grpc.StreamBlocks(eth2GRPCConn) errCheck(err, "Failed to obtain block stream") for { + fmt.Println() signedBlock, err := stream.Recv() errCheck(err, "Failed to obtain block") if signedBlock != nil { - fmt.Println("") - outputBlock(signedBlock, slotsPerEpoch) + outputBlock(signedBlock, genesisTime, secondsPerSlot, slotsPerEpoch) } } - - } else { - assert(blockInfoSlot != 0, "--slot is required") - var slot uint64 - if blockInfoSlot < 0 { - slot, err = grpc.FetchLatestFilledSlot(eth2GRPCConn) - errCheck(err, "Failed to obtain slot of latest block") - } else { - slot = uint64(blockInfoSlot) - } - assert(slot > 0, "slot must be greater than 0") - - signedBlock, err := grpc.FetchBlock(eth2GRPCConn, slot) - errCheck(err, "Failed to obtain block") - if signedBlock == nil { - outputIf(!quiet, "No block at that slot") - os.Exit(_exitFailure) - } - outputBlock(signedBlock, slotsPerEpoch) } os.Exit(_exitSuccess) }, } -func outputBlock(signedBlock *ethpb.SignedBeaconBlock, slotsPerEpoch uint64) { +func outputBlock(signedBlock *ethpb.SignedBeaconBlock, genesisTime time.Time, secondsPerSlot uint64, slotsPerEpoch uint64) { block := signedBlock.Block body := block.Body @@ -94,6 +100,7 @@ func outputBlock(signedBlock *ethpb.SignedBeaconBlock, slotsPerEpoch uint64) { errCheck(err, "Failed to calculate block body root") fmt.Printf("Slot: %d\n", block.Slot) fmt.Printf("Epoch: %d\n", block.Slot/slotsPerEpoch) + fmt.Printf("Timestamp: %v\n", time.Unix(genesisTime.Unix()+int64(block.Slot*secondsPerSlot), 0)) fmt.Printf("Block root: %#x\n", bodyRoot) outputIf(verbose, fmt.Sprintf("Parent root: %#x", block.ParentRoot)) outputIf(verbose, fmt.Sprintf("State root: %#x", block.StateRoot)) diff --git a/cmd/chaininfo.go b/cmd/chaininfo.go index 7746f31..5f9c8e2 100644 --- a/cmd/chaininfo.go +++ b/cmd/chaininfo.go @@ -43,8 +43,12 @@ In quiet mode this will return 0 if the chain information can be obtained, other os.Exit(_exitSuccess) } - fmt.Printf("Genesis time: %s\n", genesisTime.Format(time.UnixDate)) - outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesisTime.Unix())) + if genesisTime.Unix() == 0 { + fmt.Println("Genesis time: undefined") + } else { + fmt.Printf("Genesis time: %s\n", genesisTime.Format(time.UnixDate)) + outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesisTime.Unix())) + } outputIf(verbose, fmt.Sprintf("Genesis fork version: %0x", config["GenesisForkVersion"].([]byte))) outputIf(verbose, fmt.Sprintf("Seconds per slot: %v", config["SecondsPerSlot"].(uint64))) outputIf(verbose, fmt.Sprintf("Slots per epoch: %v", config["SlotsPerEpoch"].(uint64))) @@ -64,3 +68,11 @@ func timestampToSlot(genesis int64, timestamp int64, secondsPerSlot uint64) uint } return uint64(timestamp-genesis) / secondsPerSlot } + +func slotToTimestamp(genesis int64, slot uint64, secondsPerSlot uint64) int64 { + return genesis + int64(slot*secondsPerSlot) +} + +func epochToTimestamp(genesis int64, slot uint64, secondsPerSlot uint64, slotsPerEpoch uint64) int64 { + return genesis + int64(slot*secondsPerSlot*slotsPerEpoch) +} diff --git a/cmd/chainstatus.go b/cmd/chainstatus.go index 8dc77b5..607491c 100644 --- a/cmd/chainstatus.go +++ b/cmd/chainstatus.go @@ -48,7 +48,8 @@ In quiet mode this will return 0 if the chain status can be obtained, otherwise os.Exit(_exitSuccess) } - slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64)) + now := time.Now() + slot := timestampToSlot(genesisTime.Unix(), now.Unix(), config["SecondsPerSlot"].(uint64)) if chainStatusSlot { fmt.Printf("Current slot: %d\n", slot) fmt.Printf("Justified slot: %d\n", info.GetJustifiedSlot()) @@ -87,6 +88,18 @@ In quiet mode this will return 0 if the chain status can be obtained, otherwise } } + if verbose { + slotsPerEpoch := config["SlotsPerEpoch"].(uint64) + secondsPerSlot := config["SecondsPerSlot"].(uint64) + epochStartSlot := (slot / slotsPerEpoch) * slotsPerEpoch + fmt.Printf("Epoch slots: %d-%d\n", epochStartSlot, epochStartSlot+slotsPerEpoch-1) + nextSlot := slotToTimestamp(genesisTime.Unix(), slot+1, secondsPerSlot) + fmt.Printf("Time until next slot: %2.1fs\n", float64(time.Until(time.Unix(nextSlot, 0)).Milliseconds())/1000) + nextEpoch := epochToTimestamp(genesisTime.Unix(), slot/slotsPerEpoch+1, secondsPerSlot, slotsPerEpoch) + fmt.Printf("Slots until next epoch: %d\n", (slot/slotsPerEpoch+1)*slotsPerEpoch-slot) + fmt.Printf("Time until next epoch: %2.1fs\n", float64(time.Until(time.Unix(nextEpoch, 0)).Milliseconds())/1000) + } + os.Exit(_exitSuccess) }, } diff --git a/cmd/depositverify.go b/cmd/depositverify.go index f68acd1..21bf5b9 100644 --- a/cmd/depositverify.go +++ b/cmd/depositverify.go @@ -107,7 +107,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth failures = true } } - outputIf(!quiet, fmt.Sprintf("Deposit for %q verified", deposit.Name)) + outputIf(!quiet, fmt.Sprintf("Deposit %q verified", deposit.Name)) } if failures { diff --git a/cmd/nodeinfo.go b/cmd/nodeinfo.go index 6eee1d1..3659691 100644 --- a/cmd/nodeinfo.go +++ b/cmd/nodeinfo.go @@ -55,10 +55,14 @@ In quiet mode this will return 0 if the node information can be obtained, otherw errCheck(err, "Failed to obtain syncing state") fmt.Printf("Syncing: %v\n", syncing) - slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64)) - fmt.Printf("Current slot: %d\n", slot) - fmt.Printf("Current epoch: %d\n", slot/config["SlotsPerEpoch"].(uint64)) - outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesisTime.Unix())) + if genesisTime.Unix() == 0 { + fmt.Println("Not reached genesis") + } else { + slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64)) + fmt.Printf("Current slot: %d\n", slot) + fmt.Printf("Current epoch: %d\n", slot/config["SlotsPerEpoch"].(uint64)) + outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesisTime.Unix())) + } os.Exit(_exitSuccess) }, diff --git a/cmd/root.go b/cmd/root.go index be5d0c5..9840896 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,28 +15,25 @@ package cmd import ( "context" - "crypto/tls" - "crypto/x509" "fmt" - "io/ioutil" "os" "regexp" "sort" + "strconv" "strings" "time" homedir "github.com/mitchellh/go-homedir" "github.com/pkg/errors" - "github.com/prysmaticlabs/go-ssz" "github.com/spf13/cobra" "github.com/spf13/viper" e2types "github.com/wealdtech/go-eth2-types/v2" e2wallet "github.com/wealdtech/go-eth2-wallet" + dirk "github.com/wealdtech/go-eth2-wallet-dirk" filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem" s3 "github.com/wealdtech/go-eth2-wallet-store-s3" - wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" "google.golang.org/grpc" - "google.golang.org/grpc/credentials" ) var cfgFile string @@ -46,19 +43,12 @@ var debug bool // Root variables, present for all commands. var rootStore string -var rootAccount string -var rootBaseDir string // Store for wallet actions. -var store wtypes.Store +var store e2wtypes.Store // Remote connection. var remote bool -var remoteAddr string -var clientCert string -var clientKey string -var serverCACert string -var remoteGRPCConn *grpc.ClientConn // Prysm connection. var eth2GRPCConn *grpc.ClientConn @@ -87,8 +77,6 @@ func persistentPreRun(cmd *cobra.Command, args []string) { verbose = viper.GetBool("verbose") debug = viper.GetBool("debug") rootStore = viper.GetString("store") - rootAccount = viper.GetString("account") - rootBaseDir = viper.GetString("basedir") if quiet && verbose { fmt.Println("Cannot supply both quiet and verbose flags") @@ -101,7 +89,7 @@ func persistentPreRun(cmd *cobra.Command, args []string) { // Set up our wallet store switch rootStore { case "s3": - assert(rootBaseDir == "", "--basedir does not apply for the s3 store") + assert(viper.GetString("base-dir") == "", "--basedir does not apply for the s3 store") var err error store, err = s3.New(s3.WithPassphrase([]byte(getStorePassphrase()))) errCheck(err, "Failed to access Amazon S3 wallet store") @@ -110,8 +98,8 @@ func persistentPreRun(cmd *cobra.Command, args []string) { if getStorePassphrase() != "" { opts = append(opts, filesystem.WithPassphrase([]byte(getStorePassphrase()))) } - if rootBaseDir != "" { - opts = append(opts, filesystem.WithLocation(rootBaseDir)) + if viper.GetString("base-dir") != "" { + opts = append(opts, filesystem.WithLocation(viper.GetString("base-dir"))) } store = filesystem.New(opts...) default: @@ -120,8 +108,7 @@ func persistentPreRun(cmd *cobra.Command, args []string) { err := e2wallet.UseStore(store) errCheck(err, "Failed to use defined wallet store") } else { - err := initRemote() - errCheck(err, "Failed to connect to remote wallet") + remote = true } } @@ -226,6 +213,7 @@ func initConfig() { } viper.SetEnvPrefix("ETHDO") + viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) viper.AutomaticEnv() // read in environment variables that match // If a config file is found, read it in. @@ -246,7 +234,7 @@ func outputIf(condition bool, msg string) { } // walletFromPath obtains a wallet given a path specification. -func walletFromPath(path string) (wtypes.Wallet, error) { +func walletFromPath(path string) (e2wtypes.Wallet, error) { walletName, _, err := e2wallet.WalletAndAccountNames(path) if err != nil { return nil, err @@ -262,7 +250,7 @@ func walletFromPath(path string) (wtypes.Wallet, error) { } // accountFromPath obtains an account given a path specification. -func accountFromPath(path string) (wtypes.Account, error) { +func accountFromPath(ctx context.Context, path string) (e2wtypes.Account, error) { wallet, err := walletFromPath(path) if err != nil { return nil, err @@ -277,34 +265,27 @@ func accountFromPath(path string) (wtypes.Account, error) { if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") { assert(getWalletPassphrase() != "", "--walletpassphrase is required for direct path derivations") - err = wallet.Unlock([]byte(viper.GetString("wallet-passphrase"))) - if err != nil { - return nil, errors.New("invalid wallet passphrase") + + locker, isLocker := wallet.(e2wtypes.WalletLocker) + if isLocker { + err = locker.Unlock(ctx, []byte(viper.GetString("wallet-passphrase"))) + if err != nil { + return nil, errors.New("invalid wallet passphrase") + } + defer errCheck(locker.Lock(context.Background()), "failed to re-lock account") } - defer wallet.Lock() } - return wallet.AccountByName(accountName) + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + if !isAccountByNameProvider { + return nil, errors.New("wallet cannot obtain accounts by name") + } + return accountByNameProvider.AccountByName(ctx, accountName) } // accountsFromPath obtains 0 or more accounts given a path specification. -func accountsFromPath(path string) ([]wtypes.Account, error) { - accounts := make([]wtypes.Account, 0) - - // Quick check to see if it's a single account - account, err := accountFromPath(path) - if err == nil && account != nil { - accounts = append(accounts, account) - return accounts, nil - } - - wallet, err := walletFromPath(path) - if err != nil { - return nil, err - } - _, accountSpec, err := e2wallet.WalletAndAccountNames(path) - if err != nil { - return nil, err - } +func accountsFromPath(ctx context.Context, wallet e2wtypes.Wallet, accountSpec string) ([]e2wtypes.Account, error) { + accounts := make([]e2wtypes.Account, 0) if accountSpec == "" { accountSpec = "^.*$" @@ -313,7 +294,7 @@ func accountsFromPath(path string) ([]wtypes.Account, error) { } re := regexp.MustCompile(accountSpec) - for account := range wallet.Accounts() { + for account := range wallet.Accounts(ctx) { if re.Match([]byte(account.Name())) { accounts = append(accounts, account) } @@ -327,49 +308,6 @@ func accountsFromPath(path string) ([]wtypes.Account, error) { return accounts, nil } -// signStruct signs an arbitrary structure. -func signStruct(account wtypes.Account, data interface{}, domain []byte) (e2types.Signature, error) { - objRoot, err := ssz.HashTreeRoot(data) - outputIf(debug, fmt.Sprintf("Object root is %x", objRoot)) - if err != nil { - return nil, err - } - - return signRoot(account, objRoot, domain) -} - -// SigningContainer is the container for signing roots with a domain. -// Contains SSZ sizes to allow for correct calculation of root. -type SigningContainer struct { - Root []byte `ssz-size:"32"` - Domain []byte `ssz-size:"32"` -} - -// signRoot signs a root. -func signRoot(account wtypes.Account, root [32]byte, domain []byte) (e2types.Signature, error) { - container := &SigningContainer{ - Root: root[:], - Domain: domain, - } - outputIf(debug, fmt.Sprintf("Signing container:\n\troot: %x\n\tdomain: %x", container.Root, container.Domain)) - signingRoot, err := ssz.HashTreeRoot(container) - if err != nil { - return nil, err - } - outputIf(debug, fmt.Sprintf("Signing root: %x", signingRoot)) - return sign(account, signingRoot[:]) -} - -// sign signs arbitrary data. -func sign(account wtypes.Account, data []byte) (e2types.Signature, error) { - if !account.IsUnlocked() { - return nil, errors.New("account must be unlocked to sign") - } - - outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data))) - return account.Sign(data) -} - // connect connects to an Ethereum 2 endpoint. func connect() error { connection := "" @@ -391,46 +329,77 @@ func connect() error { return err } -func initRemote() error { - remote = true - remoteAddr = viper.GetString("remote") - clientCert = viper.GetString("client-cert") - assert(clientCert != "", "--remote requires --client-cert") - clientKey = viper.GetString("client-key") - assert(clientKey != "", "--remote requires --client-key") - serverCACert = viper.GetString("server-ca-cert") - assert(serverCACert != "", "--remote requires --server-ca-cert") - - // Load the client certificates. - clientPair, err := tls.LoadX509KeyPair(clientCert, clientKey) - if err != nil { - return errors.Wrap(err, "failed to access client certificate/key") - } - - tlsCfg := &tls.Config{ - Certificates: []tls.Certificate{clientPair}, - } - if serverCACert != "" { - // Load the CA for the server certificate. - serverCA, err := ioutil.ReadFile(serverCACert) - if err != nil { - return errors.Wrap(err, "failed to access CA certificate") +// bestPublicKey returns the best public key for operations. +// It prefers the composite public key if present, otherwise the public key. +func bestPublicKey(account e2wtypes.Account) (e2types.PublicKey, error) { + var pubKey e2types.PublicKey + publicKeyProvider, isCompositePublicKeyProvider := account.(e2wtypes.AccountCompositePublicKeyProvider) + if isCompositePublicKeyProvider { + pubKey = publicKeyProvider.CompositePublicKey() + } else { + publicKeyProvider, isPublicKeyProvider := account.(e2wtypes.AccountPublicKeyProvider) + if isPublicKeyProvider { + pubKey = publicKeyProvider.PublicKey() + } else { + return nil, errors.New("account does not provide a public key") } - cp := x509.NewCertPool() - if !cp.AppendCertsFromPEM(serverCA) { - return errors.Wrap(err, "failed to add CA certificate") - } - tlsCfg.RootCAs = cp } - - clientCreds := credentials.NewTLS(tlsCfg) - - opts := []grpc.DialOption{ - // Require TLS. - grpc.WithTransportCredentials(clientCreds), - // Block until server responds. - grpc.WithBlock(), - } - remoteGRPCConn, err = grpc.Dial(remoteAddr, opts...) - return err + return pubKey, nil +} + +// remotesToEndpoints generates endpoints from remote addresses. +func remotesToEndpoints(remotes []string) ([]*dirk.Endpoint, error) { + endpoints := make([]*dirk.Endpoint, 0) + for _, remote := range remotes { + parts := strings.Split(remote, ":") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid remote %q", remote) + } + port, err := strconv.ParseUint(parts[1], 10, 32) + if err != nil { + return nil, errors.Wrap(err, fmt.Sprintf("invalid port in remote %q", remote)) + } + endpoints = append(endpoints, dirk.NewEndpoint(parts[0], uint32(port))) + } + return endpoints, nil +} + +// Oepn a wallet, local or remote. +func openWallet() (e2wtypes.Wallet, error) { + var err error + // Obtain the name of the wallet. + walletName := viper.GetString("wallet") + if walletName == "" { + walletName, _, err = e2wallet.WalletAndAccountNames(viper.GetString("account")) + } + if err != nil { + return nil, errors.Wrap(err, "failed to obtain wallet name") + } + if walletName == "" { + return nil, errors.New("no wallet name provided") + } + + return openNamedWallet(walletName) +} + +// Open a named wallet, local or remote. +func openNamedWallet(walletName string) (e2wtypes.Wallet, error) { + if viper.GetString("remote") != "" { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + assert(viper.GetString("client-cert") != "", "remote connections require client-cert") + assert(viper.GetString("client-key") != "", "remote connections require client-key") + credentials, err := dirk.ComposeCredentials(ctx, viper.GetString("client-cert"), viper.GetString("client-key"), viper.GetString("server-ca-cert")) + if err != nil { + return nil, errors.Wrap(err, "failed to build dirk credentials") + } + + endpoints, err := remotesToEndpoints([]string{viper.GetString("remote")}) + if err != nil { + return nil, errors.Wrap(err, "failed to parse remote servers") + } + + return dirk.OpenWallet(ctx, walletName, credentials, endpoints) + } + return walletFromPath(walletName) } diff --git a/cmd/signature.go b/cmd/signature.go index 5ea7360..f33a87f 100644 --- a/cmd/signature.go +++ b/cmd/signature.go @@ -15,11 +15,10 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" ) -var signatureData string -var signatureDomain string - // signatureCmd represents the signature command var signatureCmd = &cobra.Command{ Use: "signature", @@ -32,7 +31,23 @@ func init() { RootCmd.AddCommand(signatureCmd) } +var dataFlag *pflag.Flag +var domainFlag *pflag.Flag + func signatureFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&signatureData, "data", "", "the hex string of data") - cmd.Flags().StringVar(&signatureDomain, "domain", "", "the hex string of the BLS domain (defaults to 0x0000000000000000)") + if dataFlag == nil { + cmd.Flags().String("data", "", "the data, as a hex string") + dataFlag = cmd.Flags().Lookup("data") + if err := viper.BindPFlag("signature-data", dataFlag); err != nil { + panic(err) + } + cmd.Flags().String("domain", "0x0000000000000000000000000000000000000000000000000000000000000000", "the BLS domain, as a hex string") + domainFlag = cmd.Flags().Lookup("domain") + if err := viper.BindPFlag("signature-domain", domainFlag); err != nil { + panic(err) + } + } else { + cmd.Flags().AddFlag(dataFlag) + cmd.Flags().AddFlag(domainFlag) + } } diff --git a/cmd/signatureaggregate.go b/cmd/signatureaggregate.go new file mode 100644 index 0000000..71b7941 --- /dev/null +++ b/cmd/signatureaggregate.go @@ -0,0 +1,110 @@ +// Copyright © 2017-2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "encoding/hex" + "fmt" + "os" + "strconv" + "strings" + + "github.com/herumi/bls-eth-go-binary/bls" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/wealdtech/ethdo/util" +) + +var signatureAggregateSignatures []string + +// signatureAggregateCmd represents the signature aggregate command +var signatureAggregateCmd = &cobra.Command{ + Use: "aggregate", + Short: "Aggregate signatures", + Long: `Aggregate signatures, either threshold or absolute. For example: + + ethdo signature aggregate --signatures=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7, + +Signatures are specified as "signature" for simple aggregation, and as "id:signature" for threshold aggregation. + +In quiet mode this will return 0 if the signatures can be aggregated, otherwise 1.`, + Run: func(cmd *cobra.Command, args []string) { + assert(len(signatureAggregateSignatures) > 1, "multiple signatures required to aggregate") + var signature *bls.Sign + var err error + if strings.Contains(signatureAggregateSignatures[0], ":") { + signature, err = generateThresholdSignature() + } else { + signature, err = generateAggregateSignature() + } + errCheck(err, "Failed to aggregate signature") + + outputIf(!quiet, fmt.Sprintf("%#x", signature.Serialize())) + os.Exit(_exitSuccess) + }, +} + +func generateThresholdSignature() (*bls.Sign, error) { + ids := make([]bls.ID, len(signatureAggregateSignatures)) + sigs := make([]bls.Sign, len(signatureAggregateSignatures)) + + for i := range signatureAggregateSignatures { + parts := strings.Split(signatureAggregateSignatures[i], ":") + if len(parts) != 2 { + return nil, errors.New("invalid threshold signature format") + } + id, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + return nil, errors.Wrap(err, "invalid threshold signature ID") + } + ids[i] = *util.BLSID(id) + sigBytes, err := hex.DecodeString(strings.TrimPrefix(parts[1], "0x")) + if err != nil { + return nil, errors.Wrap(err, "invalid threshold signature ID") + } + if err := sigs[i].Deserialize(sigBytes); err != nil { + return nil, errors.Wrap(err, "invalid signature") + } + } + + var compositeSig bls.Sign + if err := compositeSig.Recover(sigs, ids); err != nil { + return nil, err + } + + return &compositeSig, nil +} + +func generateAggregateSignature() (*bls.Sign, error) { + sigs := make([]bls.Sign, len(signatureAggregateSignatures)) + for i := range signatureAggregateSignatures { + sigBytes, err := hex.DecodeString(strings.TrimPrefix(signatureAggregateSignatures[i], "0x")) + if err != nil { + return nil, errors.Wrap(err, "failed to decode signature") + } + if err := sigs[i].Deserialize(sigBytes); err != nil { + return nil, errors.Wrap(err, "invalid signature") + } + } + var aggregateSig bls.Sign + aggregateSig.Aggregate(sigs) + + return &aggregateSig, nil +} + +func init() { + signatureCmd.AddCommand(signatureAggregateCmd) + signatureAggregateCmd.Flags().StringArrayVar(&signatureAggregateSignatures, "signature", nil, "a signature to aggregate (supply once for each signature)") + signatureFlags(signatureAggregateCmd) +} diff --git a/cmd/signaturesign.go b/cmd/signaturesign.go index a173ad5..9646949 100644 --- a/cmd/signaturesign.go +++ b/cmd/signaturesign.go @@ -20,9 +20,10 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" "github.com/wealdtech/go-bytesutil" e2types "github.com/wealdtech/go-eth2-types/v2" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) // signatureSignCmd represents the signature sign command @@ -31,59 +32,46 @@ var signatureSignCmd = &cobra.Command{ Short: "Sign a 32-byte piece of data", Long: `Sign presented data. For example: - ethereal signature sign --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --account="Personal wallet/Operations" --passphrase="my account passphrase" + ethdo signature sign --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --account="Personal wallet/Operations" --passphrase="my account passphrase" In quiet mode this will return 0 if the data can be signed, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(signatureData != "", "--data is required") - data, err := bytesutil.FromHexString(signatureData) + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("signature-data") != "", "--data is required") + data, err := bytesutil.FromHexString(viper.GetString("signature-data")) errCheck(err, "Failed to parse data") assert(len(data) == 32, "data to sign must be 32 bytes") domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot) - if signatureDomain != "" { - domainBytes, err := bytesutil.FromHexString(signatureDomain) + if viper.GetString("signature-domain") != "" { + domain, err = bytesutil.FromHexString(viper.GetString("signature-domain")) errCheck(err, "Failed to parse domain") - assert(len(domainBytes) == 32, "Domain data invalid") - domain = domainBytes + assert(len(domain) == 32, "Domain data invalid") } + outputIf(debug, fmt.Sprintf("Domain is %#x", domain)) - assert(rootAccount != "", "--account is required") + assert(viper.GetString("account") != "", "--account is required") - var signature e2types.Signature - if remote { - signClient := pb.NewSignerClient(remoteGRPCConn) - signReq := &pb.SignRequest{ - Id: &pb.SignRequest_Account{Account: rootAccount}, - Data: data, - Domain: domain, - } - ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) - defer cancel() - resp, err := signClient.Sign(ctx, signReq) - errCheck(err, "Failed to sign") - switch resp.State { - case pb.ResponseState_DENIED: - die("Signing request denied") - case pb.ResponseState_FAILED: - die("Signing request failed") - case pb.ResponseState_SUCCEEDED: - signature, err = e2types.BLSSignatureFromBytes(resp.Signature) - errCheck(err, "Invalid signature") - } - } else { - account, err := accountFromPath(rootAccount) - errCheck(err, "Failed to access account for signing") - err = account.Unlock([]byte(getPassphrase())) - errCheck(err, "Failed to unlock account for signing") - var fixedSizeData [32]byte - copy(fixedSizeData[:], data) - defer account.Lock() - signature, err = signRoot(account, fixedSizeData, domain) - errCheck(err, "Failed to sign data") - } + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") - outputIf(!quiet, fmt.Sprintf("0x%096x", signature.Marshal())) + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet does not support obtaining accounts by name") + + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + + var fixedSizeData [32]byte + copy(fixedSizeData[:], data) + signature, err := signRoot(account, fixedSizeData, domain) + errCheck(err, "Failed to sign") + + outputIf(!quiet, fmt.Sprintf("%#x", signature.Marshal())) os.Exit(_exitSuccess) }, } diff --git a/cmd/signatureverify.go b/cmd/signatureverify.go index 2c9656f..512c3db 100644 --- a/cmd/signatureverify.go +++ b/cmd/signatureverify.go @@ -15,17 +15,20 @@ package cmd import ( "context" + "fmt" "os" "github.com/prysmaticlabs/go-ssz" "github.com/spf13/cobra" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" + "github.com/spf13/viper" "github.com/wealdtech/go-bytesutil" e2types "github.com/wealdtech/go-eth2-types/v2" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var signatureVerifySignature string -var signatureVerifyPubKey string +var signatureVerifySigner string // signatureVerifyCmd represents the signature verify command var signatureVerifyCmd = &cobra.Command{ @@ -33,12 +36,12 @@ var signatureVerifyCmd = &cobra.Command{ Short: "Verify signed data", Long: `Verify signed data. For example: - ethereal signature verify --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --signature=0x8888... --account="Personal wallet/Operations" + ethdo signature verify --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --signature=0x8888... --account="Personal wallet/Operations" In quiet mode this will return 0 if the data can be signed, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(signatureData != "", "--data is required") - data, err := bytesutil.FromHexString(signatureData) + assert(viper.GetString("signature-data") != "", "--data is required") + data, err := bytesutil.FromHexString(viper.GetString("signature-data")) errCheck(err, "Failed to parse data") assert(len(data) == 32, "data to verify must be 32 bytes") @@ -49,45 +52,44 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`, errCheck(err, "Invalid signature") domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot) - if signatureDomain != "" { - domainBytes, err := bytesutil.FromHexString(signatureDomain) + if viper.GetString("signature-domain") != "" { + domain, err = bytesutil.FromHexString(viper.GetString("signature-domain")) errCheck(err, "Failed to parse domain") - assert(len(domainBytes) == 32, "Domain data invalid") + assert(len(domain) == 32, "Domain data invalid") } var pubKey e2types.PublicKey - assert(signatureVerifyPubKey == "" || rootAccount == "", "Either --pubkey or --account should be supplied") - if rootAccount != "" { - if remote { - listerClient := pb.NewListerClient(remoteGRPCConn) - listAccountsReq := &pb.ListAccountsRequest{ - Paths: []string{ - rootAccount, - }, - } - resp, err := listerClient.ListAccounts(context.Background(), listAccountsReq) - errCheck(err, "Failed to access account") - assert(resp.State == pb.ResponseState_SUCCEEDED, "Failed to obtain account") - assert(len(resp.Accounts) == 1, "No such account") - pubKey, err = e2types.BLSPublicKeyFromBytes(resp.Accounts[0].PublicKey) - errCheck(err, "Invalid public key provided for account") - } else { - account, err := accountFromPath(rootAccount) - errCheck(err, "Unknown account") - pubKey = account.PublicKey() - } + assert(signatureVerifySigner != "" || viper.GetString("account") != "", "Either --signer or --account should be supplied") + if viper.GetString("account") != "" { + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + account, err := accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") + pubKey, err = bestPublicKey(account) + errCheck(err, "Failed to obtain account's public key") } else { - pubKeyBytes, err := bytesutil.FromHexString(signatureVerifyPubKey) + pubKeyBytes, err := bytesutil.FromHexString(signatureVerifySigner) errCheck(err, "Invalid public key") pubKey, err = e2types.BLSPublicKeyFromBytes(pubKeyBytes) errCheck(err, "Invalid public key") } - container := &SigningContainer{ + outputIf(debug, fmt.Sprintf("Public key is %#x", pubKey.Marshal())) + container := &signingContainer{ Root: data, Domain: domain, } + outputIf(debug, fmt.Sprintf("Data root is %#x", data)) + outputIf(debug, fmt.Sprintf("Domain is %#x", domain)) root, err := ssz.HashTreeRoot(container) errCheck(err, "Failed to create signing root") + outputIf(debug, fmt.Sprintf("Signing root is %#x", root)) verified := signature.Verify(root[:], pubKey) if !verified { @@ -103,5 +105,5 @@ func init() { signatureCmd.AddCommand(signatureVerifyCmd) signatureFlags(signatureVerifyCmd) signatureVerifyCmd.Flags().StringVar(&signatureVerifySignature, "signature", "", "the signature to verify") - signatureVerifyCmd.Flags().StringVar(&signatureVerifyPubKey, "signer", "", "the public key of the signer (only if --account is not supplied)") + signatureVerifyCmd.Flags().StringVar(&signatureVerifySigner, "signer", "", "the public key of the signer (only if --account is not supplied)") } diff --git a/cmd/signing.go b/cmd/signing.go new file mode 100644 index 0000000..f140bdd --- /dev/null +++ b/cmd/signing.go @@ -0,0 +1,160 @@ +// Copyright © 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "context" + "fmt" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/go-ssz" + "github.com/spf13/viper" + e2types "github.com/wealdtech/go-eth2-types/v2" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" + wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" +) + +// signStruct signs an arbitrary structure. +func signStruct(account wtypes.Account, data interface{}, domain []byte) (e2types.Signature, error) { + objRoot, err := ssz.HashTreeRoot(data) + outputIf(debug, fmt.Sprintf("Object root is %#x", objRoot)) + if err != nil { + return nil, err + } + + return signRoot(account, objRoot, domain) +} + +// SigningContainer is the container for signing roots with a domain. +// Contains SSZ sizes to allow for correct calculation of root. +type signingContainer struct { + Root []byte `ssz-size:"32"` + Domain []byte `ssz-size:"32"` +} + +// signRoot signs a root. +func signRoot(account wtypes.Account, root [32]byte, domain []byte) (e2types.Signature, error) { + if _, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner); isProtectingSigner { + // Signer signs the data to sign itself. + return signGeneric(account, root[:], domain) + } + + // Build the signing data manually. + container := &signingContainer{ + Root: root[:], + Domain: domain, + } + outputIf(debug, fmt.Sprintf("Signing container:\n root: %#x\n domain: %#x", container.Root, container.Domain)) + signingRoot, err := ssz.HashTreeRoot(container) + if err != nil { + return nil, err + } + outputIf(debug, fmt.Sprintf("Signing root: %#x", signingRoot)) + return sign(account, signingRoot[:]) +} + +func signGeneric(account wtypes.Account, data []byte, domain []byte) (e2types.Signature, error) { + alreadyUnlocked, err := unlock(account) + if err != nil { + return nil, err + } + outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data))) + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + signer, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner) + if !isProtectingSigner { + return nil, errors.New("account does not provide generic signing") + } + + signature, err := signer.SignGeneric(ctx, data, domain) + errCheck(err, "failed to sign") + if !alreadyUnlocked { + if err := lock(account); err != nil { + return nil, errors.Wrap(err, "failed to lock account") + } + } + return signature, err +} + +// sign signs arbitrary data, handling unlocking and locking as required. +func sign(account wtypes.Account, data []byte) (e2types.Signature, error) { + alreadyUnlocked, err := unlock(account) + if err != nil { + return nil, err + } + outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data))) + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + signer, isSigner := account.(e2wtypes.AccountSigner) + if !isSigner { + return nil, errors.New("account does not provide signing") + } + + signature, err := signer.Sign(ctx, data) + errCheck(err, "failed to sign") + if !alreadyUnlocked { + if err := lock(account); err != nil { + return nil, errors.Wrap(err, "failed to lock account") + } + } + return signature, err +} + +// unlock attempts to unlock an account. It returns true if the account was already unlocked. +func unlock(account e2wtypes.Account) (bool, error) { + locker, isAccountLocker := account.(e2wtypes.AccountLocker) + if !isAccountLocker { + outputIf(debug, "Account does not support unlocking") + // This account doesn't support unlocking; return okay. + return true, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + alreadyUnlocked, err := locker.IsUnlocked(ctx) + cancel() + if err != nil { + return false, errors.Wrap(err, "unable to ascertain if account is unlocked") + } + + if alreadyUnlocked { + return true, nil + } + + // Not already unlocked; attempt to unlock it. + for _, passphrase := range getPassphrases() { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + err = locker.Unlock(ctx, []byte(passphrase)) + cancel() + if err == nil { + // Unlocked. + return false, nil + } + } + + // Failed to unlock it. + return false, errors.New("failed to unlock account") +} + +// lock attempts to lock an account. +func lock(account e2wtypes.Account) error { + locker, isAccountLocker := account.(e2wtypes.AccountLocker) + if !isAccountLocker { + return nil + } + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + return locker.Lock(ctx) +} diff --git a/cmd/validatordepositdata.go b/cmd/validatordepositdata.go index dca6b85..831b77e 100644 --- a/cmd/validatordepositdata.go +++ b/cmd/validatordepositdata.go @@ -14,6 +14,7 @@ package cmd import ( + "context" "encoding/hex" "fmt" "os" @@ -21,9 +22,11 @@ import ( "github.com/prysmaticlabs/go-ssz" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/wealdtech/ethdo/grpc" e2types "github.com/wealdtech/go-eth2-types/v2" util "github.com/wealdtech/go-eth2-util" + e2wallet "github.com/wealdtech/go-eth2-wallet" string2eth "github.com/wealdtech/go-string2eth" ) @@ -47,28 +50,34 @@ The information generated can be passed to ethereal to create a deposit from the In quiet mode this will return 0 if the the data can be generated correctly, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + assert(validatorDepositDataValidatorAccount != "", "--validatoraccount is required") - validatorWallet, err := walletFromPath(validatorDepositDataValidatorAccount) + validatorWalletName, validatorAccountSpec, err := e2wallet.WalletAndAccountNames(validatorDepositDataValidatorAccount) + errCheck(err, "Failed to obtain wallet and account names") + validatorWallet, err := openNamedWallet(validatorWalletName) errCheck(err, "Failed to obtain validator wallet") - validatorAccounts, err := accountsFromPath(validatorDepositDataValidatorAccount) + validatorAccounts, err := accountsFromPath(ctx, validatorWallet, validatorAccountSpec) errCheck(err, "Failed to obtain validator account") assert(len(validatorAccounts) > 0, "Failed to obtain validator account") - if len(validatorAccounts) == 1 { - outputIf(debug, fmt.Sprintf("Validator public key is %048x", validatorAccounts[0].PublicKey().Marshal())) - } else { - for _, validatorAccount := range validatorAccounts { - outputIf(verbose, fmt.Sprintf("Creating deposit for %s/%s", validatorWallet.Name(), validatorAccount.Name())) - outputIf(debug, fmt.Sprintf("Validator public key is %048x", validatorAccount.PublicKey().Marshal())) - } + + for _, validatorAccount := range validatorAccounts { + outputIf(verbose, fmt.Sprintf("Creating deposit for %s/%s", validatorWallet.Name(), validatorAccount.Name())) + pubKey, err := bestPublicKey(validatorAccount) + errCheck(err, "Validator account does not provide a public key") + outputIf(debug, fmt.Sprintf("Validator public key is %#x", pubKey.Marshal())) } assert(validatorDepositDataWithdrawalAccount != "" || validatorDepositDataWithdrawalPubKey != "", "--withdrawalaccount or --withdrawalpubkey is required") var withdrawalCredentials []byte if validatorDepositDataWithdrawalAccount != "" { - withdrawalAccount, err := accountFromPath(validatorDepositDataWithdrawalAccount) + withdrawalAccount, err := accountFromPath(ctx, validatorDepositDataWithdrawalAccount) errCheck(err, "Failed to obtain withdrawal account") - outputIf(debug, fmt.Sprintf("Withdrawal public key is %048x", withdrawalAccount.PublicKey().Marshal())) - withdrawalCredentials = util.SHA256(withdrawalAccount.PublicKey().Marshal()) + pubKey, err := bestPublicKey(withdrawalAccount) + errCheck(err, "Withdrawal account does not provide a public key") + outputIf(debug, fmt.Sprintf("Withdrawal public key is %#x", pubKey.Marshal())) + withdrawalCredentials = util.SHA256(pubKey.Marshal()) errCheck(err, "Failed to hash withdrawal credentials") } else { withdrawalPubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorDepositDataWithdrawalPubKey, "0x")) @@ -81,7 +90,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth } // This is hard-coded, to allow deposit data to be generated without a connection to the beacon node. withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX - outputIf(debug, fmt.Sprintf("Withdrawal credentials are %032x", withdrawalCredentials)) + outputIf(debug, fmt.Sprintf("Withdrawal credentials are %#x", withdrawalCredentials)) assert(validatorDepositDataDepositValue != "", "--depositvalue is required") val, err := string2eth.StringToGWei(validatorDepositDataDepositValue) @@ -92,12 +101,14 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth // For each key, generate deposit data outputs := make([]string, 0) for _, validatorAccount := range validatorAccounts { + validatorPubKey, err := bestPublicKey(validatorAccount) + errCheck(err, "Validator account does not provide a public key") depositData := struct { PubKey []byte `ssz-size:"48"` WithdrawalCredentials []byte `ssz-size:"32"` Value uint64 }{ - PubKey: validatorAccount.PublicKey().Marshal(), + PubKey: validatorPubKey.Marshal(), WithdrawalCredentials: withdrawalCredentials, Value: val, } @@ -124,17 +135,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth domain := e2types.Domain(e2types.DomainDeposit, forkVersion, e2types.ZeroGenesisValidatorsRoot) outputIf(debug, fmt.Sprintf("Domain is %x", domain)) - unlocked := false - for _, passphrase := range getPassphrases() { - err = validatorAccount.Unlock([]byte(passphrase)) - if err == nil { - unlocked = true - break - } - } - assert(unlocked, "Failed to unlock validator account") signature, err := signStruct(validatorAccount, depositData, domain) - validatorAccount.Lock() errCheck(err, "Failed to generate deposit data signature") signedDepositData := struct { @@ -143,12 +144,18 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth Value uint64 Signature []byte `ssz-size:"96"` }{ - PubKey: validatorAccount.PublicKey().Marshal(), + PubKey: validatorPubKey.Marshal(), WithdrawalCredentials: withdrawalCredentials, Value: val, Signature: signature.Marshal(), } - outputIf(debug, fmt.Sprintf("Signed deposit data:\n\tPublic key: %x\n\tWithdrawal credentials: %x\n\tValue: %d\n\tSignature: %x", signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Value, signedDepositData.Signature)) + if debug { + fmt.Printf("Signed deposit data:\n") + fmt.Printf(" Public key: %#x\n", signedDepositData.PubKey) + fmt.Printf(" Withdrawal credentials: %#x\n", signedDepositData.WithdrawalCredentials) + fmt.Printf(" Value: %d\n", signedDepositData.Value) + fmt.Printf(" Signature: %#x\n", signedDepositData.Signature) + } depositDataRoot, err := ssz.HashTreeRoot(signedDepositData) errCheck(err, "Failed to generate deposit data root") @@ -167,7 +174,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth txData = append(txData, depositDataRoot[:]...) // Validator public key (pad to 32-byte boundary) txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30}...) - txData = append(txData, validatorAccount.PublicKey().Marshal()...) + txData = append(txData, validatorPubKey.Marshal()...) txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...) // Withdrawal credentials txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}...) @@ -177,7 +184,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth txData = append(txData, signedDepositData.Signature...) outputs = append(outputs, fmt.Sprintf("%#x", txData)) } else { - outputs = append(outputs, fmt.Sprintf(`{"account":"%s","pubkey":"%048x","withdrawal_credentials":"%032x","signature":"%096x","value":%d,"deposit_data_root":"%032x","version":2}`, fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Signature, val, depositDataRoot)) + outputs = append(outputs, fmt.Sprintf(`{"name":"Deposit for %s","account":"%s","pubkey":"%#x","withdrawal_credentials":"%#x","signature":"%#x","value":%d,"deposit_data_root":"%#x","version":2}`, fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Signature, val, depositDataRoot)) } } diff --git a/cmd/validatorexit.go b/cmd/validatorexit.go index b2ce7a3..90971d3 100644 --- a/cmd/validatorexit.go +++ b/cmd/validatorexit.go @@ -46,30 +46,33 @@ var validatorExitCmd = &cobra.Command{ In quiet mode this will return 0 if the transaction has been generated, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + err := connect() errCheck(err, "Failed to obtain connect to Ethereum 2 beacon chain node") - exit, signature := validatorExitHandleInput() - validatorExitHandleExit(exit, signature) + exit, signature := validatorExitHandleInput(ctx) + validatorExitHandleExit(ctx, exit, signature) os.Exit(_exitSuccess) }, } -func validatorExitHandleInput() (*ethpb.VoluntaryExit, e2types.Signature) { +func validatorExitHandleInput(ctx context.Context) (*ethpb.VoluntaryExit, e2types.Signature) { if validatorExitJSON != "" { return validatorExitHandleJSONInput(validatorExitJSON) } - if rootAccount != "" { - account, err := accountFromPath(rootAccount) + if viper.GetString("account") != "" { + account, err := accountFromPath(ctx, viper.GetString("account")) errCheck(err, "Failed to access account") - return validatorExitHandleAccountInput(account) + return validatorExitHandleAccountInput(ctx, account) } if validatorExitKey != "" { privKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorExitKey, "0x")) errCheck(err, fmt.Sprintf("Failed to decode key %s", validatorExitKey)) account, err := util.NewScratchAccount(privKeyBytes, nil) errCheck(err, "Invalid private key") - return validatorExitHandleAccountInput(account) + return validatorExitHandleAccountInput(ctx, account) } die("one of --json, --account or --key is required") return nil, nil @@ -88,7 +91,7 @@ func validatorExitHandleJSONInput(input string) (*ethpb.VoluntaryExit, e2types.S return exit, signature } -func validatorExitHandleAccountInput(account e2wtypes.Account) (*ethpb.VoluntaryExit, e2types.Signature) { +func validatorExitHandleAccountInput(ctx context.Context, account e2wtypes.Account) (*ethpb.VoluntaryExit, e2types.Signature) { exit := ðpb.VoluntaryExit{} // Beacon chain config required for later work. @@ -141,23 +144,19 @@ func validatorExitHandleAccountInput(account e2wtypes.Account) (*ethpb.Voluntary errCheck(err, "Failed to obtain genesis validators root") domain := e2types.Domain(e2types.DomainVoluntaryExit, currentForkVersion, genesisValidatorsRoot) - unlocked := false - for _, passphrase := range getPassphrases() { - err = account.Unlock([]byte(passphrase)) - if err == nil { - unlocked = true - break - } - } - assert(unlocked, "Failed to unlock account; please confirm passphrase is correct") + alreadyUnlocked, err := unlock(account) + errCheck(err, "Failed to unlock account; please confirm passphrase is correct") signature, err := signStruct(account, exit, domain) + if !alreadyUnlocked { + errCheck(lock(account), "Failed to re-lock account") + } errCheck(err, "Failed to sign exit proposal") return exit, signature } // validatorExitHandleExit handles the exit request. -func validatorExitHandleExit(exit *ethpb.VoluntaryExit, signature e2types.Signature) { +func validatorExitHandleExit(ctx context.Context, exit *ethpb.VoluntaryExit, signature e2types.Signature) { if validatorExitJSONOutput { data := &validatorExitData{ Epoch: exit.Epoch, @@ -174,8 +173,6 @@ func validatorExitHandleExit(exit *ethpb.VoluntaryExit, signature e2types.Signat } validatorClient := ethpb.NewBeaconNodeValidatorClient(eth2GRPCConn) - ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) - defer cancel() _, err := validatorClient.ProposeExit(ctx, proposal) errCheck(err, "Failed to propose exit") outputIf(!quiet, "Validator exit transaction sent") diff --git a/cmd/validatorinfo.go b/cmd/validatorinfo.go index 41ecc79..22d783f 100644 --- a/cmd/validatorinfo.go +++ b/cmd/validatorinfo.go @@ -14,6 +14,7 @@ package cmd import ( + "context" "encoding/hex" "fmt" "os" @@ -22,9 +23,11 @@ import ( ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/wealdtech/ethdo/grpc" "github.com/wealdtech/ethdo/util" - types "github.com/wealdtech/go-eth2-wallet-types/v2" + e2wallet "github.com/wealdtech/go-eth2-wallet" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" string2eth "github.com/wealdtech/go-string2eth" ) @@ -40,15 +43,23 @@ var validatorInfoCmd = &cobra.Command{ In quiet mode this will return 0 if the validator information can be obtained, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { // Sanity checking and setup. - assert(rootAccount != "" || validatorInfoPubKey != "", "--account or --pubkey is required") + assert(viper.GetString("account") != "" || validatorInfoPubKey != "", "--account or --pubkey is required") err := connect() errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node") - var account types.Account - if rootAccount != "" { - account, err = accountFromPath(rootAccount) - errCheck(err, "Failed to access account") + var account e2wtypes.Account + if viper.GetString("account") != "" { + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") + _, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account")) + errCheck(err, "Failed to obtain account name") + accountByNameProvider, isAccountByNameProvider := wallet.(e2wtypes.WalletAccountByNameProvider) + assert(isAccountByNameProvider, "wallet cannot obtain accounts by name") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + account, err = accountByNameProvider.AccountByName(ctx, accountName) + errCheck(err, "Failed to obtain account") } else { pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorInfoPubKey, "0x")) errCheck(err, fmt.Sprintf("Failed to decode public key %s", validatorInfoPubKey)) diff --git a/cmd/version.go b/cmd/version.go index 83e88f6..aea9f58 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -30,7 +30,7 @@ var versionCmd = &cobra.Command{ ethdo version.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Println("1.4.21") + fmt.Println("1.5.0-prerelease") if viper.GetBool("verbose") { buildInfo, ok := dbg.ReadBuildInfo() if ok { diff --git a/cmd/wallet.go b/cmd/wallet.go index 8394e75..67455af 100644 --- a/cmd/wallet.go +++ b/cmd/wallet.go @@ -15,10 +15,10 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/spf13/viper" ) -var walletWallet string - // walletCmd represents the wallet command var walletCmd = &cobra.Command{ Use: "wallet", @@ -30,6 +30,16 @@ func init() { RootCmd.AddCommand(walletCmd) } +var walletFlag *pflag.Flag + func walletFlags(cmd *cobra.Command) { - cmd.Flags().StringVar(&walletWallet, "wallet", "", "Name of the wallet") + if walletFlag == nil { + cmd.Flags().String("wallet", "", "Name of the wallet") + walletFlag = cmd.Flags().Lookup("wallet") + if err := viper.BindPFlag("wallet", walletFlag); err != nil { + panic(err) + } + } else { + cmd.Flags().AddFlag(walletFlag) + } } diff --git a/cmd/walletaccounts.go b/cmd/walletaccounts.go index 4d2bf55..c892187 100644 --- a/cmd/walletaccounts.go +++ b/cmd/walletaccounts.go @@ -20,7 +20,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - pb "github.com/wealdtech/eth2-signer-api/pb/v1" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var walletAccountsCmd = &cobra.Command{ @@ -32,52 +32,35 @@ var walletAccountsCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet holds any addresses, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(walletWallet != "", "--wallet is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("wallet") != "", "wallet is required") + + wallet, err := openWallet() + errCheck(err, "Failed to access wallet") hasAccounts := false - - if remote { - listerClient := pb.NewListerClient(remoteGRPCConn) - listAccountsReq := &pb.ListAccountsRequest{ - Paths: []string{ - walletWallet, - }, - } - ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) - defer cancel() - accountsResp, err := listerClient.ListAccounts(ctx, listAccountsReq) - errCheck(err, "Failed to access wallet") - assert(accountsResp.State == pb.ResponseState_SUCCEEDED, "Request to list wallet accounts failed") - walletPrefixLen := len(walletWallet) + 1 - for _, account := range accountsResp.Accounts { - hasAccounts = true - if verbose { - fmt.Printf("%s\n", account.Name[walletPrefixLen:]) - fmt.Printf("\tPublic key: %#048x\n", account.PublicKey) - } else if !quiet { - fmt.Printf("%s\n", account.Name[walletPrefixLen:]) + for account := range wallet.Accounts(ctx) { + hasAccounts = true + outputIf(!quiet, account.Name()) + if verbose { + fmt.Printf(" UUID: %v\n", account.ID()) + pubKeyProvider, isProvider := account.(e2wtypes.AccountPublicKeyProvider) + if isProvider { + fmt.Printf(" Public key: %#x\n", pubKeyProvider.PublicKey().Marshal()) } - } - } else { - wallet, err := walletFromPath(walletWallet) - errCheck(err, "Failed to access wallet") - - for account := range wallet.Accounts() { - hasAccounts = true - if verbose { - fmt.Printf("%s\n\tUUID:\t\t%s\n\tPublic key:\t0x%048x\n", account.Name(), account.ID(), account.PublicKey().Marshal()) - } else if !quiet { - fmt.Printf("%s\n", account.Name()) + compositePubKeyProvider, isProvider := account.(e2wtypes.AccountCompositePublicKeyProvider) + if isProvider { + fmt.Printf(" Composite public key: %#x\n", compositePubKeyProvider.CompositePublicKey().Marshal()) } } } - if quiet { - if hasAccounts { - os.Exit(_exitSuccess) - } - os.Exit(_exitFailure) + if hasAccounts { + os.Exit(_exitSuccess) } + os.Exit(_exitFailure) }, } diff --git a/cmd/walletcreate.go b/cmd/walletcreate.go index db3f413..a2a00da 100644 --- a/cmd/walletcreate.go +++ b/cmd/walletcreate.go @@ -14,10 +14,13 @@ package cmd import ( + "context" "strings" "github.com/spf13/cobra" + "github.com/spf13/viper" bip39 "github.com/tyler-smith/go-bip39" + distributed "github.com/wealdtech/go-eth2-wallet-distributed" keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" hd "github.com/wealdtech/go-eth2-wallet-hd/v2" nd "github.com/wealdtech/go-eth2-wallet-nd/v2" @@ -35,18 +38,24 @@ var walletCreateCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet is created successfully, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet create not available with remote wallets") - assert(walletWallet != "", "--wallet is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("remote") == "", "wallet create not available with remote wallets") + assert(viper.GetString("wallet") != "", "--wallet is required") assert(walletCreateType != "", "--type is required") var err error switch strings.ToLower(walletCreateType) { case "non-deterministic", "nd": assert(walletCreateSeed == "", "--seed is not allowed with non-deterministic wallets") - err = walletCreateND(walletWallet) + err = walletCreateND(ctx, viper.GetString("wallet")) case "hierarchical deterministic", "hd": assert(getWalletPassphrase() != "", "--walletpassphrase is required for hierarchical deterministic wallets") - err = walletCreateHD(walletWallet, getWalletPassphrase(), walletCreateSeed) + err = walletCreateHD(ctx, viper.GetString("wallet"), getWalletPassphrase(), walletCreateSeed) + case "distributed": + assert(walletCreateSeed == "", "--seed is not allowed with distributed wallets") + err = walletCreateDistributed(ctx, viper.GetString("wallet")) default: die("unknown wallet type") } @@ -55,13 +64,19 @@ In quiet mode this will return 0 if the wallet is created successfully, otherwis } // walletCreateND creates a non-deterministic wallet. -func walletCreateND(name string) error { - _, err := nd.CreateWallet(name, store, keystorev4.New()) +func walletCreateND(ctx context.Context, name string) error { + _, err := nd.CreateWallet(ctx, name, store, keystorev4.New()) + return err +} + +// walletCreateDistributed creates a distributed wallet. +func walletCreateDistributed(ctx context.Context, name string) error { + _, err := distributed.CreateWallet(ctx, name, store, keystorev4.New()) return err } // walletCreateND creates a hierarchical-deterministic wallet. -func walletCreateHD(name string, passphrase string, seedPhrase string) error { +func walletCreateHD(ctx context.Context, name string, passphrase string, seedPhrase string) error { encryptor := keystorev4.New() if seedPhrase != "" { // Create wallet from a user-supplied seed. @@ -71,11 +86,11 @@ func walletCreateHD(name string, passphrase string, seedPhrase string) error { // Strip checksum; last byte. seed = seed[:len(seed)-1] assert(len(seed) == 32, "Seed must have 24 words") - _, err = hd.CreateWalletFromSeed(name, []byte(passphrase), store, encryptor, seed) + _, err = hd.CreateWalletFromSeed(ctx, name, []byte(passphrase), store, encryptor, seed) return err } // Create wallet with a random seed. - _, err := hd.CreateWallet(name, []byte(passphrase), store, encryptor) + _, err := hd.CreateWallet(ctx, name, []byte(passphrase), store, encryptor) return err } diff --git a/cmd/walletdelete.go b/cmd/walletdelete.go index 0842505..2728b8d 100644 --- a/cmd/walletdelete.go +++ b/cmd/walletdelete.go @@ -18,6 +18,7 @@ import ( "path/filepath" "github.com/spf13/cobra" + "github.com/spf13/viper" wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) @@ -30,10 +31,10 @@ var walletDeleteCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet has been deleted, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet delete not available with remote wallets") - assert(walletWallet != "", "--wallet is required") + assert(viper.GetString("remote") == "", "wallet delete not available with remote wallets") + assert(viper.GetString("wallet") != "", "--wallet is required") - wallet, err := walletFromPath(walletWallet) + wallet, err := walletFromPath(viper.GetString("wallet")) errCheck(err, "Failed to access wallet") storeProvider, ok := wallet.(wtypes.StoreProvider) diff --git a/cmd/walletexport.go b/cmd/walletexport.go index 8aa6a55..bef502c 100644 --- a/cmd/walletexport.go +++ b/cmd/walletexport.go @@ -14,10 +14,12 @@ package cmd import ( + "context" "fmt" "os" "github.com/spf13/cobra" + "github.com/spf13/viper" types "github.com/wealdtech/go-eth2-wallet-types/v2" ) @@ -32,17 +34,20 @@ var walletExportCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet is able to be exported, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet export not available with remote wallets") - assert(walletWallet != "", "--wallet is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("remote") == "", "wallet export not available with remote wallets") + assert(viper.GetString("wallet") != "", "--wallet is required") assert(walletExportPassphrase != "", "--exportpassphrase is required") - wallet, err := walletFromPath(walletWallet) + wallet, err := walletFromPath(viper.GetString("wallet")) errCheck(err, "Failed to access wallet") _, ok := wallet.(types.WalletExporter) assert(ok, fmt.Sprintf("wallets of type %q do not allow exporting accounts", wallet.Type())) - exportData, err := wallet.(types.WalletExporter).Export([]byte(walletExportPassphrase)) + exportData, err := wallet.(types.WalletExporter).Export(ctx, []byte(walletExportPassphrase)) errCheck(err, "Failed to export wallet") outputIf(!quiet, fmt.Sprintf("0x%x", exportData)) diff --git a/cmd/walletimport.go b/cmd/walletimport.go index aed587d..1ebc635 100644 --- a/cmd/walletimport.go +++ b/cmd/walletimport.go @@ -22,6 +22,7 @@ import ( "github.com/google/uuid" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/wealdtech/go-bytesutil" "github.com/wealdtech/go-ecodec" e2wallet "github.com/wealdtech/go-eth2-wallet" @@ -40,10 +41,10 @@ var walletImportCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet is imported successfully, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet import not available with remote wallets") + assert(viper.GetString("remote") == "", "wallet import not available with remote wallets") assert(walletImportData != "", "--importdata is required") assert(walletImportPassphrase != "", "--importpassphrase is required") - assert(walletWallet == "", "--wallet is not allowed (the wallet will retain its name)") + assert(viper.GetString("wallet") == "", "--wallet is not allowed (the wallet will retain its name)") if !strings.HasPrefix(walletImportData, "0x") { outputIf(debug, fmt.Sprintf("Reading wallet import from file %s", walletImportData)) diff --git a/cmd/walletinfo.go b/cmd/walletinfo.go index b6a82c8..3d48849 100644 --- a/cmd/walletinfo.go +++ b/cmd/walletinfo.go @@ -14,11 +14,13 @@ package cmd import ( + "context" "fmt" "os" "path/filepath" "github.com/spf13/cobra" + "github.com/spf13/viper" wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) @@ -31,10 +33,13 @@ var walletInfoCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet exists, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet info not available with remote wallets") - assert(walletWallet != "", "--wallet is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() - wallet, err := walletFromPath(walletWallet) + assert(viper.GetString("remote") == "", "wallet info not available with remote wallets") + assert(viper.GetString("wallet") != "", "--wallet is required") + + wallet, err := walletFromPath(viper.GetString("wallet")) errCheck(err, "unknown wallet") if quiet { @@ -55,7 +60,7 @@ In quiet mode this will return 0 if the wallet exists, otherwise 1.`, // Count the accounts. accounts := 0 - for range wallet.Accounts() { + for range wallet.Accounts(ctx) { accounts++ } fmt.Printf("Accounts: %d\n", accounts) diff --git a/cmd/walletlist.go b/cmd/walletlist.go index 0498e82..7772276 100644 --- a/cmd/walletlist.go +++ b/cmd/walletlist.go @@ -18,6 +18,7 @@ import ( "os" "github.com/spf13/cobra" + "github.com/spf13/viper" e2wallet "github.com/wealdtech/go-eth2-wallet" ) @@ -30,17 +31,14 @@ var walletListCmd = &cobra.Command{ In quiet mode this will return 0 if any wallets are found, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet list not available with remote wallets") + assert(viper.GetString("remote") == "", "wallet list not available with remote wallets") + assert(viper.GetString("wallet") == "", "wallet list does not take a --wallet parameter") walletsFound := false - if remote { - die("Remote wallets cannot be listed") - } else { - for w := range e2wallet.Wallets() { - walletsFound = true - outputIf(!quiet && !verbose, w.Name()) - outputIf(verbose, fmt.Sprintf("%s\n\tUUID:\t\t%s", w.Name(), w.ID().String())) - } + for w := range e2wallet.Wallets() { + walletsFound = true + outputIf(!quiet && !verbose, w.Name()) + outputIf(verbose, fmt.Sprintf("%s\n UUID: %s", w.Name(), w.ID().String())) } if !walletsFound { diff --git a/cmd/walletseed.go b/cmd/walletseed.go index 68683d0..3feab82 100644 --- a/cmd/walletseed.go +++ b/cmd/walletseed.go @@ -15,12 +15,14 @@ package cmd import ( "bytes" + "context" "fmt" "os" "github.com/spf13/cobra" + "github.com/spf13/viper" bip39 "github.com/tyler-smith/go-bip39" - types "github.com/wealdtech/go-eth2-wallet-types/v2" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) var walletSeedCmd = &cobra.Command{ @@ -32,18 +34,25 @@ var walletSeedCmd = &cobra.Command{ In quiet mode this will return 0 if the wallet is a hierarchical deterministic wallet, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { - assert(!remote, "wallet seed not available with remote wallets") - assert(walletWallet != "", "--wallet is required") + ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) + defer cancel() + + assert(viper.GetString("remote") == "", "wallet seed not available with remote wallets") + assert(viper.GetString("wallet") != "", "--wallet is required") assert(getWalletPassphrase() != "", "--walletpassphrase is required") - wallet, err := walletFromPath(walletWallet) + wallet, err := walletFromPath(viper.GetString("wallet")) errCheck(err, "Failed to access wallet") - _, ok := wallet.(types.WalletKeyProvider) + _, ok := wallet.(e2wtypes.WalletKeyProvider) assert(ok, fmt.Sprintf("wallets of type %q do not have a seed", wallet.Type())) - err = wallet.Unlock([]byte(getWalletPassphrase())) - errCheck(err, "Failed to unlock wallet") - seed, err := wallet.(types.WalletKeyProvider).Key() + locker, isLocker := wallet.(e2wtypes.WalletLocker) + if isLocker { + errCheck(locker.Unlock(ctx, []byte(getWalletPassphrase())), "Failed to unlock wallet") + } + keyProvider, isKeyProvider := wallet.(e2wtypes.WalletKeyProvider) + assert(isKeyProvider, "Wallet does not provide key") + seed, err := keyProvider.Key(ctx) errCheck(err, "Failed to obtain wallet key") outputIf(debug, fmt.Sprintf("Seed is %#x", seed)) seedStr, err := bip39.NewMnemonic(seed) diff --git a/go.mod b/go.mod index 3717457..f9efc6b 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/gogo/protobuf v1.3.1 github.com/google/uuid v1.1.1 github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect + github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.3.2 // indirect github.com/pelletier/go-toml v1.8.0 // indirect @@ -20,25 +21,25 @@ require ( github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.0.0 github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/tyler-smith/go-bip39 v1.0.2 - github.com/wealdtech/eth2-signer-api v1.4.0 + github.com/wealdtech/eth2-signer-api v1.5.2 github.com/wealdtech/go-bytesutil v1.1.1 github.com/wealdtech/go-ecodec v1.1.0 - github.com/wealdtech/go-eth2-types/v2 v2.4.2 - github.com/wealdtech/go-eth2-util v1.2.2 - github.com/wealdtech/go-eth2-wallet v1.10.2 + github.com/wealdtech/go-eth2-types/v2 v2.5.0 + github.com/wealdtech/go-eth2-util v1.5.0 + github.com/wealdtech/go-eth2-wallet v1.11.0 + github.com/wealdtech/go-eth2-wallet-dirk v1.0.0 + github.com/wealdtech/go-eth2-wallet-distributed v1.0.1 github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0 - github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3 - github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2 - github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2 - github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2 - github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0 + github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0 + github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0 + github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 + github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 + github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0 github.com/wealdtech/go-string2eth v1.1.0 - golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect golang.org/x/text v0.3.3 // indirect - google.golang.org/genproto v0.0.0-20200620020550-bd6e04640131 // indirect - google.golang.org/grpc v1.29.1 + google.golang.org/grpc v1.30.0 gopkg.in/ini.v1 v1.57.0 // indirect ) diff --git a/go.sum b/go.sum index 521597b..ba9571d 100644 --- a/go.sum +++ b/go.sum @@ -14,7 +14,6 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= @@ -26,10 +25,10 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.31.7 h1:TCA+pXKvzDMA3vVqhK21cCy5GarC8pTQb/DrVOWI3iY= -github.com/aws/aws-sdk-go v1.31.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.32.6 h1:HoswAabUWgnrUF7X/9dr4WRgrr8DyscxXvTDm7Qw/5c= github.com/aws/aws-sdk-go v1.32.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.33.5 h1:p2fr1ryvNTU6avUWLI+/H7FGv0TBIjzVM5WDgXBBv4U= +github.com/aws/aws-sdk-go v1.33.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -53,6 +52,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po= github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.0.3 h1:jh22xisGBjrEVnRZ1DVTpBVQm0Xndu8sMl0CWDzSIBI= +github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -64,7 +65,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472 h1:maoKvILdMk6CSWHanFcUdxXIZGKD9YpWIaVbUQ/4kfg= github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472/go.mod h1:LlFXPmgrgVYsuoFDwV8rDJ9tvt1pLQdjKvU1b5IRES0= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -74,45 +74,37 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -128,7 +120,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.13.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o= @@ -154,12 +145,20 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/herumi/bls-eth-go-binary v0.0.0-20200618063237-4d3c66ab099d h1:ZLYUT27mOTH+ogU6Sov6xs1zqYi9cRJ6ksBEELXC8R4= -github.com/herumi/bls-eth-go-binary v0.0.0-20200618063237-4d3c66ab099d/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/herumi/bls-eth-go-binary v0.0.0-20200621110855-298ffb6847bc h1:1ANh6XSZu8Quo4d03TDFhqiFjgUicMdavTtPm6B+RfE= github.com/herumi/bls-eth-go-binary v0.0.0-20200621110855-298ffb6847bc/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v0.0.0-20200624084043-9b7da5962ccb h1:rVlcEzuK/AJKzJp890JoSpJdU3hgak53oMB9mypa05s= +github.com/herumi/bls-eth-go-binary v0.0.0-20200624084043-9b7da5962ccb/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v0.0.0-20200703070911-61704dac4ad1 h1:da7FT3Bhp8GCx6TwDPQio/7GLRLR5hcZvoRb89hfc08= +github.com/herumi/bls-eth-go-binary v0.0.0-20200703070911-61704dac4ad1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d h1:P8yaFmLwc5ZlUx2sHuawcdQvpv5/0GM+WEGJ07ljN3g= +github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6 h1:xOOHoKwCj0WXm60FqRxQ0u8cLr+kq5DJUlPspEPsu/s= +github.com/herumi/bls-eth-go-binary v0.0.0-20200719025738-3e30d132e8f6/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/puddle v1.1.1 h1:PJAw7H/9hoWC4Kf3J8iNmL1SwA6E8vfsLqBiL+F6CtI= +github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -198,7 +197,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -210,8 +208,9 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -230,20 +229,14 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/protolambda/zssz v0.1.3/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag= -github.com/protolambda/zssz v0.1.4 h1:4jkt8sqwhOVR8B1JebREU/gVX0Ply4GypsV8+RWrDuw= -github.com/protolambda/zssz v0.1.4/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag= github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1ouek= github.com/protolambda/zssz v0.1.5/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag= github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786 h1:bJiOTV2sYykacsxViyRltztQY0DyjT/uFoVRZkEaxsY= github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786/go.mod h1:rs05kpTfWKl0KflsBWzBQFstoyPFMTWQTbxSAyGHe78= github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s= -github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669 h1:cX6YRZnZ9sgMqM5U14llxUiXVNJ3u07Res1IIjTOgtI= github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s= -github.com/prysmaticlabs/go-bitfield v0.0.0-20200617184054-d57b8c55ea83 h1:HujNkiChDhXhDOlpYtwJu42VFn5Vp1yt+QAEJy03RjU= -github.com/prysmaticlabs/go-bitfield v0.0.0-20200617184054-d57b8c55ea83/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s= github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65 h1:hJfAWrlxx7SKpn4S/h2JGl2HHwA1a2wSS3HAzzZ0F+U= github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s= -github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963 h1:Th5ufPIaL5s/7i3gXHTgiTwfsUhWDP/PwFRiI6qV6v0= github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc= github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae h1:7qd0Af1ozWKBU3c93YW2RH+/09hJns9+ftqWUZyts9c= github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc= @@ -252,6 +245,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y= +github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y= @@ -262,14 +257,12 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.0 h1:Ysnmjh1Di8EaWaBv40CYR4IdaIsBc5996Gh1oZzCBKk= github.com/spf13/afero v1.3.0/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -278,7 +271,6 @@ github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -289,64 +281,78 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.0.2 h1:+t3w+KwLXO6154GNJY+qUtIxLTmFjfUmpguQT1OlOT8= github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/wealdtech/eth2-signer-api v1.4.0 h1:y/Bg2SfTT5nGfwyIz7mILWE+BokeDOUE1eZ0jVqPBeA= -github.com/wealdtech/eth2-signer-api v1.4.0/go.mod h1:5wlLQ7NO7nbXo3znJOwIWHN8S4C3xHcZ0uOg9Ue4mvg= -github.com/wealdtech/go-bytesutil v1.0.1 h1:6xzMM+VEHf5WNh1PsIFcRwScgcno+CP8Rw1rGvT6Cew= +github.com/wealdtech/eth2-signer-api v1.5.0 h1:XkaEk7Y0vFbqUstHcCjVGssoqJy4zYnBcF76em1oWX8= +github.com/wealdtech/eth2-signer-api v1.5.0/go.mod h1:5wlLQ7NO7nbXo3znJOwIWHN8S4C3xHcZ0uOg9Ue4mvg= +github.com/wealdtech/eth2-signer-api v1.5.1 h1:RQb1xyZEcHGpVFNpTEKzLbGH/H04Ajb6y99b2sd8gVs= +github.com/wealdtech/eth2-signer-api v1.5.1/go.mod h1:5wlLQ7NO7nbXo3znJOwIWHN8S4C3xHcZ0uOg9Ue4mvg= +github.com/wealdtech/eth2-signer-api v1.5.2 h1:3jw8MW0r7KlX9bme0q6j+QMa8osRhEnKLkgkECH6xcU= +github.com/wealdtech/eth2-signer-api v1.5.2/go.mod h1:5wlLQ7NO7nbXo3znJOwIWHN8S4C3xHcZ0uOg9Ue4mvg= github.com/wealdtech/go-bytesutil v1.0.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc= github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s= github.com/wealdtech/go-ecodec v1.1.0 h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5Kr8o= github.com/wealdtech/go-ecodec v1.1.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4= -github.com/wealdtech/go-eth2-types/v2 v2.4.1 h1:8Brj7MvJk3EUkYBQ8A5bWLleIc3/W1Jr1tApzTXtW1A= -github.com/wealdtech/go-eth2-types/v2 v2.4.1/go.mod h1:gqvLvmdw5CaDJUmClvmLRp653Ugf0VlGO9ZoWdi7mLY= github.com/wealdtech/go-eth2-types/v2 v2.4.2 h1:EkOvP8Ma0Ru7WIh0haoST97rc0PYm2AJpuWG1HzgfCI= github.com/wealdtech/go-eth2-types/v2 v2.4.2/go.mod h1:hhKa4ZFaNU2fwUjEh8GYr8wKg5D1W4QyxZ3xpsb/2hw= -github.com/wealdtech/go-eth2-util v1.2.1 h1:ReY7XWgTgXf1Fi9MoRLodD1H7rCVMFHMHJKHXoHYNQE= -github.com/wealdtech/go-eth2-util v1.2.1/go.mod h1:PPhVwXc9gv1omyf/Ik4h97jL77HdCEzlEUX4P5wDqQw= +github.com/wealdtech/go-eth2-types/v2 v2.4.3 h1:VFYVYw9J2P/HFXi7T9HX7vzM+xx6BZ4od5PlVsUP5OE= +github.com/wealdtech/go-eth2-types/v2 v2.4.3/go.mod h1:hhKa4ZFaNU2fwUjEh8GYr8wKg5D1W4QyxZ3xpsb/2hw= +github.com/wealdtech/go-eth2-types/v2 v2.5.0 h1:L8sl3yoICAbn3134CBLNUt0o5h2voe0Es2KD5O9r8YQ= +github.com/wealdtech/go-eth2-types/v2 v2.5.0/go.mod h1:321w9X26lAnNa/lQJi2A6Lap5IsNORoLwFPoJ1i8QvY= github.com/wealdtech/go-eth2-util v1.2.2 h1:LALunpMSJFvu89RHS1zl6RjZ52805utRvd12RtquB54= github.com/wealdtech/go-eth2-util v1.2.2/go.mod h1:R3VlTd69B2Jf58s62ChcyXt11ZK1/36CTplTuyR/6dE= -github.com/wealdtech/go-eth2-wallet v1.10.1 h1:Inp0Mk8noUoJIMSBc+W+Si+WhPvs04pcTJrcMuYrNzM= -github.com/wealdtech/go-eth2-wallet v1.10.1/go.mod h1:nB3aarecFrhJLXjKhl+N6jhnbtymb/yAQQ9n1AankR8= +github.com/wealdtech/go-eth2-util v1.3.0 h1:aX1+PnxB904GIf5JE9GRKYPuGQJsCT+Q7PG9BMeFN40= +github.com/wealdtech/go-eth2-util v1.3.0/go.mod h1:nSHpt/mdwn1LyLiNzjGPH1DDIYdBENLFaY1fSRr+aKg= +github.com/wealdtech/go-eth2-util v1.5.0 h1:b3fgyvoq/WocW9LkWT7zcO5VCKzKLCc97rPrk/B9oIc= +github.com/wealdtech/go-eth2-util v1.5.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk= github.com/wealdtech/go-eth2-wallet v1.10.2 h1:oUgi6Ih5fA9thhIipzXMSaLkiwDQXwT8q3bCOLpCr7s= github.com/wealdtech/go-eth2-wallet v1.10.2/go.mod h1:8H9pgp5K7X1kU1cJMS/B3DrMZF74ZlwBThownrcRYgk= +github.com/wealdtech/go-eth2-wallet v1.11.0 h1:2KfrWDqF4sWGgk4N5+DaYmh0hOnqiCl0P4vCz5mx17U= +github.com/wealdtech/go-eth2-wallet v1.11.0/go.mod h1:E9ZRNO4JNdi27ys7oc+xWWucXu4IGfV5q1vWC9X3oqg= +github.com/wealdtech/go-eth2-wallet-dirk v1.0.0 h1:1QUcWILF3h4OLCgTPpWklvRSuPu0fqrt15jwSm7CSC4= +github.com/wealdtech/go-eth2-wallet-dirk v1.0.0/go.mod h1:VTzjJ51dedvYPr4huI7g7KXZVTpGR6ZrCDQwBxJpLck= +github.com/wealdtech/go-eth2-wallet-distributed v1.0.1 h1:3BxMII8T6t16g6lWcYWXjfdvaw8rXuwMQx9h0TG5wRg= +github.com/wealdtech/go-eth2-wallet-distributed v1.0.1/go.mod h1:Ha/8S+SCLEuSfXHdvhTLwnKaEF47o6gzQ+FURKwftvU= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0 h1:IcpS4VpXhYz+TVupB5n6C6IQzaKwG+Rc8nvgCa/da4c= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0/go.mod h1:X8WRO5hEwbjx8ZOqoRmtS1ngyflKs25GkP7qGv7yOqE= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.1 h1:L4L445Uvd1Uw+Af4I9Bu29e8OCJOhYgN9lKmzjRhNwQ= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.1/go.mod h1:1IC4wOz0SIySMld5tRi4Vb0cpe7tOwqP0hS2LsrGJ34= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.2 h1:Rrpit3nuxKOUKE7poDcs2x9MZOaodd+mact+KL+/S98= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.2/go.mod h1:STigKib4ZSefVvJjx88V2QpUGaoyUE1TiupcpsHpvKE= -github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3 h1:JJwCr0NfMnS0xI7gSE+GqENXBxNIfySoC3NtxK8dG1o= github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3/go.mod h1:STigKib4ZSefVvJjx88V2QpUGaoyUE1TiupcpsHpvKE= -github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.1 h1:ziEpwVutiAdP0+LsVsC+nlfhgc4kwQAaUNpPz/rJ+CM= -github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.1/go.mod h1:IEWuITdIQTImjHju0crCJkvGus05n1HmoMZmO+EDil8= -github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2 h1:j3cKJ02Js83ygvZOmbb+GA2iSCAQDYhY5nNdm7anzjQ= +github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0 h1:L+yrAn8TC9DQUw+S7moOJxQTp2jrHCoAZLpI747Nx2g= +github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0/go.mod h1:lhSwtkIO/Pfg5kz8k50yrDgj7ZQaElCPsXnixlrQn/I= github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2/go.mod h1:IssxoHII0ewO1VysMfCmdJP1D00tRhRhXIhhaEXIOVE= -github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.1 h1:HlJZp6xyJ14nd+IFPV8TvtJyumKe0RbHIG+PKEeqxTk= -github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.1/go.mod h1:C4m7Xv0gCgb7XUwCxxJp+45YX8Qfn1vrE0UOSHD/QfE= +github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0 h1:h4eePfG0ANOJYMonmIYOvxJ9uLmBEX4APb2O8Vhtv6k= +github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0/go.mod h1:Un2EtseZWSObmTBjgkt7Qz2am54S/0115jrF83lto1U= github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2 h1:Z4Pw7/Mlp6jJLoJnhgov8M1011HP/Pb3YYqcdYGCy6Q= github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2/go.mod h1:GSMbVCewjbxRrw32m6YCd9DOzCRjAXB3qUOQnr58JEs= -github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.1 h1:EFX2SfWQ9zi7lJ/Jy1WsVBHQuTdGp8Z/Q+uuxNFpBQA= -github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.1/go.mod h1:LDmyvkgcaY4rGnGBQwf1uc02m0dMSebm9nRHx7feVHU= +github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.0 h1:sWuSrAKdWSphiQCVcThozaFgTrwemXNXDI5CnFcP02s= +github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.0/go.mod h1:FvjUHDbBuZrytZGOfhLWgtBoxtrWhvkD47ABrUXvHs4= +github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 h1:l9YV6OBqcxp5fjscK63lzuCUIye8ANACjJdpm5ULGS8= +github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1/go.mod h1:Zxhj/4i8nRpk4LTTqFKbfI2KyvO3uqLMerNXqKZKDK0= github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2 h1:a7GWfFd139CODvvkuTbRIuRwAAjb55sFDGRh177KXGk= github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2/go.mod h1:VWvXScZKUWHbhQpadLX8Yj+mc8U/i4zGthQJee+o3xg= -github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.1 h1:uw2Kqqfcr7NMBHM0x/JpKkr1XpKr+zeASOXhOV6xobk= -github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.1/go.mod h1:psrxFO0Df0R+2iGD8Wdvb5AAYBY7zx+4/qtULaJ57IY= +github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 h1:+q7p58NvOEfEDw8NgEoNaSG/s1eFHpyg91NEobA6RF0= +github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI5bWuvjhanEyrD4MqTj8hIvt2Y= github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2 h1:GvG3ZuzxbqFjGUaGoa8Tz7XbPlDA33G6nHQbSZInC3g= github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2/go.mod h1:+TbqLmJuT98PWi/xW1bp5nwZbKz+SIJYVh/+NUkmnb4= -github.com/wealdtech/go-eth2-wallet-types/v2 v2.1.1 h1:RGvhM7C85ptEdVsCDQNt+fJrF0SrMnUb0gkgtU75ifI= -github.com/wealdtech/go-eth2-wallet-types/v2 v2.1.1/go.mod h1:608wNFKrwPzwjWeQVRE/rHnHkrRmmTCUhFg2/Bgkbvs= +github.com/wealdtech/go-eth2-wallet-store-scratch v1.5.0/go.mod h1:RMIIV5/N8TgukTVzyumQd7AplpC440ZXDSk8VffeEwQ= github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0 h1:SfoBlW2LYjW05uHhnTZaezX37gbRsp+VYtxWT6SeAME= github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0/go.mod h1:XEvrlKFnHLbg1tj4Dep76XKASeS13TBpvdeXmvLiH+k= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0-beta4 h1:VmpgUSr+aUexFmC2AYlQ7zpeAy0w0mcK58ihpDeMCL8= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0-beta4/go.mod h1:5tVjyWK/jIzKaD+L8SCmHnc/eT9k+Fmm7zd8SwNB7jA= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0 h1:PsCvp/lw7+h8Q0V3jL0f+/w2VmgS7m0mH48lbv/c2LY= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0/go.mod h1:SLST6Pw/2wOEfsMYvIQjWlxbWX+jaZu8jIEbZJc4K5Q= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0 h1:J29mbkSCUMl2xdu8Lg6U+JptFGfmli6xl04DAHtq9aM= +github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA= github.com/wealdtech/go-indexer v1.0.0 h1:/S4rfWQbSOnnYmwnvuTVatDibZ8o1s9bmTCHO16XINg= github.com/wealdtech/go-indexer v1.0.0/go.mod h1:u1cjsbsOXsm5jzJDyLmZY7GsrdX8KYXKBXkZcAmk3Zg= github.com/wealdtech/go-string2eth v1.1.0 h1:USJQmysUrBYYmZs7d45pMb90hRSyEwizP7lZaOZLDAw= @@ -365,12 +371,14 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59 h1:PyXRxSVbvzDGuqYXjHndV7xDzJ7w2K8KD9Ef8GB7KOE= golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg= +golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -405,12 +413,12 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200528225125-3c3fba18258b h1:IYiJPiJfzktmDAO1HQiwjMjwjlYKHAL7KzeD544RJPs= golang.org/x/net v0.0.0-20200528225125-3c3fba18258b/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -419,7 +427,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -437,15 +444,13 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200620081246-981b61492c35 h1:wb/9mP8eUAmHfkM8RmpeLq6nUA7c2i5+bQOtcDftjaE= golang.org/x/sys v0.0.0-20200620081246-981b61492c35/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORKTAbhZo2AbWNRCnevdo= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -482,7 +487,6 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -496,54 +500,60 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200528191852-705c0b31589b h1:nl5tymnV+50ACFZUDAP+xFCe3Zh3SWdMDx+ernZSKNA= google.golang.org/genproto v0.0.0-20200528191852-705c0b31589b/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200620020550-bd6e04640131 h1:IXNofpkLhv80L3TJQvj2YQLnMHZgAktycswvtXwQiRk= google.golang.org/genproto v0.0.0-20200620020550-bd6e04640131/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200710124503-20a17af7bd0e h1:k+p/u26/lVeNEpdxSeUrm7rTvoFckBKaf7gTzgmHyDA= +google.golang.org/genproto v0.0.0-20200710124503-20a17af7bd0e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxtiIncJxFXeCyq84ixuKWVCaCAi9Oc= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c h1:6DWnZZ6EY/59QRRQttZKiktVL23UuQYs7uy75MhhLRM= +google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= +gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/grpc/beaconchain.go b/grpc/beaconchain.go index 1308111..e5b227f 100644 --- a/grpc/beaconchain.go +++ b/grpc/beaconchain.go @@ -20,11 +20,10 @@ import ( "github.com/gogo/protobuf/types" "github.com/pkg/errors" - "github.com/spf13/viper" - "google.golang.org/grpc" - ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" - wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" + "github.com/spf13/viper" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" + "google.golang.org/grpc" ) // FetchChainConfig fetches the chain configuration from the beacon node. @@ -125,7 +124,7 @@ func FetchValidatorCommittees(conn *grpc.ClientConn, epoch uint64) (map[uint64][ } // FetchValidator fetches the validator definition from the beacon node. -func FetchValidator(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.Validator, error) { +func FetchValidator(conn *grpc.ClientConn, account e2wtypes.Account) (*ethpb.Validator, error) { if conn == nil { return nil, errors.New("no connection to beacon node") } @@ -133,9 +132,18 @@ func FetchValidator(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.Valid ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + var pubKey []byte + if pubKeyProvider, ok := account.(e2wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return nil, errors.New("Unable to obtain public key") + } + req := ðpb.GetValidatorRequest{ QueryFilter: ðpb.GetValidatorRequest_PublicKey{ - PublicKey: account.PublicKey().Marshal(), + PublicKey: pubKey, }, } return beaconClient.GetValidator(ctx, req) @@ -159,7 +167,7 @@ func FetchValidatorByIndex(conn *grpc.ClientConn, index uint64) (*ethpb.Validato } // FetchValidatorBalance fetches the validator balance from the beacon node. -func FetchValidatorBalance(conn *grpc.ClientConn, account wtypes.Account) (uint64, error) { +func FetchValidatorBalance(conn *grpc.ClientConn, account e2wtypes.Account) (uint64, error) { if conn == nil { return 0, errors.New("no connection to beacon node") } @@ -167,8 +175,17 @@ func FetchValidatorBalance(conn *grpc.ClientConn, account wtypes.Account) (uint6 ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + var pubKey []byte + if pubKeyProvider, ok := account.(e2wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return 0, errors.New("Unable to obtain public key") + } + res, err := beaconClient.ListValidatorBalances(ctx, ðpb.ListValidatorBalancesRequest{ - PublicKeys: [][]byte{account.PublicKey().Marshal()}, + PublicKeys: [][]byte{pubKey}, }) if err != nil { return 0, err @@ -180,7 +197,7 @@ func FetchValidatorBalance(conn *grpc.ClientConn, account wtypes.Account) (uint6 } // FetchValidatorPerformance fetches the validator performance from the beacon node. -func FetchValidatorPerformance(conn *grpc.ClientConn, account wtypes.Account) (bool, bool, bool, uint64, int64, error) { +func FetchValidatorPerformance(conn *grpc.ClientConn, account e2wtypes.Account) (bool, bool, bool, uint64, int64, error) { if conn == nil { return false, false, false, 0, 0, errors.New("no connection to beacon node") } @@ -188,8 +205,17 @@ func FetchValidatorPerformance(conn *grpc.ClientConn, account wtypes.Account) (b ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + var pubKey []byte + if pubKeyProvider, ok := account.(e2wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return false, false, false, 0, 0, errors.New("Unable to obtain public key") + } + req := ðpb.ValidatorPerformanceRequest{ - PublicKeys: [][]byte{account.PublicKey().Marshal()}, + PublicKeys: [][]byte{pubKey}, } res, err := beaconClient.GetValidatorPerformance(ctx, req) if err != nil { @@ -207,7 +233,7 @@ func FetchValidatorPerformance(conn *grpc.ClientConn, account wtypes.Account) (b } // FetchValidatorInfo fetches current validator info from the beacon node. -func FetchValidatorInfo(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.ValidatorInfo, error) { +func FetchValidatorInfo(conn *grpc.ClientConn, account e2wtypes.Account) (*ethpb.ValidatorInfo, error) { if conn == nil { return nil, errors.New("no connection to beacon node") } @@ -220,9 +246,18 @@ func FetchValidatorInfo(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.V return nil, errors.Wrap(err, "failed to contact beacon node") } + var pubKey []byte + if pubKeyProvider, ok := account.(e2wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(e2wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return nil, errors.New("Unable to obtain public key") + } + changeSet := ðpb.ValidatorChangeSet{ Action: ethpb.SetAction_SET_VALIDATOR_KEYS, - PublicKeys: [][]byte{account.PublicKey().Marshal()}, + PublicKeys: [][]byte{pubKey}, } err = stream.Send(changeSet) if err != nil { diff --git a/grpc/beaconnode.go b/grpc/beaconnode.go index ce10f7b..90059db 100644 --- a/grpc/beaconnode.go +++ b/grpc/beaconnode.go @@ -33,9 +33,18 @@ func FetchValidatorIndex(conn *grpc.ClientConn, account wtypes.Account) (uint64, ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + var pubKey []byte + if pubKeyProvider, ok := account.(wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return 0, errors.New("Unable to obtain public key") + } + // Fetch the account. req := ðpb.ValidatorIndexRequest{ - PublicKey: account.PublicKey().Marshal(), + PublicKey: pubKey, } resp, err := validatorClient.ValidatorIndex(ctx, req) if err != nil { @@ -54,9 +63,18 @@ func FetchValidatorState(conn *grpc.ClientConn, account wtypes.Account) (ethpb.V ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) defer cancel() + var pubKey []byte + if pubKeyProvider, ok := account.(wtypes.AccountCompositePublicKeyProvider); ok { + pubKey = pubKeyProvider.CompositePublicKey().Marshal() + } else if pubKeyProvider, ok := account.(wtypes.AccountPublicKeyProvider); ok { + pubKey = pubKeyProvider.PublicKey().Marshal() + } else { + return ethpb.ValidatorStatus_UNKNOWN_STATUS, errors.New("Unable to obtain public key") + } + // Fetch the account. req := ðpb.ValidatorStatusRequest{ - PublicKey: account.PublicKey().Marshal(), + PublicKey: pubKey, } resp, err := validatorClient.ValidatorStatus(ctx, req) if err != nil { diff --git a/util/bls.go b/util/bls.go new file mode 100644 index 0000000..285435b --- /dev/null +++ b/util/bls.go @@ -0,0 +1,31 @@ +// Copyright © 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "encoding/binary" + + "github.com/herumi/bls-eth-go-binary/bls" +) + +// BLSID turns a uint64 in to a BLS identifier. +func BLSID(id uint64) *bls.ID { + var res bls.ID + buf := [8]byte{} + binary.LittleEndian.PutUint64(buf[:], id) + if err := res.SetLittleEndian(buf[:]); err != nil { + panic(err) + } + return &res +}