This commit is contained in:
Jim McDonald
2020-07-20 13:38:51 +01:00
parent f2bb5e0d51
commit fc9c4cfe0c
36 changed files with 1146 additions and 569 deletions

View File

@@ -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)
}
}

View File

@@ -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)
},
}

View File

@@ -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)

View File

@@ -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)
},
}

View File

@@ -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")
},
}

View File

@@ -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)
},

View File

@@ -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)
}
}

View File

@@ -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))

View File

@@ -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)
}

View File

@@ -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)
},
}

View File

@@ -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 {

View File

@@ -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)
},

View File

@@ -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)
}

View File

@@ -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)
}
}

110
cmd/signatureaggregate.go Normal file
View File

@@ -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)
}

View File

@@ -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)
},
}

View File

@@ -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)")
}

160
cmd/signing.go Normal file
View File

@@ -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)
}

View File

@@ -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))
}
}

View File

@@ -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 := &ethpb.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")

View File

@@ -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))

View File

@@ -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 {

View File

@@ -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)
}
}

View File

@@ -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)
},
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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))

View File

@@ -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))

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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)

27
go.mod
View File

@@ -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
)

150
go.sum
View File

@@ -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=

View File

@@ -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 := &ethpb.GetValidatorRequest{
QueryFilter: &ethpb.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, &ethpb.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 := &ethpb.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 := &ethpb.ValidatorChangeSet{
Action: ethpb.SetAction_SET_VALIDATOR_KEYS,
PublicKeys: [][]byte{account.PublicKey().Marshal()},
PublicKeys: [][]byte{pubKey},
}
err = stream.Send(changeSet)
if err != nil {

View File

@@ -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 := &ethpb.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 := &ethpb.ValidatorStatusRequest{
PublicKey: account.PublicKey().Marshal(),
PublicKey: pubKey,
}
resp, err := validatorClient.ValidatorStatus(ctx, req)
if err != nil {

31
util/bls.go Normal file
View File

@@ -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
}