mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 14:37:57 -05:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c3237cd0d | ||
|
|
7215e04a69 | ||
|
|
71e9c0471b | ||
|
|
1a6f402fb8 | ||
|
|
b9297c2506 | ||
|
|
1032789706 | ||
|
|
51e289b72b | ||
|
|
a75a350cef | ||
|
|
aa34e61a80 | ||
|
|
3f33f04be2 | ||
|
|
5733b5b638 | ||
|
|
e1ce81c81d | ||
|
|
bd67ba0307 | ||
|
|
12bb5a7ab8 | ||
|
|
d57dbbf104 | ||
|
|
6482b4add6 | ||
|
|
b672e83470 |
@@ -5,7 +5,7 @@
|
||||
|
||||
A command-line tool for managing common tasks in Ethereum 2.
|
||||
|
||||
** Please note that this library uses standards that are not yet final, and as such may result in changes that alter public and private keys. Do not use this library for production use just yet **
|
||||
**Please note that this tool and its underlying libraries have not yet undergone a security audit; use at your own risk.**
|
||||
|
||||
## Table of Contents
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ In quiet mode this will return 0 if the account is imported successfully, otherw
|
||||
errCheck(err, "Failed to unlock wallet")
|
||||
|
||||
_, accountName, err := walletAndAccountNamesFromPath(rootAccount)
|
||||
errCheck(err, "Failed to obtain accout name")
|
||||
errCheck(err, "Failed to obtain account name")
|
||||
|
||||
account, err := w.(types.WalletAccountImporter).ImportAccount(accountName, key, []byte(rootAccountPassphrase))
|
||||
errCheck(err, "Failed to create account")
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
|
||||
util "github.com/wealdtech/go-eth2-util"
|
||||
)
|
||||
|
||||
var accountInfoCmd = &cobra.Command{
|
||||
@@ -33,6 +34,7 @@ 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")
|
||||
|
||||
var withdrawalCredentials []byte
|
||||
if remote {
|
||||
listerClient := pb.NewListerClient(remoteGRPCConn)
|
||||
listAccountsReq := &pb.ListAccountsRequest{
|
||||
@@ -44,13 +46,18 @@ In quiet mode this will return 0 if the account exists, otherwise 1.`,
|
||||
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: %#048x\n", resp.Accounts[0].PublicKey)
|
||||
|
||||
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: %#048x", account.PublicKey().Marshal()))
|
||||
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()))
|
||||
}
|
||||
|
||||
|
||||
265
cmd/blockinfo.go
265
cmd/blockinfo.go
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -30,6 +31,7 @@ import (
|
||||
)
|
||||
|
||||
var blockInfoSlot int64
|
||||
var blockInfoStream bool
|
||||
|
||||
var blockInfoCmd = &cobra.Command{
|
||||
Use: "info",
|
||||
@@ -43,139 +45,157 @@ In quiet mode this will return 0 if the block information is present and not ski
|
||||
err := connect()
|
||||
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain block")
|
||||
|
||||
assert(blockInfoSlot != 0, "--slot is required")
|
||||
if blockInfoStream {
|
||||
stream, err := grpc.StreamBlocks(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain block stream")
|
||||
for {
|
||||
signedBlock, err := stream.Recv()
|
||||
errCheck(err, "Failed to obtain block")
|
||||
if signedBlock != nil {
|
||||
fmt.Println("")
|
||||
outputBlock(signedBlock)
|
||||
}
|
||||
}
|
||||
|
||||
var slot uint64
|
||||
if blockInfoSlot < 0 {
|
||||
// TODO 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)
|
||||
}
|
||||
block := signedBlock.Block
|
||||
body := block.Body
|
||||
|
||||
// General info.
|
||||
bodyRoot, err := ssz.HashTreeRoot(block)
|
||||
errCheck(err, "Failed to calculate block body root")
|
||||
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))
|
||||
if len(body.Graffiti) > 0 && hex.EncodeToString(body.Graffiti) != "0000000000000000000000000000000000000000000000000000000000000000" {
|
||||
if utf8.Valid(body.Graffiti) {
|
||||
fmt.Printf("Graffiti: %s\n", string(body.Graffiti))
|
||||
assert(blockInfoSlot != 0, "--slot is required")
|
||||
var slot uint64
|
||||
if blockInfoSlot < 0 {
|
||||
slot, err = grpc.FetchLatestFilledSlot(eth2GRPCConn)
|
||||
} else {
|
||||
fmt.Printf("Graffiti: %#x\n", body.Graffiti)
|
||||
slot = uint64(blockInfoSlot)
|
||||
}
|
||||
}
|
||||
assert(slot > 0, "slot must be greater than 0")
|
||||
|
||||
// Eth1 data.
|
||||
eth1Data := body.Eth1Data
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 deposit count: %d", eth1Data.DepositCount))
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 deposit root: %#x", eth1Data.DepositRoot))
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 block hash: %#x", eth1Data.BlockHash))
|
||||
|
||||
// Attestations.
|
||||
fmt.Printf("Attestations: %d\n", len(body.Attestations))
|
||||
if verbose {
|
||||
for i, att := range body.Attestations {
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
|
||||
fmt.Printf("\t\tCommittee index: %d\n", att.Data.CommitteeIndex)
|
||||
fmt.Printf("\t\tAttesters: %d/%d\n", att.AggregationBits.Count(), att.AggregationBits.Len())
|
||||
fmt.Printf("\t\tAggregation bits: %s\n", bitsToString(att.AggregationBits))
|
||||
fmt.Printf("\t\tSlot: %d\n", att.Data.Slot)
|
||||
fmt.Printf("\t\tBeacon block root: %#x\n", att.Data.BeaconBlockRoot)
|
||||
fmt.Printf("\t\tSource epoch: %d\n", att.Data.Source.Epoch)
|
||||
fmt.Printf("\t\tSource root: %#x\n", att.Data.Source.Root)
|
||||
fmt.Printf("\t\tTarget epoch: %d\n", att.Data.Target.Epoch)
|
||||
fmt.Printf("\t\tTarget root: %#x\n", att.Data.Target.Root)
|
||||
}
|
||||
}
|
||||
|
||||
// Attester slashings.
|
||||
fmt.Printf("Attester slashings: %d\n", len(body.AttesterSlashings))
|
||||
if verbose {
|
||||
for i, slashing := range body.AttesterSlashings {
|
||||
// Say what was slashed.
|
||||
att1 := slashing.Attestation_1
|
||||
outputIf(debug, fmt.Sprintf("Attestation 1 attesting indices are %v", att1.AttestingIndices))
|
||||
att2 := slashing.Attestation_2
|
||||
outputIf(debug, fmt.Sprintf("Attestation 2 attesting indices are %v", att2.AttestingIndices))
|
||||
slashedIndices := intersection(att1.AttestingIndices, att2.AttestingIndices)
|
||||
if len(slashedIndices) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
|
||||
fmt.Println("\t\tSlashed validators:")
|
||||
for _, slashedIndex := range slashedIndices {
|
||||
validator, err := grpc.FetchValidatorByIndex(eth2GRPCConn, slashedIndex)
|
||||
errCheck(err, "Failed to obtain validator information")
|
||||
fmt.Printf("\t\t\t%#x (%d)\n", validator.PublicKey, slashedIndex)
|
||||
}
|
||||
|
||||
// Say what caused the slashing.
|
||||
if att1.Data.Target.Epoch == att2.Data.Target.Epoch {
|
||||
fmt.Printf("\t\tDouble voted for same target epoch (%d):\n", att1.Data.Target.Epoch)
|
||||
if !bytes.Equal(att1.Data.Target.Root, att2.Data.Target.Root) {
|
||||
fmt.Printf("\t\t\tAttestation 1 target epoch root: %#x\n", att1.Data.Target.Root)
|
||||
fmt.Printf("\t\t\tAttestation 2target epoch root: %#x\n", att2.Data.Target.Root)
|
||||
}
|
||||
if !bytes.Equal(att1.Data.BeaconBlockRoot, att2.Data.BeaconBlockRoot) {
|
||||
fmt.Printf("\t\t\tAttestation 1 beacon block root: %#x\n", att1.Data.BeaconBlockRoot)
|
||||
fmt.Printf("\t\t\tAttestation 2 beacon block root: %#x\n", att2.Data.BeaconBlockRoot)
|
||||
}
|
||||
} else {
|
||||
if att1.Data.Source.Epoch < att2.Data.Source.Epoch &&
|
||||
att1.Data.Target.Epoch > att2.Data.Target.Epoch {
|
||||
fmt.Printf("\t\tSurround voted:\n")
|
||||
fmt.Printf("\t\t\tAttestation 1 vote: %d->%d\n", att1.Data.Source.Epoch, att1.Data.Target.Epoch)
|
||||
fmt.Printf("\t\t\tAttestation 2 vote: %d->%d\n", att2.Data.Source.Epoch, att2.Data.Target.Epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Proposer slashings once proposer slashings exist.
|
||||
|
||||
// Deposits.
|
||||
fmt.Printf("Deposits: %d\n", len(body.Deposits))
|
||||
if verbose {
|
||||
for i, deposit := range body.Deposits {
|
||||
data := deposit.Data
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
fmt.Printf("\t\tPublic key: %#x\n", data.PublicKey)
|
||||
fmt.Printf("\t\tAmount: %s\n", string2eth.GWeiToString(data.Amount, true))
|
||||
fmt.Printf("\t\tWithdrawal credentials: %#x\n", data.WithdrawalCredentials)
|
||||
fmt.Printf("\t\tSignature: %#x\n", data.Signature)
|
||||
}
|
||||
}
|
||||
|
||||
// Voluntary exits.
|
||||
fmt.Printf("Voluntary exits: %d\n", len(body.VoluntaryExits))
|
||||
if verbose {
|
||||
for i, voluntaryExit := range body.VoluntaryExits {
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
validator, err := grpc.FetchValidatorByIndex(eth2GRPCConn, voluntaryExit.Exit.ValidatorIndex)
|
||||
errCheck(err, "Failed to obtain validator information")
|
||||
fmt.Printf("\t\tValidator: %#x (%d)\n", validator.PublicKey, voluntaryExit.Exit.ValidatorIndex)
|
||||
fmt.Printf("\t\tEpoch: %d\n", voluntaryExit.Exit.Epoch)
|
||||
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)
|
||||
}
|
||||
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
}
|
||||
|
||||
func outputBlock(signedBlock *ethpb.SignedBeaconBlock) {
|
||||
block := signedBlock.Block
|
||||
body := block.Body
|
||||
|
||||
// General info.
|
||||
bodyRoot, err := ssz.HashTreeRoot(block)
|
||||
errCheck(err, "Failed to calculate block body root")
|
||||
fmt.Printf("Slot: %d\n", block.Slot)
|
||||
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))
|
||||
if len(body.Graffiti) > 0 && hex.EncodeToString(body.Graffiti) != "0000000000000000000000000000000000000000000000000000000000000000" {
|
||||
if utf8.Valid(body.Graffiti) {
|
||||
fmt.Printf("Graffiti: %s\n", string(body.Graffiti))
|
||||
} else {
|
||||
fmt.Printf("Graffiti: %#x\n", body.Graffiti)
|
||||
}
|
||||
}
|
||||
|
||||
// Eth1 data.
|
||||
eth1Data := body.Eth1Data
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 deposit count: %d", eth1Data.DepositCount))
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 deposit root: %#x", eth1Data.DepositRoot))
|
||||
outputIf(verbose, fmt.Sprintf("Ethereum 1 block hash: %#x", eth1Data.BlockHash))
|
||||
|
||||
// Attestations.
|
||||
fmt.Printf("Attestations: %d\n", len(body.Attestations))
|
||||
if verbose {
|
||||
for i, att := range body.Attestations {
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
|
||||
fmt.Printf("\t\tCommittee index: %d\n", att.Data.CommitteeIndex)
|
||||
fmt.Printf("\t\tAttesters: %d/%d\n", att.AggregationBits.Count(), att.AggregationBits.Len())
|
||||
fmt.Printf("\t\tAggregation bits: %s\n", bitsToString(att.AggregationBits))
|
||||
fmt.Printf("\t\tSlot: %d\n", att.Data.Slot)
|
||||
fmt.Printf("\t\tBeacon block root: %#x\n", att.Data.BeaconBlockRoot)
|
||||
fmt.Printf("\t\tSource epoch: %d\n", att.Data.Source.Epoch)
|
||||
fmt.Printf("\t\tSource root: %#x\n", att.Data.Source.Root)
|
||||
fmt.Printf("\t\tTarget epoch: %d\n", att.Data.Target.Epoch)
|
||||
fmt.Printf("\t\tTarget root: %#x\n", att.Data.Target.Root)
|
||||
}
|
||||
}
|
||||
|
||||
// Attester slashings.
|
||||
fmt.Printf("Attester slashings: %d\n", len(body.AttesterSlashings))
|
||||
if verbose {
|
||||
for i, slashing := range body.AttesterSlashings {
|
||||
// Say what was slashed.
|
||||
att1 := slashing.Attestation_1
|
||||
outputIf(debug, fmt.Sprintf("Attestation 1 attesting indices are %v", att1.AttestingIndices))
|
||||
att2 := slashing.Attestation_2
|
||||
outputIf(debug, fmt.Sprintf("Attestation 2 attesting indices are %v", att2.AttestingIndices))
|
||||
slashedIndices := intersection(att1.AttestingIndices, att2.AttestingIndices)
|
||||
if len(slashedIndices) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
|
||||
fmt.Println("\t\tSlashed validators:")
|
||||
for _, slashedIndex := range slashedIndices {
|
||||
validator, err := grpc.FetchValidatorByIndex(eth2GRPCConn, slashedIndex)
|
||||
errCheck(err, "Failed to obtain validator information")
|
||||
fmt.Printf("\t\t\t%#x (%d)\n", validator.PublicKey, slashedIndex)
|
||||
}
|
||||
|
||||
// Say what caused the slashing.
|
||||
if att1.Data.Target.Epoch == att2.Data.Target.Epoch {
|
||||
fmt.Printf("\t\tDouble voted for same target epoch (%d):\n", att1.Data.Target.Epoch)
|
||||
if !bytes.Equal(att1.Data.Target.Root, att2.Data.Target.Root) {
|
||||
fmt.Printf("\t\t\tAttestation 1 target epoch root: %#x\n", att1.Data.Target.Root)
|
||||
fmt.Printf("\t\t\tAttestation 2target epoch root: %#x\n", att2.Data.Target.Root)
|
||||
}
|
||||
if !bytes.Equal(att1.Data.BeaconBlockRoot, att2.Data.BeaconBlockRoot) {
|
||||
fmt.Printf("\t\t\tAttestation 1 beacon block root: %#x\n", att1.Data.BeaconBlockRoot)
|
||||
fmt.Printf("\t\t\tAttestation 2 beacon block root: %#x\n", att2.Data.BeaconBlockRoot)
|
||||
}
|
||||
} else {
|
||||
if att1.Data.Source.Epoch < att2.Data.Source.Epoch &&
|
||||
att1.Data.Target.Epoch > att2.Data.Target.Epoch {
|
||||
fmt.Printf("\t\tSurround voted:\n")
|
||||
fmt.Printf("\t\t\tAttestation 1 vote: %d->%d\n", att1.Data.Source.Epoch, att1.Data.Target.Epoch)
|
||||
fmt.Printf("\t\t\tAttestation 2 vote: %d->%d\n", att2.Data.Source.Epoch, att2.Data.Target.Epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Proposer slashings once proposer slashings exist.
|
||||
|
||||
// Deposits.
|
||||
fmt.Printf("Deposits: %d\n", len(body.Deposits))
|
||||
if verbose {
|
||||
for i, deposit := range body.Deposits {
|
||||
data := deposit.Data
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
fmt.Printf("\t\tPublic key: %#x\n", data.PublicKey)
|
||||
fmt.Printf("\t\tAmount: %s\n", string2eth.GWeiToString(data.Amount, true))
|
||||
fmt.Printf("\t\tWithdrawal credentials: %#x\n", data.WithdrawalCredentials)
|
||||
fmt.Printf("\t\tSignature: %#x\n", data.Signature)
|
||||
}
|
||||
}
|
||||
|
||||
// Voluntary exits.
|
||||
fmt.Printf("Voluntary exits: %d\n", len(body.VoluntaryExits))
|
||||
if verbose {
|
||||
for i, voluntaryExit := range body.VoluntaryExits {
|
||||
fmt.Printf("\t%d:\n", i)
|
||||
validator, err := grpc.FetchValidatorByIndex(eth2GRPCConn, voluntaryExit.Exit.ValidatorIndex)
|
||||
errCheck(err, "Failed to obtain validator information")
|
||||
fmt.Printf("\t\tValidator: %#x (%d)\n", validator.PublicKey, voluntaryExit.Exit.ValidatorIndex)
|
||||
fmt.Printf("\t\tEpoch: %d\n", voluntaryExit.Exit.Epoch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// intersection returns a list of items common between the two sets.
|
||||
func intersection(set1 []uint64, set2 []uint64) []uint64 {
|
||||
sort.Slice(set1, func(i, j int) bool { return set1[i] < set1[j] })
|
||||
@@ -220,5 +240,6 @@ func bitsToString(input bitfield.Bitlist) string {
|
||||
func init() {
|
||||
blockCmd.AddCommand(blockInfoCmd)
|
||||
blockFlags(blockInfoCmd)
|
||||
blockInfoCmd.Flags().Int64Var(&blockInfoSlot, "slot", -1, "the default slot")
|
||||
blockInfoCmd.Flags().Int64Var(&blockInfoSlot, "slot", -1, "the latest slot with a block")
|
||||
blockInfoCmd.Flags().BoolVar(&blockInfoStream, "stream", false, "continually stream blocks as they arrive")
|
||||
}
|
||||
|
||||
32
cmd/deposit.go
Normal file
32
cmd/deposit.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2019 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// depositCmd represents the deposit command
|
||||
var depositCmd = &cobra.Command{
|
||||
Use: "deposit",
|
||||
Short: "Manage Ethereum 2 deposits",
|
||||
Long: `Manage Ethereum 2 deposits.`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(depositCmd)
|
||||
}
|
||||
|
||||
func depositFlags(cmd *cobra.Command) {
|
||||
}
|
||||
234
cmd/depositverify.go
Normal file
234
cmd/depositverify.go
Normal file
@@ -0,0 +1,234 @@
|
||||
// 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"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
e2types "github.com/wealdtech/go-eth2-types/v2"
|
||||
util "github.com/wealdtech/go-eth2-util"
|
||||
string2eth "github.com/wealdtech/go-string2eth"
|
||||
)
|
||||
|
||||
type depositData struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
PublicKey string `json:"pubkey"`
|
||||
WithdrawalCredentials string `json:"withdrawal_credentials"`
|
||||
Signature string `json:"signature"`
|
||||
DepositDataRoot string `json:"deposit_data_root"`
|
||||
Value uint64 `json:"value"`
|
||||
Version uint64 `json:"version"`
|
||||
}
|
||||
|
||||
var depositVerifyData string
|
||||
var depositVerifyWithdrawalPubKey string
|
||||
var depositVerifyValidatorPubKey string
|
||||
var depositVerifyDepositValue string
|
||||
|
||||
var depositVerifyCmd = &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Verify deposit data matches requirements",
|
||||
Long: `Verify deposit data matches requirements. For example:
|
||||
|
||||
ethdo deposit verify --data=depositdata.json --withdrawalaccount=primary/current --value="32 Ether"
|
||||
|
||||
The information generated can be passed to ethereal to create a deposit from the Ethereum 1 chain.
|
||||
|
||||
In quiet mode this will return 0 if the the data can be generated correctly, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
assert(depositVerifyData != "", "--data is required")
|
||||
deposits, err := depositDataFromJSON(depositVerifyData)
|
||||
errCheck(err, "Failed to fetch deposit data")
|
||||
|
||||
withdrawalCredentials := ""
|
||||
if depositVerifyWithdrawalPubKey != "" {
|
||||
withdrawalPubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(depositVerifyWithdrawalPubKey, "0x"))
|
||||
errCheck(err, "Invalid withdrawal public key")
|
||||
assert(len(withdrawalPubKeyBytes) == 48, "Public key should be 48 bytes")
|
||||
withdrawalPubKey, err := e2types.BLSPublicKeyFromBytes(withdrawalPubKeyBytes)
|
||||
errCheck(err, "Value supplied with --withdrawalpubkey is not a valid public key")
|
||||
withdrawalBytes := util.SHA256(withdrawalPubKey.Marshal())
|
||||
withdrawalBytes[0] = 0 // BLS_WITHDRAWAL_PREFIX
|
||||
withdrawalCredentials = fmt.Sprintf("%x", withdrawalBytes)
|
||||
}
|
||||
outputIf(debug, fmt.Sprintf("Withdrawal credentials are %s", withdrawalCredentials))
|
||||
|
||||
depositValue := uint64(0)
|
||||
if depositVerifyDepositValue != "" {
|
||||
depositValue, err = string2eth.StringToGWei(depositVerifyDepositValue)
|
||||
errCheck(err, "Invalid value")
|
||||
// This is hard-coded, to allow deposit data to be generated without a connection to the beacon node.
|
||||
assert(depositValue >= 1000000000, "deposit value must be at least 1 Ether") // MIN_DEPOSIT_AMOUNT
|
||||
}
|
||||
|
||||
validatorPubKeys := make(map[string]bool)
|
||||
if depositVerifyValidatorPubKey != "" {
|
||||
validatorPubKeys, err = validatorPubKeysFromInput(depositVerifyValidatorPubKey)
|
||||
errCheck(err, "Failed to obtain validator public key(s))")
|
||||
}
|
||||
|
||||
failures := false
|
||||
for i, deposit := range deposits {
|
||||
if withdrawalCredentials != "" {
|
||||
if deposit.WithdrawalCredentials != withdrawalCredentials {
|
||||
outputIf(!quiet, fmt.Sprintf("Invalid withdrawal credentials for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
}
|
||||
if depositValue != 0 {
|
||||
if deposit.Value != depositValue {
|
||||
outputIf(!quiet, fmt.Sprintf("Invalid deposit value for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
}
|
||||
if len(validatorPubKeys) != 0 {
|
||||
if _, exists := validatorPubKeys[deposit.PublicKey]; !exists {
|
||||
outputIf(!quiet, fmt.Sprintf("Unknown validator public key for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
}
|
||||
outputIf(verbose, fmt.Sprintf("Deposit %d verified", i))
|
||||
}
|
||||
|
||||
if failures {
|
||||
os.Exit(_exitFailure)
|
||||
}
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
}
|
||||
|
||||
func validatorPubKeysFromInput(input string) (map[string]bool, error) {
|
||||
pubKeys := make(map[string]bool)
|
||||
var err error
|
||||
var data []byte
|
||||
// Input could be a public key or a path to public keys.
|
||||
if strings.HasPrefix(input, "0x") {
|
||||
// Looks like a public key.
|
||||
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "public key is not a hex string")
|
||||
}
|
||||
if len(pubKeyBytes) != 48 {
|
||||
return nil, errors.New("public key should be 48 bytes")
|
||||
}
|
||||
pubKey, err := e2types.BLSPublicKeyFromBytes(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "invalid public key")
|
||||
}
|
||||
pubKeys[fmt.Sprintf("%x", pubKey.Marshal())] = true
|
||||
} else {
|
||||
// Assume it's a path to a file of public keys.
|
||||
data, err = ioutil.ReadFile(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find public key file")
|
||||
}
|
||||
lines := bytes.Split(bytes.Replace(data, []byte("\r\n"), []byte("\n"), -1), []byte("\n"))
|
||||
if len(lines) == 0 {
|
||||
return nil, errors.New("file has no public keys")
|
||||
}
|
||||
for _, line := range lines {
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(string(line), "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "public key is not a hex string")
|
||||
}
|
||||
if len(pubKeyBytes) != 48 {
|
||||
return nil, errors.New("public key should be 48 bytes")
|
||||
}
|
||||
pubKey, err := e2types.BLSPublicKeyFromBytes(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "invalid public key")
|
||||
}
|
||||
pubKeys[fmt.Sprintf("%x", pubKey.Marshal())] = true
|
||||
}
|
||||
}
|
||||
|
||||
return pubKeys, nil
|
||||
}
|
||||
|
||||
func depositDataFromJSON(input string) ([]*depositData, error) {
|
||||
var err error
|
||||
var data []byte
|
||||
// Input could be JSON or a path to JSON
|
||||
switch {
|
||||
case strings.HasPrefix(input, "{"):
|
||||
// Looks like JSON
|
||||
data = []byte("[" + input + "]")
|
||||
case strings.HasPrefix(input, "["):
|
||||
// Looks like JSON array
|
||||
data = []byte(input)
|
||||
default:
|
||||
// Assume it's a path to JSON
|
||||
data, err = ioutil.ReadFile(input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find deposit data file")
|
||||
}
|
||||
if data[0] == '{' {
|
||||
data = []byte("[" + string(data) + "]")
|
||||
}
|
||||
}
|
||||
var depositData []*depositData
|
||||
err = json.Unmarshal(data, &depositData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "data is not valid JSON")
|
||||
}
|
||||
if len(depositData) == 0 {
|
||||
return nil, errors.New("no deposits supplied")
|
||||
}
|
||||
minVersion := depositData[0].Version
|
||||
maxVersion := depositData[0].Version
|
||||
for i := range depositData {
|
||||
if depositData[i].PublicKey == "" {
|
||||
return nil, fmt.Errorf("no public key for deposit %d", i)
|
||||
}
|
||||
if depositData[i].DepositDataRoot == "" {
|
||||
return nil, fmt.Errorf("no data root for deposit %d", i)
|
||||
}
|
||||
if depositData[i].Signature == "" {
|
||||
return nil, fmt.Errorf("no signature for deposit %d", i)
|
||||
}
|
||||
if depositData[i].WithdrawalCredentials == "" {
|
||||
return nil, fmt.Errorf("no withdrawal credentials for deposit %d", i)
|
||||
}
|
||||
if depositData[i].Value < 1000000000 {
|
||||
return nil, fmt.Errorf("Deposit amount too small for deposit %d", i)
|
||||
}
|
||||
if depositData[i].Version > maxVersion {
|
||||
maxVersion = depositData[i].Version
|
||||
}
|
||||
if depositData[i].Version < minVersion {
|
||||
minVersion = depositData[i].Version
|
||||
}
|
||||
}
|
||||
return depositData, nil
|
||||
}
|
||||
func init() {
|
||||
depositCmd.AddCommand(depositVerifyCmd)
|
||||
depositFlags(depositVerifyCmd)
|
||||
depositVerifyCmd.Flags().StringVar(&depositVerifyData, "data", "", "JSON data, or path to JSON data")
|
||||
depositVerifyCmd.Flags().StringVar(&depositVerifyWithdrawalPubKey, "withdrawalpubkey", "", "Public key of the account to which the validator funds will be withdrawn")
|
||||
depositVerifyCmd.Flags().StringVar(&depositVerifyDepositValue, "depositvalue", "", "Value of the amount to be deposited")
|
||||
depositVerifyCmd.Flags().StringVar(&depositVerifyValidatorPubKey, "validatorpubkey", "", "Public key(s) of the account(s) that will be carrying out validation")
|
||||
}
|
||||
35
cmd/root.go
35
cmd/root.go
@@ -45,10 +45,6 @@ var quiet bool
|
||||
var verbose bool
|
||||
var debug bool
|
||||
|
||||
// For transaction commands.
|
||||
var wait bool
|
||||
var generate bool
|
||||
|
||||
// Root variables, present for all commands.
|
||||
var rootStore string
|
||||
var rootAccount string
|
||||
@@ -57,6 +53,9 @@ var rootStorePassphrase string
|
||||
var rootWalletPassphrase string
|
||||
var rootAccountPassphrase string
|
||||
|
||||
// Store for wallet actions.
|
||||
var store wtypes.Store
|
||||
|
||||
// Remote connection.
|
||||
var remote bool
|
||||
var remoteAddr string
|
||||
@@ -98,33 +97,15 @@ func persistentPreRun(cmd *cobra.Command, args []string) {
|
||||
rootWalletPassphrase = viper.GetString("walletpassphrase")
|
||||
rootAccountPassphrase = viper.GetString("passphrase")
|
||||
|
||||
// ...lots of commands have transaction-related flags (e.g.) 'wait'
|
||||
// as options but we want to bind them to this particular command and
|
||||
// this is the first chance we get
|
||||
if cmd.Flags().Lookup("wait") != nil {
|
||||
err := viper.BindPFlag("wait", cmd.Flags().Lookup("wait"))
|
||||
errCheck(err, "Failed to set wait option")
|
||||
}
|
||||
wait = viper.GetBool("wait")
|
||||
if cmd.Flags().Lookup("generate") != nil {
|
||||
err := viper.BindPFlag("generate", cmd.Flags().Lookup("generate"))
|
||||
errCheck(err, "Failed to set generate option")
|
||||
}
|
||||
generate = viper.GetBool("generate")
|
||||
|
||||
if quiet && verbose {
|
||||
die("Cannot supply both quiet and verbose flags")
|
||||
fmt.Println("Cannot supply both quiet and verbose flags")
|
||||
}
|
||||
if quiet && debug {
|
||||
die("Cannot supply both quiet and debug flags")
|
||||
}
|
||||
if generate && wait {
|
||||
die("Cannot supply both generate and wait flags")
|
||||
fmt.Println("Cannot supply both quiet and debug flags")
|
||||
}
|
||||
|
||||
if viper.GetString("remote") == "" {
|
||||
// Set up our wallet store
|
||||
var store wtypes.Store
|
||||
switch rootStore {
|
||||
case "s3":
|
||||
assert(rootBaseDir == "", "--basedir does not apply for the s3 store")
|
||||
@@ -413,12 +394,6 @@ func sign(account wtypes.Account, data []byte) (e2types.Signature, error) {
|
||||
return account.Sign(data)
|
||||
}
|
||||
|
||||
// addTransactionFlags adds flags used in all transactions.
|
||||
func addTransactionFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool("generate", false, "Do not send the transaction; generate and output as a hex string only")
|
||||
cmd.Flags().Bool("wait", false, "wait for the transaction to be mined before returning")
|
||||
}
|
||||
|
||||
// connect connects to an Ethereum 2 endpoint.
|
||||
func connect() error {
|
||||
connection := ""
|
||||
|
||||
@@ -112,7 +112,10 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
err := connect()
|
||||
errCheck(err, "Failed to connect to beacon node")
|
||||
config, err := grpc.FetchChainConfig(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain chain configuration")
|
||||
if err != nil {
|
||||
outputIf(!quiet, "Could not connect to beacon node; supply a connection with --connection or provide a fork version with --forkversion to generate a deposit")
|
||||
os.Exit(_exitFailure)
|
||||
}
|
||||
genesisForkVersion, exists := config["GenesisForkVersion"]
|
||||
assert(exists, "Failed to obtain genesis fork version")
|
||||
forkVersion = genesisForkVersion.([]byte)
|
||||
|
||||
@@ -176,7 +176,6 @@ func init() {
|
||||
validatorExitCmd.Flags().StringVar(&validatorExitKey, "key", "", "Private key if account not known by ethdo")
|
||||
validatorExitCmd.Flags().BoolVar(&validatorExitJSONOutput, "json-output", false, "Print JSON transaction; do not broadcast to network")
|
||||
validatorExitCmd.Flags().StringVar(&validatorExitJSON, "json", "", "Use JSON as created by --json-output to exit")
|
||||
addTransactionFlags(validatorExitCmd)
|
||||
}
|
||||
|
||||
type validatorExitData struct {
|
||||
|
||||
@@ -30,7 +30,7 @@ var versionCmd = &cobra.Command{
|
||||
|
||||
ethdo version.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Println("1.4.12")
|
||||
fmt.Println("1.4.20")
|
||||
if viper.GetBool("verbose") {
|
||||
buildInfo, ok := dbg.ReadBuildInfo()
|
||||
if ok {
|
||||
|
||||
@@ -32,7 +32,7 @@ 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")
|
||||
assert(walletWallet != "", "--wallet is required")
|
||||
|
||||
hasAccounts := false
|
||||
|
||||
|
||||
@@ -18,10 +18,9 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
bip39 "github.com/tyler-smith/go-bip39"
|
||||
wallet "github.com/wealdtech/go-eth2-wallet"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
hd "github.com/wealdtech/go-eth2-wallet-hd/v2"
|
||||
filesystem "github.com/wealdtech/go-eth2-wallet-store-filesystem"
|
||||
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
|
||||
)
|
||||
|
||||
var walletCreateType string
|
||||
@@ -44,23 +43,10 @@ In quiet mode this will return 0 if the wallet is created successfully, otherwis
|
||||
switch strings.ToLower(walletCreateType) {
|
||||
case "non-deterministic", "nd":
|
||||
assert(walletCreateSeed == "", "--seed is not allowed with non-deterministic wallets")
|
||||
_, err = wallet.CreateWallet(walletWallet, wallet.WithType("nd"))
|
||||
err = walletCreateND(walletWallet)
|
||||
case "hierarchical deterministic", "hd":
|
||||
assert(rootWalletPassphrase != "", "--walletpassphrase is required for hierarchical deterministic wallets")
|
||||
store := filesystem.New()
|
||||
encryptor := keystorev4.New()
|
||||
if walletCreateSeed != "" {
|
||||
// Creating wallet from a seed.
|
||||
var seed []byte
|
||||
seed, err = bip39.MnemonicToByteArray(walletCreateSeed)
|
||||
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(walletWallet, []byte(rootWalletPassphrase), store, encryptor, seed)
|
||||
} else {
|
||||
_, err = hd.CreateWallet(walletWallet, []byte(rootWalletPassphrase), store, encryptor)
|
||||
}
|
||||
err = walletCreateHD(walletWallet, rootWalletPassphrase, walletCreateSeed)
|
||||
default:
|
||||
die("unknown wallet type")
|
||||
}
|
||||
@@ -68,6 +54,31 @@ 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())
|
||||
return err
|
||||
}
|
||||
|
||||
// walletCreateND creates a hierarchical-deterministic wallet.
|
||||
func walletCreateHD(name string, passphrase string, seedPhrase 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(name, []byte(passphrase), store, encryptor, seed)
|
||||
return err
|
||||
}
|
||||
// Create wallet with a random seed.
|
||||
_, err := hd.CreateWallet(name, []byte(passphrase), store, encryptor)
|
||||
return err
|
||||
}
|
||||
|
||||
func init() {
|
||||
walletCmd.AddCommand(walletCreateCmd)
|
||||
walletFlags(walletCreateCmd)
|
||||
|
||||
55
cmd/walletdelete.go
Normal file
55
cmd/walletdelete.go
Normal file
@@ -0,0 +1,55 @@
|
||||
// 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 (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
|
||||
)
|
||||
|
||||
var walletDeleteCmd = &cobra.Command{
|
||||
Use: "delete",
|
||||
Short: "Delete a wallet",
|
||||
Long: `Delete a wallet. For example:
|
||||
|
||||
ethdo wallet delete --wallet=primary
|
||||
|
||||
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")
|
||||
|
||||
wallet, err := walletFromPath(walletWallet)
|
||||
errCheck(err, "Failed to access wallet")
|
||||
|
||||
storeProvider, ok := wallet.(wtypes.StoreProvider)
|
||||
assert(ok, "Cannot obtain store for the wallet")
|
||||
store := storeProvider.Store()
|
||||
storeLocationProvider, ok := store.(wtypes.StoreLocationProvider)
|
||||
assert(ok, "Cannot obtain store location for the wallet")
|
||||
walletLocation := filepath.Join(storeLocationProvider.Location(), wallet.ID().String())
|
||||
err = os.RemoveAll(walletLocation)
|
||||
errCheck(err, "Failed to delete wallet")
|
||||
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
walletCmd.AddCommand(walletDeleteCmd)
|
||||
walletFlags(walletDeleteCmd)
|
||||
}
|
||||
@@ -14,18 +14,22 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wealdtech/go-bytesutil"
|
||||
"github.com/wealdtech/go-ecodec"
|
||||
wallet "github.com/wealdtech/go-eth2-wallet"
|
||||
)
|
||||
|
||||
var walletImportData string
|
||||
var walletImportPassphrase string
|
||||
var walletImportVerify bool
|
||||
|
||||
var walletImportCmd = &cobra.Command{
|
||||
Use: "import",
|
||||
@@ -52,8 +56,42 @@ In quiet mode this will return 0 if the wallet is imported successfully, otherwi
|
||||
importData, err := bytesutil.FromHexString(walletImportData)
|
||||
errCheck(err, "Failed to decode wallet data")
|
||||
|
||||
_, err = wallet.ImportWallet(importData, []byte(walletImportPassphrase))
|
||||
errCheck(err, "Failed to import wallet")
|
||||
if walletImportVerify {
|
||||
type accountInfo struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
type walletInfo struct {
|
||||
ID uuid.UUID `json:"uuid"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type export struct {
|
||||
Wallet *walletInfo `json:"wallet"`
|
||||
Accounts []*accountInfo `json:"accounts"`
|
||||
}
|
||||
|
||||
data, err := ecodec.Decrypt(importData, []byte(walletImportPassphrase))
|
||||
errCheck(err, "Failed to decrypt wallet")
|
||||
ext := &export{}
|
||||
err = json.Unmarshal(data, ext)
|
||||
errCheck(err, "Failed to read wallet")
|
||||
|
||||
outputIf(!quiet, fmt.Sprintf("Wallet name: %s", ext.Wallet.Name))
|
||||
outputIf(!quiet, fmt.Sprintf("Wallet type: %s", ext.Wallet.Type))
|
||||
outputIf(verbose, fmt.Sprintf("Wallet UUID: %s", ext.Wallet.ID))
|
||||
if verbose {
|
||||
fmt.Printf("Wallet accounts:\n")
|
||||
for _, account := range ext.Accounts {
|
||||
outputIf(verbose, fmt.Sprintf(" %s", account.Name))
|
||||
}
|
||||
} else {
|
||||
outputIf(!quiet, fmt.Sprintf("Wallet accounts: %d", len(ext.Accounts)))
|
||||
}
|
||||
|
||||
} else {
|
||||
_, err = wallet.ImportWallet(importData, []byte(walletImportPassphrase))
|
||||
errCheck(err, "Failed to import wallet")
|
||||
}
|
||||
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
@@ -64,4 +102,5 @@ func init() {
|
||||
walletFlags(walletImportCmd)
|
||||
walletImportCmd.Flags().StringVar(&walletImportData, "importdata", "", "The data to import, or the name of a file to read")
|
||||
walletImportCmd.Flags().StringVar(&walletImportPassphrase, "importpassphrase", "", "Passphrase protecting the data to import")
|
||||
walletImportCmd.Flags().BoolVar(&walletImportVerify, "verify", false, "Verify the wallet can be imported, but do not import it")
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ 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")
|
||||
assert(walletWallet != "", "--wallet is required")
|
||||
|
||||
wallet, err := walletFromPath(walletWallet)
|
||||
errCheck(err, "unknown wallet")
|
||||
|
||||
@@ -28,7 +28,7 @@ Spending: 0x85dfc6dcee4c9da36f6473ec02fda283d6c920c641fc8e3a76113c5c227d4aeeb100
|
||||
#### `create`
|
||||
|
||||
`ethdo wallet create` creates a new wallet with the given parameters. Options for creating a wallet include:
|
||||
- `wallet`: the name of the wallet to create (defaults to "primary")
|
||||
- `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
|
||||
@@ -37,6 +37,16 @@ Spending: 0x85dfc6dcee4c9da36f6473ec02fda283d6c920c641fc8e3a76113c5c227d4aeeb100
|
||||
$ ethdo wallet create --wallet="Personal wallet" --type="hd" --walletpassphrase="my wallet secret"
|
||||
```
|
||||
|
||||
#### `delete`
|
||||
`ethdo wallet delete` deletes a wallet. Options for deleting a wallet include:
|
||||
- `wallet`: the name of the wallet to delete
|
||||
|
||||
```sh
|
||||
$ ethdo wallet delete --wallet="Old wallet"
|
||||
```
|
||||
|
||||
**Warning** Deleting a wallet is permanent. Only use this command if you really don't want the wallet, or you have securely backed the wallet up using `wallet export`.
|
||||
|
||||
#### `export`
|
||||
|
||||
`ethdo wallet export` exports the wallet and all of its accounts. Options for exporting a wallet include:
|
||||
@@ -59,6 +69,7 @@ $ ethdo wallet export --wallet="Personal wallet" --exportpassphrase="my export s
|
||||
`ethdo wallet import` imports a wallet and all of its accounts exported by `ethdo wallet export`. Options for importing a wallet include:
|
||||
- `importdata`: the data exported by `ethdo wallet export`
|
||||
- `importpassphrase`: the passphrase that was provided to `ethdo wallet export` to encrypt the data
|
||||
- `verify`: confirm information about the wallet import without importing it
|
||||
|
||||
```sh
|
||||
$ ethdo wallet import --importdata="0x01c7a27ad40d45b4ae5be5f..." --importpassphrase="my export secret"
|
||||
|
||||
35
go.mod
35
go.mod
@@ -4,19 +4,16 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.30.25 // indirect
|
||||
github.com/ferranbt/fastssz v0.0.0-20200415074633-b062b680417b // indirect
|
||||
github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/gogo/protobuf v1.3.1
|
||||
github.com/golang/protobuf v1.4.1 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.5 // indirect
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200508110836-07e8f416e478 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.0 // indirect
|
||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.3.1 // indirect
|
||||
github.com/pelletier/go-toml v1.8.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200511212457-3444ffb75440
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200528232825-cf963636d24e
|
||||
github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669
|
||||
github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
@@ -29,19 +26,19 @@ require (
|
||||
github.com/tyler-smith/go-bip39 v1.0.2
|
||||
github.com/wealdtech/eth2-signer-api v1.3.0
|
||||
github.com/wealdtech/go-bytesutil v1.1.1
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.3.1
|
||||
github.com/wealdtech/go-eth2-util v1.1.5
|
||||
github.com/wealdtech/go-eth2-wallet v1.9.4
|
||||
github.com/wealdtech/go-ecodec v1.1.0
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.4.0
|
||||
github.com/wealdtech/go-eth2-util v1.2.0
|
||||
github.com/wealdtech/go-eth2-wallet v1.10.0
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.0.4
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.7.3
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.6.3
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.2
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.0
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.0
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.1.0
|
||||
github.com/wealdtech/go-string2eth v1.1.0
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380 // indirect
|
||||
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b // indirect
|
||||
google.golang.org/grpc v1.29.1
|
||||
gopkg.in/ini.v1 v1.56.0 // indirect
|
||||
gopkg.in/ini.v1 v1.57.0 // indirect
|
||||
)
|
||||
|
||||
52
go.sum
52
go.sum
@@ -21,6 +21,7 @@ github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdII
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
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=
|
||||
@@ -29,6 +30,8 @@ github.com/aws/aws-sdk-go v1.30.15 h1:Sd8QDVzzE8Sl+xNccmdj0HwMrFowv6uVUx9tGsCE1Z
|
||||
github.com/aws/aws-sdk-go v1.30.15/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.30.25 h1:89NXJkfpjnMEnsxkP8MVX+LDsoiLCSqevraLb5y4Mjk=
|
||||
github.com/aws/aws-sdk-go v1.30.25/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
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/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=
|
||||
@@ -63,6 +66,8 @@ 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-20200415074633-b062b680417b h1:CxaMtGnKgr9Ar2xLMVddPhnMwYLDsY56w/LxQ/wnsKA=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200415074633-b062b680417b/go.mod h1:LlFXPmgrgVYsuoFDwV8rDJ9tvt1pLQdjKvU1b5IRES0=
|
||||
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=
|
||||
@@ -103,6 +108,8 @@ 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=
|
||||
@@ -129,9 +136,12 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmg
|
||||
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.12.2/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.13.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.5 h1:aiLxiiVzAXb7wb3lAmubA69IokWOoUNe+E7TdGKh8yw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.5/go.mod h1:UJ0EZAp832vCd54Wev9N1BMKEyvcZ5+IM0AwDrnlkEc=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
@@ -157,6 +167,8 @@ github.com/herumi/bls-eth-go-binary v0.0.0-20200428020417-6dd0e5634b87 h1:23l9wM
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200428020417-6dd0e5634b87/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200508110836-07e8f416e478 h1:UMIHMlIgtPmh96SmXdDiEDRbQ2NSroxBQzpEknueoG4=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200508110836-07e8f416e478/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200522010937-01d282b5380b h1:mu+F5uA3Y68oB6KXZqWlASKMetbNufhQx2stMI+sD+Y=
|
||||
github.com/herumi/bls-eth-go-binary v0.0.0-20200522010937-01d282b5380b/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/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
|
||||
@@ -200,6 +212,8 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.3.0 h1:iDwIio/3gk2QtLLEsqU5lInaMzos0hDTz8a6lazSFVw=
|
||||
github.com/mitchellh/mapstructure v1.3.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
|
||||
github.com/mitchellh/mapstructure v1.3.1/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=
|
||||
@@ -208,6 +222,8 @@ 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.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||
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/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=
|
||||
@@ -231,6 +247,8 @@ github.com/protolambda/zssz v0.1.4 h1:4jkt8sqwhOVR8B1JebREU/gVX0Ply4GypsV8+RWrDu
|
||||
github.com/protolambda/zssz v0.1.4/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200511212457-3444ffb75440 h1:plalLbsEdAKKURjR7u+JUsgD2tyxSa/yitdMyqaWY4E=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200511212457-3444ffb75440/go.mod h1:5OkRN6UmvgtP+kIewitcEKC7S5KOzLOGtya/Tz+HBns=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200528232825-cf963636d24e h1:AvUpoH1sezZmue9NKyHxk7HpD6ajzLVh9m6YCyFwgSw=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200528232825-cf963636d24e/go.mod h1:UQrDJAnxOPXPxvzECD1fmiKAw84LIYcoX2Op7KEUfGk=
|
||||
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=
|
||||
@@ -298,25 +316,42 @@ github.com/wealdtech/go-ecodec v1.1.0 h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5
|
||||
github.com/wealdtech/go-ecodec v1.1.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.3.1 h1:2KSUzducArOynCL2prRf4vWU5GjwaPSnSN9oqNgf+dQ=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.3.1/go.mod h1:FubkGSavaa+rvmHDMTUVoPdFh00wKg0k5QPW6G52mhw=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.4.0 h1:1sFuNENHka/BYHY9F6f1gQqE3dCCQxKODEHc+3RK8fI=
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.4.0/go.mod h1:azyBA/qeMC5sa3BuNm3spje96rHMmW0dyZkJzog8NIk=
|
||||
github.com/wealdtech/go-eth2-util v1.1.5 h1:4OPbf2yaEQmqDmOIU6UKBfhKTPNZ7skU4lPhueBLx8o=
|
||||
github.com/wealdtech/go-eth2-util v1.1.5/go.mod h1:wYYmtc9KpQQAaAzWjXSPLgtsJMkoDAmTNN0h6uj3RCA=
|
||||
github.com/wealdtech/go-eth2-util v1.2.0 h1:ineLDTrFN8zpb7+R2lWrm1HMmTFxlirtcCsppKoVix0=
|
||||
github.com/wealdtech/go-eth2-util v1.2.0/go.mod h1:UNDR21GfVCq429DP+RyFVl2iKkHaMI8B8r7F44NECkU=
|
||||
github.com/wealdtech/go-eth2-wallet v1.9.4 h1:9XFM1Y7dsyrgNFFCnE3Gd00PAsrpob70SAQqHSPmsBU=
|
||||
github.com/wealdtech/go-eth2-wallet v1.9.4/go.mod h1:UGd1bAPDEtP+UrFjj3HCbip7jggFGDIQoeGw8/XHMvo=
|
||||
github.com/wealdtech/go-eth2-wallet v1.10.0 h1:WX6wZQvGwXtu3+L9d9HCW7WWrw6522ur2XiPI6W1lYg=
|
||||
github.com/wealdtech/go-eth2-wallet v1.10.0/go.mod h1:vqB02WIpP0SL+Ug8p4Q8BqVkwPyO1SEarOHAqppjqHE=
|
||||
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.0.3/go.mod h1:nNNZNXCP1BrJCu1hLlFUCAQBvCInD4zwE7eslf2U5XQ=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.0.4 h1:/nBbza+ZPY1dn455AnZRRpIEjeUmTRQCS5QdKf6nhrg=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.0.4/go.mod h1:nNNZNXCP1BrJCu1hLlFUCAQBvCInD4zwE7eslf2U5XQ=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.0 h1:gB3wFIovLgS7GVNU81mpCgekfUmGm8H/f6WtG6xqEJw=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.0/go.mod h1:6voi4JG8G7inZ1bGx41xL2z+YJZc6rr6echT0AUtUdw=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.0.3 h1:NfeWHtyjtZt3hmVA7kysNf2w+cB9Y82w6Cv4zWbFRSk=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.0.3/go.mod h1:RDXAfay+PL+apCVLnVtWBUb183m4uug93FBZ0c2cVaw=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.0 h1:d8JOfWRd39c7w3BLud3eErJH4xSa3tdrMOZjeFXXg0c=
|
||||
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.0/go.mod h1:DTnJWJ5/O56pxqXAR53H4t8K80Rrtop5pmTSOc5tCFA=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.7.3 h1:2nMDDRULzSSa6LCk3044d5J4rXi2HX61nRLyGLXGI3M=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.7.3/go.mod h1:HE1JcXUhWUtJ7F/APzSI/ZTfXjdxbQ15CDe6L0mjtaQ=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.0 h1:iNwHjCj9zGpybEO9URx7AmHWET1PrnkfKcpLYUyFFxw=
|
||||
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.0/go.mod h1:qjU0CZ12duEMCTGORb4bjeUncvy5vUSTVOtwI+/A4A8=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.6.3 h1:SD5tsdj9pRdsfWbhpL09X6gDGO9rJvlI6lz2cxpdfA4=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.6.3/go.mod h1:wS8sqBuIcn9QuLR1VlV7JaSKrFiNOMSPDDBYtWWe98c=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.0 h1:aYMCj2WMCLPbXcITrXx22+P5vhfRW0I1Y1NuJxp5XK0=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.0/go.mod h1:dT5tX+uTFI16qdt4On7KCmxx96V7xYn+vdUJUzPDdyo=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.3.3 h1:0cKttlJ5QONJ2ZndVLUVv3RhbEaSU0TKvOI2BIB9j60=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.3.3/go.mod h1:/tvALCsQ07lvqlU+IKKAdwYFYyjIO628bu/Ssv0JRv4=
|
||||
github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.0/go.mod h1:F+CGazuwGZpxa+2nmr8T1zC3rC0mTTZyO3UFmimNwSs=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.2 h1:Lhwne1gRUp961fD+eoWrgDbZF5rHwosI2LS5pIdX4Yc=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.2/go.mod h1:d7WZ9WvtL3vGSHtSh/jnVh4YO93verLL1dRW2NK5sN4=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.1.0 h1:Zl36EPHI/4SYgjnx+mmYRVKLDdrFpWkT39ClRKYiL7U=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.1.0/go.mod h1:6mlZXBwEeyeAKj22OF+b3E0RFnwoOBM/BXIdAo5QG2M=
|
||||
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=
|
||||
@@ -380,9 +415,12 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjut
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f h1:QBjCr1Fz5kw158VqdE9JfI9cJnl/ymnJWAdMuinqL7Y=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
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/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=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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=
|
||||
@@ -409,6 +447,8 @@ golang.org/x/sys v0.0.0-20200427175716-29b57079015a h1:08u6b1caTT9MQY4wSbmsd4Ulm
|
||||
golang.org/x/sys v0.0.0-20200427175716-29b57079015a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/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/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=
|
||||
@@ -460,6 +500,10 @@ 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-20200511104702-f5ebc3bea380 h1:xriR1EgvKfkKxIoU2uUvrMVl+H26359loFFUleSMXFo=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/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/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=
|
||||
@@ -485,6 +529,10 @@ google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zim
|
||||
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=
|
||||
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=
|
||||
@@ -495,6 +543,8 @@ 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.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
|
||||
gopkg.in/ini.v1 v1.56.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=
|
||||
@@ -504,6 +554,8 @@ 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.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/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=
|
||||
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=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
||||
@@ -75,6 +75,22 @@ func FetchChainConfig(conn *grpc.ClientConn) (map[string]interface{}, error) {
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func FetchLatestFilledSlot(conn *grpc.ClientConn) (uint64, error) {
|
||||
if conn == nil {
|
||||
return 0, errors.New("no connection to beacon node")
|
||||
}
|
||||
beaconClient := ethpb.NewBeaconChainClient(conn)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
|
||||
chainHead, err := beaconClient.GetChainHead(ctx, &types.Empty{})
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "failed to obtain latest")
|
||||
}
|
||||
|
||||
return chainHead.HeadSlot, nil
|
||||
}
|
||||
|
||||
// FetchValidator fetches the validator definition from the beacon node.
|
||||
func FetchValidator(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.Validator, error) {
|
||||
if conn == nil {
|
||||
@@ -167,3 +183,17 @@ func FetchBlock(conn *grpc.ClientConn, slot uint64) (*ethpb.SignedBeaconBlock, e
|
||||
}
|
||||
return resp.BlockContainers[0].Block, nil
|
||||
}
|
||||
|
||||
func StreamBlocks(conn *grpc.ClientConn) (ethpb.BeaconChain_StreamBlocksClient, error) {
|
||||
if conn == nil {
|
||||
return nil, errors.New("no connection to beacon node")
|
||||
}
|
||||
|
||||
beaconClient := ethpb.NewBeaconChainClient(conn)
|
||||
stream, err := beaconClient.StreamBlocks(context.Background(), &types.Empty{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user