Skip to content

Commit

Permalink
Add 'exit verify' command
Browse files Browse the repository at this point in the history
  • Loading branch information
mcdee committed Jul 31, 2020
1 parent b34a633 commit 115d037
Show file tree
Hide file tree
Showing 24 changed files with 417 additions and 270 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ jobs:
mv ethdo-linux-arm64 ethdo
tar zcf ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz ethdo
- name: Create draft release
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ env.RELEASE_VERSION }}
draft: true
draft: false
prerelease: false

- name: Upload windows zip file
Expand Down
7 changes: 4 additions & 3 deletions cmd/accountcreate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,19 @@ 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) {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()

assert(viper.GetString("account") != "", "--account is required")

wallet, err := openWallet()
wallet, err := walletFromInput(ctx)
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")
}
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")
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/accountimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ In quiet mode this will return 0 if the account is imported successfully, otherw
key, err := bytesutil.FromHexString(accountImportKey)
errCheck(err, "Invalid key")

w, err := walletFromPath(viper.GetString("account"))
w, err := walletFromPath(ctx, 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(ctx, viper.GetString("account"))
_, _, err = walletAndAccountFromPath(ctx, viper.GetString("account"))
assert(err != nil, "Account already exists")

locker, isLocker := w.(e2wtypes.WalletLocker)
Expand Down
27 changes: 3 additions & 24 deletions cmd/accountinfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,11 @@ import (
"context"
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
"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"
)

Expand All @@ -36,30 +34,11 @@ 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(viper.GetString("account") != "", "--account is required")

wallet, err := openWallet()
errCheck(err, "Failed to access wallet")
outputIf(debug, fmt.Sprintf("Opened wallet %q of type %s", wallet.Name(), wallet.Type()))

_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
errCheck(err, "Failed to obtain account name")

if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") {
assert(getWalletPassphrase() != "", "walletpassphrase is required to show information about dynamically generated hierarchical deterministic accounts")
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")
}
}

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)

assert(viper.GetString("account") != "", "--account is required")
wallet, account, err := walletAndAccountFromInput(ctx)
errCheck(err, "Failed to obtain account")

// Disallow wildcards (for now)
Expand Down
28 changes: 4 additions & 24 deletions cmd/accountkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ import (
"context"
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/viper"
e2wallet "github.com/wealdtech/go-eth2-wallet"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)

Expand All @@ -35,31 +33,13 @@ 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) {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()

assert(!remote, "account keys not available with remote wallets")
assert(viper.GetString("account") != "", "--account is required")

wallet, err := openWallet()
errCheck(err, "Failed to access wallet")
outputIf(debug, fmt.Sprintf("Opened wallet %q of type %s", wallet.Name(), wallet.Type()))

_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
errCheck(err, "Failed to obtain account name")

if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") {
assert(getWalletPassphrase() != "", "walletpassphrase is required to show information about dynamically generated hierarchical deterministic accounts")
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")
}
}

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)
_, account, err := walletAndAccountFromInput(ctx)
errCheck(err, "Failed to obtain account")

privateKeyProvider, isPrivateKeyProvider := account.(e2wtypes.AccountPrivateKeyProvider)
Expand Down
18 changes: 4 additions & 14 deletions cmd/accountlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/viper"
e2wallet "github.com/wealdtech/go-eth2-wallet"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)

Expand All @@ -31,27 +30,18 @@ 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(viper.GetString("account") != "", "--account is required")

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)

assert(viper.GetString("account") != "", "--account is required")

_, account, err := walletAndAccountFromInput(ctx)
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")
},
}
Expand Down
16 changes: 4 additions & 12 deletions cmd/accountunlock.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (

"github.com/spf13/cobra"
"github.com/spf13/viper"
e2wallet "github.com/wealdtech/go-eth2-wallet"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)

Expand All @@ -32,19 +31,12 @@ 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(viper.GetString("account") != "", "--account is required")

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)

assert(viper.GetString("account") != "", "--account is required")

_, account, err := walletAndAccountFromInput(ctx)
errCheck(err, "Failed to obtain account")

locker, isLocker := account.(e2wtypes.AccountLocker)
Expand Down
12 changes: 1 addition & 11 deletions cmd/accountwithdrawalcredentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"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{
Expand All @@ -47,15 +45,7 @@ In quiet mode this will return 0 if the account exists, otherwise 1.`,
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)
_, account, err := walletAndAccountFromInput(ctx)
errCheck(err, "Failed to obtain account")

key, err := bestPublicKey(account)
Expand Down
35 changes: 22 additions & 13 deletions cmd/depositverify.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,17 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
deposits, err := depositDataFromJSON(depositVerifyData)
errCheck(err, "Failed to fetch deposit data")

withdrawalCredentials := ""
var withdrawalCredentials []byte
if depositVerifyWithdrawalPubKey != "" {
withdrawalPubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(depositVerifyWithdrawalPubKey, "0x"))
errCheck(err, "Invalid withdrawal public key")
assert(len(withdrawalPubKeyBytes) == 48, "Public key should be 48 bytes")
withdrawalPubKey, err := e2types.BLSPublicKeyFromBytes(withdrawalPubKeyBytes)
errCheck(err, "Value supplied with --withdrawalpubkey is not a valid public key")
withdrawalBytes := util.SHA256(withdrawalPubKey.Marshal())
withdrawalBytes[0] = 0 // BLS_WITHDRAWAL_PREFIX
withdrawalCredentials = fmt.Sprintf("%x", withdrawalBytes)
withdrawalCredentials = util.SHA256(withdrawalPubKey.Marshal())
withdrawalCredentials[0] = 0 // BLS_WITHDRAWAL_PREFIX
}
outputIf(debug, fmt.Sprintf("Withdrawal credentials are %s", withdrawalCredentials))
outputIf(debug, fmt.Sprintf("Withdrawal credentials are %#x", withdrawalCredentials))

depositValue := uint64(0)
if depositVerifyDepositValue != "" {
Expand All @@ -81,16 +80,18 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
assert(depositValue >= 1000000000, "deposit value must be at least 1 Ether") // MIN_DEPOSIT_AMOUNT
}

validatorPubKeys := make(map[string]bool)
validatorPubKeys := make(map[[48]byte]bool)
if depositVerifyValidatorPubKey != "" {
validatorPubKeys, err = validatorPubKeysFromInput(depositVerifyValidatorPubKey)
errCheck(err, "Failed to obtain validator public key(s))")
}

failures := false
for i, deposit := range deposits {
if withdrawalCredentials != "" {
if deposit.WithdrawalCredentials != withdrawalCredentials {
if withdrawalCredentials != nil {
depositWithdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x"))
errCheck(err, fmt.Sprintf("Invalid withdrawal public key for deposit %d", i))
if !bytes.Equal(depositWithdrawalCredentials, withdrawalCredentials) {
outputIf(!quiet, fmt.Sprintf("Invalid withdrawal credentials for deposit %d", i))
failures = true
}
Expand All @@ -102,7 +103,11 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
}
}
if len(validatorPubKeys) != 0 {
if _, exists := validatorPubKeys[deposit.PublicKey]; !exists {
depositValidatorPubKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x"))
errCheck(err, fmt.Sprintf("Invalid validator public key for deposit %d", i))
var key [48]byte
copy(key[:], depositValidatorPubKey)
if _, exists := validatorPubKeys[key]; !exists {
outputIf(!quiet, fmt.Sprintf("Unknown validator public key for deposit %d", i))
failures = true
}
Expand All @@ -117,8 +122,8 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
},
}

func validatorPubKeysFromInput(input string) (map[string]bool, error) {
pubKeys := make(map[string]bool)
func validatorPubKeysFromInput(input string) (map[[48]byte]bool, error) {
pubKeys := make(map[[48]byte]bool)
var err error
var data []byte
// Input could be a public key or a path to public keys.
Expand All @@ -135,7 +140,9 @@ func validatorPubKeysFromInput(input string) (map[string]bool, error) {
if err != nil {
return nil, errors.Wrap(err, "invalid public key")
}
pubKeys[fmt.Sprintf("%x", pubKey.Marshal())] = true
var key [48]byte
copy(key[:], pubKey.Marshal())
pubKeys[key] = true
} else {
// Assume it's a path to a file of public keys.
data, err = ioutil.ReadFile(input)
Expand All @@ -161,7 +168,9 @@ func validatorPubKeysFromInput(input string) (map[string]bool, error) {
if err != nil {
return nil, errors.Wrap(err, "invalid public key")
}
pubKeys[fmt.Sprintf("%x", pubKey.Marshal())] = true
var key [48]byte
copy(key[:], pubKey.Marshal())
pubKeys[key] = true
}
}

Expand Down
32 changes: 32 additions & 0 deletions cmd/exit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright © 2019 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 (
"github.com/spf13/cobra"
)

// exitCmd represents the exit command
var exitCmd = &cobra.Command{
Use: "exit",
Short: "Manage Ethereum 2 voluntary exits",
Long: `Manage Ethereum 2 voluntary exits.`,
}

func init() {
RootCmd.AddCommand(exitCmd)
}

func exitFlags(cmd *cobra.Command) {
}
Loading

0 comments on commit 115d037

Please sign in to comment.