mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-09 22:18:01 -05:00
Compare commits
9 Commits
v1.5.0-bet
...
v1.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f0aeac9b4 | ||
|
|
37cab43242 | ||
|
|
6f94e599ac | ||
|
|
86bc3d5418 | ||
|
|
8cc45f0b4b | ||
|
|
77df1bba43 | ||
|
|
1d4e52cb49 | ||
|
|
c1e124fbd3 | ||
|
|
91bc6ec86d |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
go get github.com/suburbandad/xgo
|
||||
|
||||
- name: Cross-compile
|
||||
run: xgo -v -x --targets="linux/amd64,linux/arm64,windows/amd64" github.com/wealdtech/ethdo
|
||||
run: xgo -v -x -ldflags="-X github.com/wealdtech/ethdo/cmd.ReleaseVersion=${RELEASE_VERSION}" --targets="linux/amd64,linux/arm64,windows/amd64" github.com/wealdtech/ethdo
|
||||
|
||||
- name: Create windows zip file
|
||||
run: |
|
||||
|
||||
27
README.md
27
README.md
@@ -10,7 +10,9 @@ A command-line tool for managing common tasks in Ethereum 2.
|
||||
## Table of Contents
|
||||
|
||||
- [Install](#install)
|
||||
- [Binaries](#binaries)
|
||||
- [Docker](#docker)
|
||||
- [Source](#source)
|
||||
- [Usage](#usage)
|
||||
- [Maintainers](#maintainers)
|
||||
- [Contribute](#contribute)
|
||||
@@ -18,6 +20,19 @@ A command-line tool for managing common tasks in Ethereum 2.
|
||||
|
||||
## Install
|
||||
|
||||
### Binaries
|
||||
|
||||
Binaries for the latest version of `ethdo` can be obtained from [the releases page](https://github.com/wealdtech/ethdo/releases).
|
||||
|
||||
### Docker
|
||||
|
||||
You can obtain the latest version of `ethdo` using docker with:
|
||||
|
||||
```
|
||||
docker pull wealdtech/ethdo
|
||||
```
|
||||
|
||||
### Source
|
||||
`ethdo` is a standard Go program which can be installed with:
|
||||
|
||||
```sh
|
||||
@@ -28,15 +43,7 @@ Note that `ethdo` requires at least version 1.13 of go to operate. The version
|
||||
|
||||
If this does not work please see the [troubleshooting](https://github.com/wealdtech/ethdo/blob/master/docs/troubleshooting.md) page.
|
||||
|
||||
### Docker
|
||||
|
||||
You can obtain the latest version of `ethdo` using docker with:
|
||||
|
||||
```
|
||||
docker pull wealdtech/ethdo
|
||||
```
|
||||
|
||||
Or build `ethdo` using docker:
|
||||
The docker image can be build locally with:
|
||||
|
||||
```sh
|
||||
docker build -t ethdo .
|
||||
@@ -142,6 +149,8 @@ There is a [HOWTO](https://github.com/wealdtech/ethdo/blob/master/docs/howto.md)
|
||||
|
||||
Jim McDonald: [@mcdee](https://github.com/mcdee).
|
||||
|
||||
Special thanks to [@SuburbanDad](https://github.com/SuburbanDad) for updating xgo to allow for cross-compilation of `ethdo` releaes.
|
||||
|
||||
## Contribute
|
||||
|
||||
Contributions welcome. Please check out [the issues](https://github.com/wealdtech/ethdo/issues).
|
||||
|
||||
@@ -61,6 +61,7 @@ In quiet mode this will return 0 if the account is created successfully, otherwi
|
||||
defer cancel()
|
||||
account, err = distributedCreator.CreateDistributedAccount(ctx, accountName, viper.GetUint32("participants"), viper.GetUint32("signing-threshold"), []byte(getPassphrase()))
|
||||
} else {
|
||||
// Want a standard account.
|
||||
creator, isCreator := wallet.(e2wtypes.WalletAccountCreator)
|
||||
assert(isCreator, "Wallet does not support account creation")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
|
||||
@@ -55,7 +55,7 @@ In quiet mode this will return 0 if the key can be obtained, otherwise 1.`,
|
||||
}
|
||||
}
|
||||
assert(unlocked, "Failed to unlock account to obtain private key")
|
||||
defer errCheck(locker.Lock(context.Background()), "failed to re-lock account")
|
||||
defer relockAccount(locker)
|
||||
}
|
||||
privateKey, err := privateKeyProvider.PrivateKey(ctx)
|
||||
errCheck(err, "Failed to obtain private key")
|
||||
|
||||
@@ -57,10 +57,10 @@ func assert(condition bool, msg string) {
|
||||
|
||||
// die prints an error and quits
|
||||
func die(msg string) {
|
||||
if !quiet {
|
||||
if msg != "" && !quiet {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", msg)
|
||||
}
|
||||
os.Exit(1)
|
||||
os.Exit(_exitFailure)
|
||||
}
|
||||
|
||||
// warnCheck checks for an error and warns if it is present
|
||||
|
||||
47
cmd/networks.go
Normal file
47
cmd/networks.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/wealdtech/ethdo/grpc"
|
||||
)
|
||||
|
||||
// networks is a map of deposit contract addresses to networks.
|
||||
var networks = map[string]string{
|
||||
"16e82d77882a663454ef92806b7deca1d394810f": "Altona",
|
||||
"0f0f0fc0530007361933eab5db97d09acdd6c1c8": "Onyx",
|
||||
"07b39f4fde4a38bace212b546dac87c58dfe3fdc": "Medalla",
|
||||
}
|
||||
|
||||
// network returns the name of the network, if known.
|
||||
func network() string {
|
||||
if err := connect(); err != nil {
|
||||
return "Unknown"
|
||||
}
|
||||
|
||||
depositContractAddress, err := grpc.FetchDepositContractAddress(eth2GRPCConn)
|
||||
if err != nil {
|
||||
return "Unknown"
|
||||
}
|
||||
outputIf(debug, fmt.Sprintf("Deposit contract is %x", depositContractAddress))
|
||||
|
||||
depositContract := fmt.Sprintf("%x", depositContractAddress)
|
||||
if network, exists := networks[depositContract]; exists {
|
||||
return network
|
||||
} else {
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
12
cmd/root.go
12
cmd/root.go
@@ -272,7 +272,7 @@ func accountFromPath(ctx context.Context, path string) (e2wtypes.Account, error)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid wallet passphrase")
|
||||
}
|
||||
defer errCheck(locker.Lock(context.Background()), "failed to re-lock account")
|
||||
defer relockAccount(locker)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,11 @@ func accountsFromPath(ctx context.Context, wallet e2wtypes.Wallet, accountSpec s
|
||||
|
||||
// connect connects to an Ethereum 2 endpoint.
|
||||
func connect() error {
|
||||
if eth2GRPCConn != nil {
|
||||
// Already connected.
|
||||
return nil
|
||||
}
|
||||
|
||||
connection := ""
|
||||
if viper.GetString("connection") != "" {
|
||||
connection = viper.GetString("connection")
|
||||
@@ -403,3 +408,8 @@ func openNamedWallet(walletName string) (e2wtypes.Wallet, error) {
|
||||
}
|
||||
return walletFromPath(walletName)
|
||||
}
|
||||
|
||||
// relockAccount locks an account; generally called as a defer after an account is unlocked.
|
||||
func relockAccount(locker e2wtypes.AccountLocker) {
|
||||
errCheck(locker.Lock(context.Background()), "failed to re-lock account")
|
||||
}
|
||||
|
||||
@@ -14,13 +14,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -42,74 +48,73 @@ 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(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 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))
|
||||
account, err = util.NewScratchAccount(nil, pubKeyBytes)
|
||||
errCheck(err, fmt.Sprintf("Invalid public key %s", validatorInfoPubKey))
|
||||
}
|
||||
account, err := validatorInfoAccount()
|
||||
errCheck(err, "Failed to obtain validator account")
|
||||
|
||||
validatorInfo, err := grpc.FetchValidatorInfo(eth2GRPCConn, account)
|
||||
errCheck(err, "Failed to obtain validator information")
|
||||
validatorDef, err := grpc.FetchValidator(eth2GRPCConn, account)
|
||||
validator, err := grpc.FetchValidator(eth2GRPCConn, account)
|
||||
if err != nil {
|
||||
// We can live with this.
|
||||
validator = nil
|
||||
}
|
||||
if validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED &&
|
||||
validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
|
||||
errCheck(err, "Failed to obtain validator definition")
|
||||
}
|
||||
|
||||
assert(validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS, "Not known as a validator")
|
||||
|
||||
if quiet {
|
||||
os.Exit(_exitSuccess)
|
||||
}
|
||||
|
||||
outputIf(verbose, fmt.Sprintf("Epoch of data:\t\t%v", validatorInfo.Epoch))
|
||||
outputIf(verbose && validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED, fmt.Sprintf("Index:\t\t\t%v", validatorInfo.Index))
|
||||
outputIf(verbose, fmt.Sprintf("Public key:\t\t%#x", validatorInfo.PublicKey))
|
||||
fmt.Printf("Status:\t\t\t%s\n", strings.Title(strings.ToLower(validatorInfo.Status.String())))
|
||||
fmt.Printf("Balance:\t\t%s\n", string2eth.GWeiToString(validatorInfo.Balance, true))
|
||||
outputIf(verbose, fmt.Sprintf("Epoch of data: %v", validatorInfo.Epoch))
|
||||
outputIf(verbose && validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED, fmt.Sprintf("Index: %v", validatorInfo.Index))
|
||||
outputIf(verbose, fmt.Sprintf("Public key: %#x", validatorInfo.PublicKey))
|
||||
fmt.Printf("Status: %s\n", strings.Title(strings.ToLower(validatorInfo.Status.String())))
|
||||
fmt.Printf("Balance: %s\n", string2eth.GWeiToString(validatorInfo.Balance, true))
|
||||
|
||||
if verbose {
|
||||
network := network()
|
||||
outputIf(debug, fmt.Sprintf("Network is %s", network))
|
||||
deposits, totalDeposited, err := graphData(network, validator.PublicKey)
|
||||
if err == nil {
|
||||
fmt.Printf("Number of deposits: %d\n", deposits)
|
||||
fmt.Printf("Total deposited: %s\n", string2eth.GWeiToString(totalDeposited, true))
|
||||
}
|
||||
}
|
||||
|
||||
if validatorInfo.Status == ethpb.ValidatorStatus_ACTIVE ||
|
||||
validatorInfo.Status == ethpb.ValidatorStatus_EXITING ||
|
||||
validatorInfo.Status == ethpb.ValidatorStatus_SLASHING {
|
||||
fmt.Printf("Effective balance:\t%s\n", string2eth.GWeiToString(validatorInfo.EffectiveBalance, true))
|
||||
fmt.Printf("Effective balance: %s\n", string2eth.GWeiToString(validatorInfo.EffectiveBalance, true))
|
||||
}
|
||||
if validatorDef != nil {
|
||||
outputIf(verbose, fmt.Sprintf("Withdrawal credentials:\t%#x", validatorDef.WithdrawalCredentials))
|
||||
|
||||
if validator != nil {
|
||||
outputIf(verbose, fmt.Sprintf("Withdrawal credentials: %#x", validator.WithdrawalCredentials))
|
||||
}
|
||||
|
||||
transition := time.Unix(int64(validatorInfo.TransitionTimestamp), 0)
|
||||
transitionPassed := int64(validatorInfo.TransitionTimestamp) <= time.Now().Unix()
|
||||
switch validatorInfo.Status {
|
||||
case ethpb.ValidatorStatus_DEPOSITED:
|
||||
if validatorInfo.TransitionTimestamp != 0 {
|
||||
fmt.Printf("Inclusion in chain:\t%s\n", transition)
|
||||
fmt.Printf("Inclusion in chain: %s\n", transition)
|
||||
}
|
||||
case ethpb.ValidatorStatus_PENDING:
|
||||
fmt.Printf("Activation:\t\t%s\n", transition)
|
||||
fmt.Printf("Activation: %s\n", transition)
|
||||
case ethpb.ValidatorStatus_EXITING, ethpb.ValidatorStatus_SLASHING:
|
||||
fmt.Printf("Attesting finishes:\t%s\n", transition)
|
||||
fmt.Printf("Attesting finishes: %s\n", transition)
|
||||
case ethpb.ValidatorStatus_EXITED:
|
||||
if transitionPassed {
|
||||
fmt.Printf("Funds withdrawable:\tNow\n")
|
||||
fmt.Printf("Funds withdrawable: Now\n")
|
||||
} else {
|
||||
fmt.Printf("Funds withdrawable:\t%s\n", transition)
|
||||
fmt.Printf("Funds withdrawable: %s\n", transition)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +122,87 @@ In quiet mode this will return 0 if the validator information can be obtained, o
|
||||
},
|
||||
}
|
||||
|
||||
// validatorInfoAccount obtains the account for the validator info command.
|
||||
func validatorInfoAccount() (e2wtypes.Account, error) {
|
||||
var account e2wtypes.Account
|
||||
if viper.GetString("account") != "" {
|
||||
wallet, err := openWallet()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to open wallet")
|
||||
}
|
||||
_, accountName, err := e2wallet.WalletAndAccountNames(viper.GetString("account"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain account name")
|
||||
}
|
||||
accountByNameProvider, isProvider := wallet.(e2wtypes.WalletAccountByNameProvider)
|
||||
if !isProvider {
|
||||
return nil, errors.New("failed to ask wallet for account by name")
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
account, err = accountByNameProvider.AccountByName(ctx, accountName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain account")
|
||||
}
|
||||
} else {
|
||||
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorInfoPubKey, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", validatorInfoPubKey))
|
||||
}
|
||||
account, err = util.NewScratchAccount(nil, pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", validatorInfoPubKey))
|
||||
}
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
// graphData returns data from the graph about number and amount of deposits
|
||||
func graphData(network string, validatorPubKey []byte) (uint64, uint64, error) {
|
||||
subgraph := fmt.Sprintf("attestantio/eth2deposits-%s", strings.ToLower(network))
|
||||
query := fmt.Sprintf(`{"query": "{deposits(where: {validatorPubKey:\"%#x\"}) { id amount withdrawalCredentials }}"}`, validatorPubKey)
|
||||
url := fmt.Sprintf("https://api.thegraph.com/subgraphs/name/%s", subgraph)
|
||||
graphResp, err := http.Post(url, "application/json", bytes.NewBufferString(query))
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, "failed to check if there is already a deposit for this validator")
|
||||
}
|
||||
defer graphResp.Body.Close()
|
||||
body, err := ioutil.ReadAll(graphResp.Body)
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, "bad information returned from existing deposit check")
|
||||
}
|
||||
|
||||
type graphDeposit struct {
|
||||
Index string `json:"index"`
|
||||
Amount string `json:"amount"`
|
||||
WithdrawalCredentials string `json:"withdrawalCredentials"`
|
||||
}
|
||||
type graphData struct {
|
||||
Deposits []*graphDeposit `json:"deposits,omitempty"`
|
||||
}
|
||||
type graphResponse struct {
|
||||
Data *graphData `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
var response graphResponse
|
||||
if err := json.Unmarshal(body, &response); err != nil {
|
||||
return 0, 0, errors.Wrap(err, "invalid data returned from existing deposit check")
|
||||
}
|
||||
deposits := uint64(0)
|
||||
totalDeposited := uint64(0)
|
||||
if response.Data != nil && len(response.Data.Deposits) > 0 {
|
||||
for _, deposit := range response.Data.Deposits {
|
||||
deposits++
|
||||
depositAmount, err := strconv.ParseUint(deposit.Amount, 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, errors.Wrap(err, fmt.Sprintf("invalid deposit amount from pre-existing deposit %s", deposit.Amount))
|
||||
}
|
||||
totalDeposited += depositAmount
|
||||
}
|
||||
}
|
||||
return deposits, totalDeposited, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
validatorCmd.AddCommand(validatorInfoCmd)
|
||||
validatorInfoCmd.Flags().StringVar(&validatorInfoPubKey, "pubkey", "", "Public key for which to obtain status")
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var ReleaseVersion = "local build"
|
||||
var ReleaseVersion = "local build from v1.5.1"
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
|
||||
@@ -17,6 +17,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -40,27 +43,66 @@ In quiet mode this will return 0 if the wallet holds any addresses, otherwise 1.
|
||||
wallet, err := openWallet()
|
||||
errCheck(err, "Failed to access wallet")
|
||||
|
||||
hasAccounts := false
|
||||
accounts := make([]e2wtypes.Account, 0, 128)
|
||||
for account := range wallet.Accounts(ctx) {
|
||||
hasAccounts = true
|
||||
accounts = append(accounts, account)
|
||||
}
|
||||
assert(len(accounts) > 0, "")
|
||||
|
||||
if _, isPathProvider := accounts[0].(e2wtypes.AccountPathProvider); isPathProvider {
|
||||
// Order accounts by their path components.
|
||||
sort.Slice(accounts, func(i int, j int) bool {
|
||||
iBits := strings.Split(accounts[i].(e2wtypes.AccountPathProvider).Path(), "/")
|
||||
jBits := strings.Split(accounts[j].(e2wtypes.AccountPathProvider).Path(), "/")
|
||||
for index := range iBits {
|
||||
if iBits[index] == "m" && jBits[index] == "m" {
|
||||
continue
|
||||
}
|
||||
if len(jBits) <= index {
|
||||
return false
|
||||
}
|
||||
iBit, err := strconv.ParseUint(iBits[index], 10, 64)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
jBit, err := strconv.ParseUint(jBits[index], 10, 64)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if iBit < jBit {
|
||||
return true
|
||||
}
|
||||
if iBit > jBit {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return len(jBits) > len(iBits)
|
||||
})
|
||||
} else {
|
||||
// Order accounts by their name.
|
||||
sort.Slice(accounts, func(i int, j int) bool {
|
||||
return strings.Compare(accounts[i].Name(), accounts[j].Name()) < 0
|
||||
})
|
||||
}
|
||||
|
||||
for _, account := range accounts {
|
||||
outputIf(!quiet, account.Name())
|
||||
if verbose {
|
||||
fmt.Printf(" UUID: %v\n", account.ID())
|
||||
pubKeyProvider, isProvider := account.(e2wtypes.AccountPublicKeyProvider)
|
||||
if isProvider {
|
||||
if pathProvider, isProvider := account.(e2wtypes.AccountPathProvider); isProvider {
|
||||
if pathProvider.Path() != "" {
|
||||
fmt.Printf("Path: %s\n", pathProvider.Path())
|
||||
}
|
||||
}
|
||||
if pubKeyProvider, isProvider := account.(e2wtypes.AccountPublicKeyProvider); isProvider {
|
||||
fmt.Printf(" Public key: %#x\n", pubKeyProvider.PublicKey().Marshal())
|
||||
}
|
||||
compositePubKeyProvider, isProvider := account.(e2wtypes.AccountCompositePublicKeyProvider)
|
||||
if isProvider {
|
||||
if compositePubKeyProvider, isProvider := account.(e2wtypes.AccountCompositePublicKeyProvider); isProvider {
|
||||
fmt.Printf(" Composite public key: %#x\n", compositePubKeyProvider.CompositePublicKey().Marshal())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasAccounts {
|
||||
os.Exit(_exitSuccess)
|
||||
}
|
||||
os.Exit(_exitFailure)
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,12 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
bip39 "github.com/tyler-smith/go-bip39"
|
||||
@@ -26,9 +30,6 @@ import (
|
||||
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
|
||||
)
|
||||
|
||||
var walletCreateType string
|
||||
var walletCreateSeed string
|
||||
|
||||
var walletCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a wallet",
|
||||
@@ -43,18 +44,22 @@ In quiet mode this will return 0 if the wallet is created successfully, otherwis
|
||||
|
||||
assert(viper.GetString("remote") == "", "wallet create not available with remote wallets")
|
||||
assert(viper.GetString("wallet") != "", "--wallet is required")
|
||||
assert(walletCreateType != "", "--type is required")
|
||||
assert(viper.GetString("type") != "", "--type is required")
|
||||
|
||||
var err error
|
||||
switch strings.ToLower(walletCreateType) {
|
||||
switch strings.ToLower(viper.GetString("type")) {
|
||||
case "non-deterministic", "nd":
|
||||
assert(walletCreateSeed == "", "--seed is not allowed with non-deterministic wallets")
|
||||
assert(viper.GetString("mnemonic") == "", "--mnemonic is not allowed with non-deterministic wallets")
|
||||
err = walletCreateND(ctx, viper.GetString("wallet"))
|
||||
case "hierarchical deterministic", "hd":
|
||||
if quiet {
|
||||
fmt.Printf("Creation of hierarchical deterministic wallets prints its mnemonic, so cannot be run with the --quiet flag")
|
||||
os.Exit(_exitFailure)
|
||||
}
|
||||
assert(getWalletPassphrase() != "", "--walletpassphrase is required for hierarchical deterministic wallets")
|
||||
err = walletCreateHD(ctx, viper.GetString("wallet"), getWalletPassphrase(), walletCreateSeed)
|
||||
err = walletCreateHD(ctx, viper.GetString("wallet"), getWalletPassphrase(), viper.GetString("mnemonic"))
|
||||
case "distributed":
|
||||
assert(walletCreateSeed == "", "--seed is not allowed with distributed wallets")
|
||||
assert(viper.GetString("mnemonic") == "", "--mnemonic is not allowed with distributed wallets")
|
||||
err = walletCreateDistributed(ctx, viper.GetString("wallet"))
|
||||
default:
|
||||
die("unknown wallet type")
|
||||
@@ -75,28 +80,66 @@ func walletCreateDistributed(ctx context.Context, name string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// walletCreateND creates a hierarchical-deterministic wallet.
|
||||
func walletCreateHD(ctx context.Context, name string, passphrase string, seedPhrase string) error {
|
||||
// walletCreateHD creates a hierarchical-deterministic wallet.
|
||||
func walletCreateHD(ctx context.Context, name string, passphrase string, mnemonic string) error {
|
||||
encryptor := keystorev4.New()
|
||||
if seedPhrase != "" {
|
||||
// Create wallet from a user-supplied seed.
|
||||
var seed []byte
|
||||
seed, err := bip39.MnemonicToByteArray(seedPhrase)
|
||||
errCheck(err, "Failed to decode seed")
|
||||
// Strip checksum; last byte.
|
||||
seed = seed[:len(seed)-1]
|
||||
assert(len(seed) == 32, "Seed must have 24 words")
|
||||
_, err = hd.CreateWalletFromSeed(ctx, name, []byte(passphrase), store, encryptor, seed)
|
||||
return err
|
||||
|
||||
printMnemonic := mnemonic == ""
|
||||
mnemonicPassphrase := ""
|
||||
|
||||
if mnemonic == "" {
|
||||
// Create a new random mnemonic.
|
||||
entropy := make([]byte, 32)
|
||||
_, err := rand.Read(entropy)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate entropy for wallet mnemonic")
|
||||
}
|
||||
mnemonic, err = bip39.NewMnemonic(entropy)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate wallet mnemonic")
|
||||
}
|
||||
} else {
|
||||
// We have an existing mnemonic. If there are more than 24 words we treat the additional characters as the passphrase.
|
||||
mnemonicParts := strings.Split(mnemonic, " ")
|
||||
if len(mnemonicParts) > 24 {
|
||||
mnemonic = strings.Join(mnemonicParts[:24], " ")
|
||||
mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ")
|
||||
}
|
||||
}
|
||||
// Create wallet with a random seed.
|
||||
_, err := hd.CreateWallet(ctx, name, []byte(passphrase), store, encryptor)
|
||||
|
||||
// Ensure the mnemonic is valid
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
return errors.New("mnemonic is not valid")
|
||||
}
|
||||
|
||||
// Create seed from mnemonic and passphrase.
|
||||
seed := bip39.NewSeed(mnemonic, mnemonicPassphrase)
|
||||
|
||||
_, err := hd.CreateWallet(ctx, name, []byte(passphrase), store, encryptor, seed)
|
||||
|
||||
if printMnemonic {
|
||||
fmt.Printf(`The following phrase is your mnemonic for this wallet:
|
||||
|
||||
%s
|
||||
|
||||
Anyone with access to this mnemonic can recreate the accounts in this wallet, so please store this mnemonic safely. More information about mnemonics can be found at https://support.mycrypto.com/general-knowledge/cryptography/how-do-mnemonic-phrases-work
|
||||
|
||||
Please note this mnemonic is not stored within the wallet, so cannot be retrieved or displayed again. As such, this mnemonic should be written down or otherwise protected before proceeding.
|
||||
`, mnemonic)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func init() {
|
||||
walletCmd.AddCommand(walletCreateCmd)
|
||||
walletFlags(walletCreateCmd)
|
||||
walletCreateCmd.Flags().StringVar(&walletCreateType, "type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)")
|
||||
walletCreateCmd.Flags().StringVar(&walletCreateSeed, "seed", "", "The 24-word seed phrase for a hierarchical deterministic wallet")
|
||||
walletCreateCmd.Flags().String("type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)")
|
||||
if err := viper.BindPFlag("type", walletCreateCmd.Flags().Lookup("type")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
walletCreateCmd.Flags().String("mnemonic", "", "The 24-word mnemonic for a hierarchical deterministic wallet")
|
||||
if err := viper.BindPFlag("mnemonic", walletCreateCmd.Flags().Lookup("mnemonic")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
// 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 (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
bip39 "github.com/tyler-smith/go-bip39"
|
||||
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
|
||||
)
|
||||
|
||||
var walletSeedCmd = &cobra.Command{
|
||||
Use: "seed",
|
||||
Short: "Display the seed of a wallet",
|
||||
Long: `Display the seed for an hierarchical deterministic wallet. For example:
|
||||
|
||||
ethdo wallet seed --wallet=primary
|
||||
|
||||
In quiet mode this will return 0 if the wallet is a hierarchical deterministic wallet, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
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(viper.GetString("wallet"))
|
||||
errCheck(err, "Failed to access wallet")
|
||||
_, ok := wallet.(e2wtypes.WalletKeyProvider)
|
||||
assert(ok, fmt.Sprintf("wallets of type %q do not have a seed", wallet.Type()))
|
||||
|
||||
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)
|
||||
errCheck(err, "Failed to generate seed mnemonic")
|
||||
// Re-read mnemonimc to ensure correctness.
|
||||
recalcSeed, err := bip39.MnemonicToByteArray(seedStr)
|
||||
// Drop checksum (last byte).
|
||||
errCheck(err, "Failed to recalculate seed")
|
||||
recalcSeed = recalcSeed[:len(recalcSeed)-1]
|
||||
outputIf(debug, fmt.Sprintf("Recalc seed is %#x", recalcSeed))
|
||||
errCheck(err, "Failed to recalculate seed mnemonic")
|
||||
assert(bytes.Equal(recalcSeed, seed), "Generated invalid mnemonic")
|
||||
|
||||
outputIf(!quiet, seedStr)
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
walletCmd.AddCommand(walletSeedCmd)
|
||||
walletFlags(walletSeedCmd)
|
||||
}
|
||||
@@ -2,19 +2,7 @@
|
||||
|
||||
## Installing ethdo
|
||||
|
||||
1. To install `ethdo`, issue the following command:
|
||||
|
||||
```sh
|
||||
GO111MODULE=on go get github.com/wealdtech/ethdo@latest
|
||||
```
|
||||
|
||||
2. Ensure `ethdo` is installed properly by issuing the command:
|
||||
|
||||
```sh
|
||||
ethdo version
|
||||
```
|
||||
|
||||
Ensure the output matches the most recent version listed on the repository's [release history](https://github.com/wealdtech/ethdo/releases/).
|
||||
1. To install `ethdo`, use the instructions on the [main page](https://github.com/wealdtech/ethdo).
|
||||
|
||||
## Typical validating setups
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Troubleshooting
|
||||
|
||||
## Compilation problems
|
||||
## Compilation problems on Linux
|
||||
|
||||
### gcc not found
|
||||
### cannot find -lstdc++
|
||||
|
||||
This is usually an error on linux systems. If you receive errors of this type your computer is missing some files to allow `ethdo` to build. To resolve this run the following command:
|
||||
If you receive errors of this type your computer is missing some files to allow `ethdo` to build. To resolve this, run the following command:
|
||||
|
||||
```sh
|
||||
sudo apt install build-essential libstdc++6
|
||||
@@ -13,6 +13,12 @@ sudo apt install build-essential libstdc++6
|
||||
|
||||
and then try to install `ethdo` again.
|
||||
|
||||
## Compilation problems on Windows
|
||||
|
||||
### gcc not found
|
||||
|
||||
If you receive errors of this type your computer is missing some files to allow `ethdo` to build. To resolve this install gcc by following the instructions at http://mingw-w64.org/doku.php
|
||||
|
||||
## ethdo not found after installing
|
||||
|
||||
This is usually due to an incorrectly set path. Go installs its binaries (such as `ethdo`) in a particular location. The defaults are:
|
||||
|
||||
@@ -31,7 +31,7 @@ Spending: 0x85dfc6dcee4c9da36f6473ec02fda283d6c920c641fc8e3a76113c5c227d4aeeb100
|
||||
- `wallet`: the name of the wallet to create
|
||||
- `type`: the type of wallet to create. This can be either "nd" for a non-deterministic wallet, where private keys are generated randomly, or "hd" for a hierarchical deterministic wallet, where private keys are generated from a seed and path as per [ERC-2333](https://github.com/CarlBeek/EIPs/blob/bls_path/EIPS/eip-2334.md) (defaults to "nd")
|
||||
- `walletpassphrase`: the passphrase for of the wallet. This is required for hierarchical deterministic wallets, to protect the seed
|
||||
- `seed`: for hierarchical deterministic wallets only, use a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to create the wallet. **Warning** The same seed can be imported in to multiple wallets, in which case they will generate the same keys. Please ensure that only a single wallet is active with any single seed phrase
|
||||
- `mnemonic`: for hierarchical deterministic wallets only, use a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to create the wallet, along with an additional "seed extension" phrase if required. **Warning** The same mnemonic can be used to create multiple wallets, in which case they will generate the same keys.
|
||||
|
||||
```sh
|
||||
$ ethdo wallet create --wallet="Personal wallet" --type="hd" --walletpassphrase="my wallet secret"
|
||||
@@ -103,17 +103,6 @@ Personal wallet
|
||||
|
||||
**N.B.** encrypted wallets will not show up in this list unless the correct passphrase for the store is supplied.
|
||||
|
||||
#### `seed`
|
||||
|
||||
`ethdo wallet seed` provides the seed for hierarchical deterministic wallets. Options include:
|
||||
- `wallet`: the name of the wallet
|
||||
- `walletpassphrase`: the passphrase for the wallet
|
||||
|
||||
```sh
|
||||
$ ethdo wallet seed --wallet="Personal wallet" --walletpassphrase="my wallet secret"
|
||||
decorate false mail domain gain later motion chair tank muffin smoke involve witness bean shell urge team solve share truly shadow decorate jeans hen
|
||||
```
|
||||
|
||||
### `account` commands
|
||||
|
||||
Account commands focus on information about local accounts, generally those used by Geth and Parity but also those from hardware devices.
|
||||
|
||||
25
go.mod
25
go.mod
@@ -4,20 +4,21 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.33.11 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
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/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
||||
github.com/pelletier/go-toml v1.8.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200709024211-e8095222f77b
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65
|
||||
github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.3.0 // indirect
|
||||
github.com/spf13/afero v1.3.2 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
@@ -29,17 +30,19 @@ require (
|
||||
github.com/wealdtech/go-ecodec v1.1.0
|
||||
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.2.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0
|
||||
github.com/wealdtech/go-eth2-wallet v1.12.0
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.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-eth2-wallet-types/v2 v2.6.0
|
||||
github.com/wealdtech/go-string2eth v1.1.0
|
||||
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200722002428-88e341933a54 // indirect
|
||||
google.golang.org/grpc v1.30.0
|
||||
gopkg.in/ini.v1 v1.57.0 // indirect
|
||||
)
|
||||
|
||||
31
go.sum
31
go.sum
@@ -29,6 +29,8 @@ 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/aws/aws-sdk-go v1.33.11 h1:A7b3mNKbh/0zrhnNN/KxWD0YZJw2RImnjFXWOquYKB4=
|
||||
github.com/aws/aws-sdk-go v1.33.11/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=
|
||||
@@ -155,6 +157,10 @@ github.com/herumi/bls-eth-go-binary v0.0.0-20200706085701-832d8c2c0f7d h1:P8yaFm
|
||||
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/herumi/bls-eth-go-binary v0.0.0-20200721081051-e31ced8c0204 h1:owpf19DI+vvpSOetnfE1NsLykSxZt8dSag7SDsJd8F0=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200721081051-e31ced8c0204/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4 h1:TfBVK1MJ9vhrMXWVHu5p/MlVHZTeCGgDAEu5RykVZeI=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200722032157-41fc56eba7b4/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=
|
||||
@@ -200,6 +206,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||
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=
|
||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
@@ -233,6 +241,8 @@ github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1oue
|
||||
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/ethereumapis v0.0.0-20200709024211-e8095222f77b h1:GjYix8Y4VpQhlsjA2ickr3HxjIns4bI36zOmC+lwaNw=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200709024211-e8095222f77b/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/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65 h1:hJfAWrlxx7SKpn4S/h2JGl2HHwA1a2wSS3HAzzZ0F+U=
|
||||
@@ -263,6 +273,8 @@ github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2
|
||||
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/afero v1.3.2 h1:GDarE4TJQI52kYSbSAmLiId1Elfj+xgSDqrUZxFhxlU=
|
||||
github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
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=
|
||||
@@ -320,18 +332,30 @@ github.com/wealdtech/go-eth2-wallet v1.10.2 h1:oUgi6Ih5fA9thhIipzXMSaLkiwDQXwT8q
|
||||
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 v1.12.0 h1:nrwI3jPhehUhJGlBtNv/UmIo/57llvuVZZavLnfdQHI=
|
||||
github.com/wealdtech/go-eth2-wallet v1.12.0/go.mod h1:ouV+YSMbzk2dyecmofm8jhaMKdSigdIPMSnSqmWEfW8=
|
||||
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-dirk v1.0.1 h1:YUE1QlJPun8b+xbz0JM71/3t1i9zp9KjcZdJvtJQL+E=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1/go.mod h1:5jK/aEAjYAVRBKKjYAvJWSmOWxiECs4asYXHwloNI+w=
|
||||
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-distributed v1.1.0 h1:OZjjuxcIYo+EhAfph7lYP1z+VeNs9ruOI32kqtYe1Jg=
|
||||
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0/go.mod h1:8r06Vpg/315/7Hl9CXq0ShQP8/cgUrBGzKKo6ywA4yQ=
|
||||
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-encryptor-keystorev4 v1.1.0 h1:CWb82xeNaZQt1Z829RyDALUy7UZbc6VOfTS+82jRdEQ=
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0/go.mod h1:JelKMM10UzDJNXdIcojMj6SCIsHC8NYn4c1S2FFk7OQ=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3/go.mod h1:STigKib4ZSefVvJjx88V2QpUGaoyUE1TiupcpsHpvKE=
|
||||
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-hd/v2 v2.3.0 h1:UORXUYRoUYgYF96Y+QiBq33OKQVtn/nEjnSoQbe1UOA=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.3.0/go.mod h1:Kc/8WcqMTczfH2xy5mDfCRd0NI/ca/j2jXmqJ7gz8yk=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2/go.mod h1:IssxoHII0ewO1VysMfCmdJP1D00tRhRhXIhhaEXIOVE=
|
||||
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-nd/v2 v2.3.0 h1:L1aPK9nc+8Ctcw+8I05vM6408weFc4a5RtLQDUeS0eE=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.0/go.mod h1:e2q2uuEdq5+B3GE7jk+Mi9oz9V5nPPKXcXRg1XYavsU=
|
||||
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-filesystem v1.16.0 h1:sWuSrAKdWSphiQCVcThozaFgTrwemXNXDI5CnFcP02s=
|
||||
@@ -345,6 +369,7 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI
|
||||
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-store-scratch v1.5.0/go.mod h1:RMIIV5/N8TgukTVzyumQd7AplpC440ZXDSk8VffeEwQ=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0/go.mod h1:XtXHbl4OV/XenQsvGmXbh+bVXaGS788oa30DB7kDInA=
|
||||
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=
|
||||
@@ -353,6 +378,8 @@ github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0 h1:PsCvp/lw7+h8Q0V3jL0f+/w2V
|
||||
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-eth2-wallet-types/v2 v2.6.0 h1:vBrH5icPPSeb14cdShA7/P2PBZOgZscJ2IhBlTIaFrA=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.6.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=
|
||||
@@ -449,6 +476,8 @@ golang.org/x/sys v0.0.0-20200620081246-981b61492c35 h1:wb/9mP8eUAmHfkM8RmpeLq6nU
|
||||
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/sys v0.0.0-20200722175500-76b94024e4b6 h1:X9xIZ1YU8bLZA3l6gqDUHSFiD0GFI9S548h6C8nDtOY=
|
||||
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -509,6 +538,8 @@ google.golang.org/genproto v0.0.0-20200711021454-869866162049 h1:YFTFpQhgvrLrmxt
|
||||
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/genproto v0.0.0-20200722002428-88e341933a54 h1:ASrBgpl9XvkNTP0m39/j18mid7aoF21npu2ioIBxYnY=
|
||||
google.golang.org/genproto v0.0.0-20200722002428-88e341933a54/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/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
||||
15
grpc/node.go
15
grpc/node.go
@@ -55,6 +55,21 @@ func FetchGenesisValidatorsRoot(conn *grpc.ClientConn) ([]byte, error) {
|
||||
return res.GetGenesisValidatorsRoot(), nil
|
||||
}
|
||||
|
||||
// FetchDepositContractAddress fetches the address of the deposit contract.
|
||||
func FetchDepositContractAddress(conn *grpc.ClientConn) ([]byte, error) {
|
||||
if conn == nil {
|
||||
return nil, errors.New("no connection to beacon node")
|
||||
}
|
||||
client := ethpb.NewNodeClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
res, err := client.GetGenesis(ctx, &types.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.DepositContractAddress, nil
|
||||
}
|
||||
|
||||
// FetchVersion fetches the version and metadata from the server.
|
||||
func FetchVersion(conn *grpc.ClientConn) (string, string, error) {
|
||||
if conn == nil {
|
||||
|
||||
Reference in New Issue
Block a user