mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 14:37:57 -05:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d10b7f2739 | ||
|
|
5f4be0415f | ||
|
|
0f1c6f09bd | ||
|
|
6118f9cab8 | ||
|
|
829dbd3bf2 | ||
|
|
f0ad10463e | ||
|
|
3d0dab0b95 | ||
|
|
5abfabc355 | ||
|
|
e84b600d5d | ||
|
|
e64a46f126 | ||
|
|
0746fa3048 | ||
|
|
94eb3fbca7 | ||
|
|
48d63398d4 | ||
|
|
4e1f47e187 | ||
|
|
85c7c7fc55 | ||
|
|
05406e8d81 |
14
CHANGELOG.md
Normal file
14
CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
1.6.0:
|
||||
- update BLS HKDF function to match spec 04
|
||||
- add --launchpad option to "validator depositdata" to output data in launchpad format
|
||||
1.5.9:
|
||||
- fix issue where wallet mnemonics were not normalised to NFKD
|
||||
- "block info" supports fetching the gensis block (--slot=0)
|
||||
- "attester inclusion" command finds the inclusion slot for a validator's attestation
|
||||
- "account info" with verbose option now displays participants for distributed accounts
|
||||
- fix issue where distributed account generation without a passphrase was not allowed
|
||||
|
||||
1.5.8:
|
||||
- allow raw deposit transactions to be supplied to "deposit verify"
|
||||
- move functionality of "account withdrawalcredentials" to be part of "account info"
|
||||
- add genesis validators root to "chain info"
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
@@ -60,14 +61,27 @@ In quiet mode this will return 0 if the account is created successfully, otherwi
|
||||
outputIf(debug, fmt.Sprintf("Distributed account has %d/%d threshold", viper.GetUint32("signing-threshold"), viper.GetUint32("participants")))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
account, err = distributedCreator.CreateDistributedAccount(ctx, accountName, viper.GetUint32("participants"), viper.GetUint32("signing-threshold"), []byte(getPassphrase()))
|
||||
account, err = distributedCreator.CreateDistributedAccount(ctx, accountName, viper.GetUint32("participants"), viper.GetUint32("signing-threshold"), []byte(getOptionalPassphrase()))
|
||||
} 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"))
|
||||
defer cancel()
|
||||
account, err = creator.CreateAccount(ctx, accountName, []byte(getPassphrase()))
|
||||
if viper.GetString("path") != "" {
|
||||
// Want a pathed account
|
||||
creator, isCreator := wallet.(e2wtypes.WalletPathedAccountCreator)
|
||||
assert(isCreator, "Wallet does not support account creation with an explicit path")
|
||||
var match bool
|
||||
match, err = regexp.Match("^m/[0-9]+/[0-9]+(/[0-9+])+", []byte(viper.GetString("path")))
|
||||
errCheck(err, "Unable to match path to regular expression")
|
||||
assert(match, "Path does not match expected format m/...")
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
account, err = creator.CreatePathedAccount(ctx, viper.GetString("path"), accountName, []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"))
|
||||
defer cancel()
|
||||
account, err = creator.CreateAccount(ctx, accountName, []byte(getPassphrase()))
|
||||
}
|
||||
}
|
||||
errCheck(err, "Failed to create account")
|
||||
|
||||
@@ -85,11 +99,18 @@ func init() {
|
||||
accountCmd.AddCommand(accountCreateCmd)
|
||||
accountFlags(accountCreateCmd)
|
||||
accountCreateCmd.Flags().Uint32("participants", 0, "Number of participants (for distributed accounts)")
|
||||
accountCreateCmd.Flags().Uint32("signing-threshold", 0, "Signing threshold (for distributed accounts)")
|
||||
accountCreateCmd.Flags().String("path", "", "path of account (for hierarchical deterministic accounts)")
|
||||
}
|
||||
|
||||
func accountCreateBindings() {
|
||||
if err := viper.BindPFlag("participants", accountCreateCmd.Flags().Lookup("participants")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
accountCreateCmd.Flags().Uint32("signing-threshold", 0, "Signing threshold (for distributed accounts)")
|
||||
if err := viper.BindPFlag("signing-threshold", accountCreateCmd.Flags().Lookup("signing-threshold")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := viper.BindPFlag("path", accountCreateCmd.Flags().Lookup("path")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,13 @@ In quiet mode this will return 0 if the account exists, otherwise 1.`,
|
||||
if distributedAccount, ok := account.(e2wtypes.DistributedAccount); ok {
|
||||
fmt.Printf("Composite public key: %#x\n", distributedAccount.CompositePublicKey().Marshal())
|
||||
fmt.Printf("Signing threshold: %d/%d\n", distributedAccount.SigningThreshold(), len(distributedAccount.Participants()))
|
||||
if verbose {
|
||||
fmt.Printf("Participants:\n")
|
||||
for k, v := range distributedAccount.Participants() {
|
||||
fmt.Printf(" %d: %s\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
withdrawalPubKey = distributedAccount.CompositePublicKey()
|
||||
}
|
||||
if verbose {
|
||||
|
||||
@@ -1,73 +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 (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
util "github.com/wealdtech/go-eth2-util"
|
||||
)
|
||||
|
||||
var accountWithdrawalCredentialsCmd = &cobra.Command{
|
||||
Use: "withdrawalcredentials",
|
||||
Short: "Provide withdrawal credentials for an account",
|
||||
Long: `Provide withdrawal credentials for an account. For example:
|
||||
|
||||
ethdo account withdrawalcredentials --account="Validators/1"
|
||||
|
||||
In quiet mode this will return 0 if the account exists, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
|
||||
assert(viper.GetString("account") != "" || viper.GetString("pubkey") != "", "account or pubkey is required")
|
||||
|
||||
var pubKey []byte
|
||||
if viper.GetString("pubkey") != "" {
|
||||
var err error
|
||||
pubKey, err = hex.DecodeString(strings.TrimPrefix(viper.GetString("pubkey"), "0x"))
|
||||
errCheck(err, "Failed to decode supplied public key")
|
||||
} else {
|
||||
_, account, err := walletAndAccountFromInput(ctx)
|
||||
errCheck(err, "Failed to obtain account")
|
||||
|
||||
key, err := bestPublicKey(account)
|
||||
errCheck(err, "Account does not provide a public key")
|
||||
pubKey = key.Marshal()
|
||||
}
|
||||
|
||||
if quiet {
|
||||
os.Exit(_exitSuccess)
|
||||
}
|
||||
|
||||
withdrawalCredentials := util.SHA256(pubKey)
|
||||
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
|
||||
fmt.Printf("%#x\n", withdrawalCredentials)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
accountCmd.AddCommand(accountWithdrawalCredentialsCmd)
|
||||
accountFlags(accountWithdrawalCredentialsCmd)
|
||||
accountWithdrawalCredentialsCmd.Flags().String("pubkey", "", "Public key (overrides account)")
|
||||
if err := viper.BindPFlag("pubkey", accountCreateCmd.Flags().Lookup("pubkey")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
32
cmd/attester.go
Normal file
32
cmd/attester.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// attesterCmd represents the attester command
|
||||
var attesterCmd = &cobra.Command{
|
||||
Use: "attester",
|
||||
Short: "Obtain information about Ethereum 2 attesters",
|
||||
Long: "Obtain information about Ethereum 2 attesters",
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(attesterCmd)
|
||||
}
|
||||
|
||||
func attesterFlags(cmd *cobra.Command) {
|
||||
}
|
||||
156
cmd/attesterinclusion.go
Normal file
156
cmd/attesterinclusion.go
Normal file
@@ -0,0 +1,156 @@
|
||||
// Copyright © 2020 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/wealdtech/ethdo/grpc"
|
||||
"github.com/wealdtech/ethdo/util"
|
||||
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
|
||||
)
|
||||
|
||||
var attesterInclusionCmd = &cobra.Command{
|
||||
Use: "inclusion",
|
||||
Short: "Obtain information about attester inclusion",
|
||||
Long: `Obtain information about attester inclusion. For example:
|
||||
|
||||
ethdo attester inclusion --account=Validators/00001 --epoch=12345
|
||||
|
||||
In quiet mode this will return 0 if an attestation from the attester is found on the block fo the given epoch, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := connect()
|
||||
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain block")
|
||||
|
||||
// Obtain the epoch.
|
||||
epoch := viper.GetInt64("epoch")
|
||||
if epoch == -1 {
|
||||
outputIf(debug, "No epoch supplied; fetching current epoch")
|
||||
config, err := grpc.FetchChainConfig(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain beacon chain configuration")
|
||||
slotsPerEpoch := config["SlotsPerEpoch"].(uint64)
|
||||
secondsPerSlot := config["SecondsPerSlot"].(uint64)
|
||||
genesisTime, err := grpc.FetchGenesisTime(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain beacon chain genesis")
|
||||
epoch = int64(time.Since(genesisTime).Seconds()) / int64(secondsPerSlot*slotsPerEpoch)
|
||||
}
|
||||
outputIf(debug, fmt.Sprintf("Epoch is %d", epoch))
|
||||
|
||||
// Obtain the validator.
|
||||
account, err := attesterInclusionAccount()
|
||||
errCheck(err, "Failed to obtain account")
|
||||
validatorIndex, err := grpc.FetchValidatorIndex(eth2GRPCConn, account)
|
||||
errCheck(err, "Failed to obtain validator")
|
||||
|
||||
// Find the attesting slot for the given epoch.
|
||||
committees, err := grpc.FetchValidatorCommittees(eth2GRPCConn, uint64(epoch))
|
||||
errCheck(err, "Failed to obtain validator committees")
|
||||
|
||||
slot := uint64(0)
|
||||
committeeIndex := uint64(0)
|
||||
validatorPositionInCommittee := uint64(0)
|
||||
found := false
|
||||
for searchSlot, committee := range committees {
|
||||
for searchCommitteeIndex, committeeValidatorIndices := range committee {
|
||||
for position, committeeValidatorIndex := range committeeValidatorIndices {
|
||||
if validatorIndex == committeeValidatorIndex {
|
||||
outputIf(verbose, fmt.Sprintf("Validator %d scheduled to attest at slot %d for epoch %d: entry %d in committee %d", validatorIndex, searchSlot, epoch, position, searchCommitteeIndex))
|
||||
slot = searchSlot
|
||||
committeeIndex = uint64(searchCommitteeIndex)
|
||||
validatorPositionInCommittee = uint64(position)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(found, "Failed to find attester duty for validator in the given epoch")
|
||||
|
||||
startSlot := slot + 1
|
||||
endSlot := startSlot + 32
|
||||
for curSlot := startSlot; curSlot < endSlot; curSlot++ {
|
||||
signedBlock, err := grpc.FetchBlock(eth2GRPCConn, curSlot)
|
||||
errCheck(err, "Failed to obtain block")
|
||||
if signedBlock == nil {
|
||||
outputIf(debug, fmt.Sprintf("No block at slot %d", curSlot))
|
||||
continue
|
||||
}
|
||||
outputIf(debug, fmt.Sprintf("Fetched block %d", curSlot))
|
||||
for i, attestation := range signedBlock.Block.Body.Attestations {
|
||||
outputIf(debug, fmt.Sprintf("Attestation %d is for slot %d and committee %d", i, attestation.Data.Slot, attestation.Data.CommitteeIndex))
|
||||
if attestation.Data.Slot == slot &&
|
||||
attestation.Data.CommitteeIndex == committeeIndex &&
|
||||
attestation.AggregationBits.BitAt(validatorPositionInCommittee) {
|
||||
if verbose {
|
||||
fmt.Printf("Attestation included in block %d, attestation %d (inclusion delay %d)\n", curSlot, i, curSlot-slot)
|
||||
} else if !quiet {
|
||||
fmt.Printf("Attestation included in block %d (inclusion delay %d)\n", curSlot, curSlot-slot)
|
||||
}
|
||||
os.Exit(_exitSuccess)
|
||||
}
|
||||
}
|
||||
}
|
||||
outputIf(verbose, "Attestation not included on the chain")
|
||||
os.Exit(_exitFailure)
|
||||
},
|
||||
}
|
||||
|
||||
// attesterInclusionAccount obtains the account for the attester inclusion command.
|
||||
func attesterInclusionAccount() (e2wtypes.Account, error) {
|
||||
var account e2wtypes.Account
|
||||
var err error
|
||||
if viper.GetString("account") != "" {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
_, account, err = walletAndAccountFromPath(ctx, viper.GetString("account"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain account")
|
||||
}
|
||||
} else {
|
||||
pubKey := viper.GetString("pubkey")
|
||||
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(pubKey, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", pubKey))
|
||||
}
|
||||
account, err = util.NewScratchAccount(nil, pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", pubKey))
|
||||
}
|
||||
}
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
attesterCmd.AddCommand(attesterInclusionCmd)
|
||||
attesterFlags(attesterInclusionCmd)
|
||||
attesterInclusionCmd.Flags().Int64("epoch", -1, "the current epoch")
|
||||
attesterInclusionCmd.Flags().String("pubkey", "", "the public key of the attester")
|
||||
}
|
||||
|
||||
func attesterInclusionBindings() {
|
||||
if err := viper.BindPFlag("epoch", attesterInclusionCmd.Flags().Lookup("epoch")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := viper.BindPFlag("pubkey", attesterInclusionCmd.Flags().Lookup("pubkey")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ In quiet mode this will return 0 if the block information is present and not ski
|
||||
genesisTime, err := grpc.FetchGenesisTime(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain beacon chain genesis")
|
||||
|
||||
assert(blockInfoStream || blockInfoSlot != 0, "--slot or --stream is required")
|
||||
assert(!blockInfoStream || blockInfoSlot == -1, "--slot and --stream are not supported together")
|
||||
|
||||
var slot uint64
|
||||
@@ -64,8 +63,6 @@ In quiet mode this will return 0 if the block information is present and not ski
|
||||
} 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 {
|
||||
|
||||
@@ -39,6 +39,9 @@ In quiet mode this will return 0 if the chain information can be obtained, other
|
||||
genesisTime, err := grpc.FetchGenesisTime(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain genesis time")
|
||||
|
||||
genesisValidatorsRoot, err := grpc.FetchGenesisValidatorsRoot(eth2GRPCConn)
|
||||
errCheck(err, "Failed to obtain genesis validators root")
|
||||
|
||||
if quiet {
|
||||
os.Exit(_exitSuccess)
|
||||
}
|
||||
@@ -49,9 +52,10 @@ In quiet mode this will return 0 if the chain information can be obtained, other
|
||||
fmt.Printf("Genesis time: %s\n", genesisTime.Format(time.UnixDate))
|
||||
outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesisTime.Unix()))
|
||||
}
|
||||
outputIf(verbose, fmt.Sprintf("Genesis fork version: %0x", config["GenesisForkVersion"].([]byte)))
|
||||
outputIf(verbose, fmt.Sprintf("Seconds per slot: %v", config["SecondsPerSlot"].(uint64)))
|
||||
outputIf(verbose, fmt.Sprintf("Slots per epoch: %v", config["SlotsPerEpoch"].(uint64)))
|
||||
fmt.Printf("Genesis validators root: %#x\n", genesisValidatorsRoot)
|
||||
fmt.Printf("Genesis fork version: %#x\n", config["GenesisForkVersion"].([]byte))
|
||||
fmt.Printf("Seconds per slot: %d\n", config["SecondsPerSlot"].(uint64))
|
||||
fmt.Printf("Slots per epoch: %d\n", config["SlotsPerEpoch"].(uint64))
|
||||
|
||||
os.Exit(_exitSuccess)
|
||||
},
|
||||
|
||||
@@ -16,48 +16,60 @@ package cmd
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/wealdtech/ethdo/util"
|
||||
e2types "github.com/wealdtech/go-eth2-types/v2"
|
||||
util "github.com/wealdtech/go-eth2-util"
|
||||
eth2util "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 depositVerifyDepositAmount string
|
||||
|
||||
var depositVerifyCmd = &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Verify deposit data matches requirements",
|
||||
Long: `Verify deposit data matches requirements. For example:
|
||||
Short: "Verify deposit data matches the provided data",
|
||||
Long: `Verify deposit data matches the provided input data. 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.
|
||||
The deposit data is compared to the supplied withdrawal account/public key, validator public key, and value to ensure they match.
|
||||
|
||||
In quiet mode this will return 0 if the the data can be generated correctly, otherwise 1.`,
|
||||
In quiet mode this will return 0 if the the data is verified correctly, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
assert(depositVerifyData != "", "--data is required")
|
||||
deposits, err := depositDataFromJSON(depositVerifyData)
|
||||
var data []byte
|
||||
var err error
|
||||
// Input could be JSON or a path to JSON.
|
||||
switch {
|
||||
case strings.HasPrefix(depositVerifyData, "0x"):
|
||||
// Looks like raw binary.
|
||||
data = []byte(depositVerifyData)
|
||||
case strings.HasPrefix(depositVerifyData, "{"):
|
||||
// Looks like JSON.
|
||||
data = []byte("[" + depositVerifyData + "]")
|
||||
case strings.HasPrefix(depositVerifyData, "["):
|
||||
// Looks like JSON array.
|
||||
data = []byte(depositVerifyData)
|
||||
default:
|
||||
// Assume it's a path to JSON.
|
||||
data, err = ioutil.ReadFile(depositVerifyData)
|
||||
errCheck(err, "Failed to read deposit data file")
|
||||
if data[0] == '{' {
|
||||
data = []byte("[" + string(data) + "]")
|
||||
}
|
||||
}
|
||||
|
||||
deposits, err := util.DepositInfoFromJSON(data)
|
||||
errCheck(err, "Failed to fetch deposit data")
|
||||
|
||||
var withdrawalCredentials []byte
|
||||
@@ -67,17 +79,16 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
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")
|
||||
withdrawalCredentials = util.SHA256(withdrawalPubKey.Marshal())
|
||||
withdrawalCredentials = eth2util.SHA256(withdrawalPubKey.Marshal())
|
||||
withdrawalCredentials[0] = 0 // BLS_WITHDRAWAL_PREFIX
|
||||
}
|
||||
outputIf(debug, fmt.Sprintf("Withdrawal credentials are %#x", withdrawalCredentials))
|
||||
|
||||
depositValue := uint64(0)
|
||||
if depositVerifyDepositValue != "" {
|
||||
depositValue, err = string2eth.StringToGWei(depositVerifyDepositValue)
|
||||
depositAmount := uint64(0)
|
||||
if depositVerifyDepositAmount != "" {
|
||||
depositAmount, err = string2eth.StringToGWei(depositVerifyDepositAmount)
|
||||
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
|
||||
assert(depositAmount >= 1000000000, "deposit amount must be at least 1 Ether") // MIN_DEPOSIT_AMOUNT
|
||||
}
|
||||
|
||||
validatorPubKeys := make(map[[48]byte]bool)
|
||||
@@ -88,31 +99,17 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
|
||||
failures := false
|
||||
for i, deposit := range deposits {
|
||||
if withdrawalCredentials != nil {
|
||||
depositWithdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x"))
|
||||
errCheck(err, fmt.Sprintf("Invalid withdrawal public key for deposit %d", i))
|
||||
if !bytes.Equal(depositWithdrawalCredentials, withdrawalCredentials) {
|
||||
outputIf(!quiet, fmt.Sprintf("Invalid withdrawal credentials for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
if deposit.Amount == 0 {
|
||||
deposit.Amount = depositAmount
|
||||
}
|
||||
if depositValue != 0 {
|
||||
if deposit.Value != depositValue {
|
||||
outputIf(!quiet, fmt.Sprintf("Invalid deposit value for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
verified, err := verifyDeposit(deposit, withdrawalCredentials, validatorPubKeys, depositAmount)
|
||||
errCheck(err, fmt.Sprintf("Error attempting to verify deposit %d", i))
|
||||
if !verified {
|
||||
failures = true
|
||||
outputIf(!quiet, fmt.Sprintf("Deposit %q failed verification", deposit.Name))
|
||||
} else {
|
||||
outputIf(quiet, fmt.Sprintf("Deposit %q verified", deposit.Name))
|
||||
}
|
||||
if len(validatorPubKeys) != 0 {
|
||||
depositValidatorPubKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x"))
|
||||
errCheck(err, fmt.Sprintf("Invalid validator public key for deposit %d", i))
|
||||
var key [48]byte
|
||||
copy(key[:], depositValidatorPubKey)
|
||||
if _, exists := validatorPubKeys[key]; !exists {
|
||||
outputIf(!quiet, fmt.Sprintf("Unknown validator public key for deposit %d", i))
|
||||
failures = true
|
||||
}
|
||||
}
|
||||
outputIf(!quiet, fmt.Sprintf("Deposit %q verified", deposit.Name))
|
||||
}
|
||||
|
||||
if failures {
|
||||
@@ -177,61 +174,47 @@ func validatorPubKeysFromInput(input string) (map[[48]byte]bool, error) {
|
||||
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) + "]")
|
||||
func verifyDeposit(deposit *util.DepositInfo, withdrawalCredentials []byte, validatorPubKeys map[[48]byte]bool, amount uint64) (bool, error) {
|
||||
if withdrawalCredentials != nil {
|
||||
if !bytes.Equal(deposit.WithdrawalCredentials, withdrawalCredentials) {
|
||||
return false, errors.New("withdrawal credentials incorrect")
|
||||
}
|
||||
outputIf(verbose, "Withdrawal credentials verified")
|
||||
}
|
||||
var depositData []*depositData
|
||||
err = json.Unmarshal(data, &depositData)
|
||||
if amount != 0 {
|
||||
if deposit.Amount != amount {
|
||||
return false, errors.New("deposit value incorrect")
|
||||
}
|
||||
outputIf(verbose, "Amount verified")
|
||||
}
|
||||
|
||||
if len(validatorPubKeys) != 0 {
|
||||
var key [48]byte
|
||||
copy(key[:], deposit.PublicKey)
|
||||
if _, exists := validatorPubKeys[key]; !exists {
|
||||
return false, errors.New("validator public key incorrect")
|
||||
}
|
||||
outputIf(verbose, "Validator public key verified")
|
||||
}
|
||||
|
||||
depositData := ðpb.Deposit_Data{
|
||||
PublicKey: deposit.PublicKey,
|
||||
WithdrawalCredentials: deposit.WithdrawalCredentials,
|
||||
Amount: deposit.Amount,
|
||||
Signature: deposit.Signature,
|
||||
}
|
||||
depositDataRoot, err := depositData.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "data is not valid JSON")
|
||||
return false, errors.Wrap(err, "failed to generate deposit data root")
|
||||
}
|
||||
if len(depositData) == 0 {
|
||||
return nil, errors.New("no deposits supplied")
|
||||
if !bytes.Equal(deposit.DepositDataRoot, depositDataRoot[:]) {
|
||||
return false, errors.New("deposit data root incorrect")
|
||||
}
|
||||
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
|
||||
outputIf(debug, "Deposit data root verified")
|
||||
|
||||
outputIf(verbose, "Deposit verified")
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -239,6 +222,6 @@ func init() {
|
||||
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(&depositVerifyDepositAmount, "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")
|
||||
}
|
||||
|
||||
@@ -36,14 +36,12 @@ var exitVerifyPubKey string
|
||||
|
||||
var exitVerifyCmd = &cobra.Command{
|
||||
Use: "verify",
|
||||
Short: "Verify deposit data matches requirements",
|
||||
Long: `Verify deposit data matches requirements. For example:
|
||||
Short: "Verify exit data is valid",
|
||||
Long: `Verify that exit data generated by "ethdo validator exit" is correct for a given account. For example:
|
||||
|
||||
ethdo deposit verify --data=depositdata.json --withdrawalaccount=primary/current --value="32 Ether"
|
||||
ethdo exit verify --data=exitdata.json --account=primary/current
|
||||
|
||||
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.`,
|
||||
In quiet mode this will return 0 if the the exit is verified correctly, otherwise 1.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
@@ -60,7 +58,7 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
err = connect()
|
||||
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
|
||||
genesisValidatorsRoot, err := grpc.FetchGenesisValidatorsRoot(eth2GRPCConn)
|
||||
outputIf(debug, fmt.Sprintf("Genesis validators root is %x", genesisValidatorsRoot))
|
||||
outputIf(debug, fmt.Sprintf("Genesis validators root is %#x", genesisValidatorsRoot))
|
||||
errCheck(err, "Failed to obtain genesis validators root")
|
||||
domain := e2types.Domain(e2types.DomainVoluntaryExit, data.ForkVersion, genesisValidatorsRoot)
|
||||
exit := ðpb.VoluntaryExit{
|
||||
@@ -131,7 +129,10 @@ func init() {
|
||||
exitFlags(exitVerifyCmd)
|
||||
exitVerifyCmd.Flags().String("data", "", "JSON data, or path to JSON data")
|
||||
exitVerifyCmd.Flags().StringVar(&exitVerifyPubKey, "pubkey", "", "Public key for which to verify exit")
|
||||
if err := viper.BindPFlag("exit.data", exitVerifyCmd.Flags().Lookup("data")); err != nil {
|
||||
}
|
||||
|
||||
func exitVerifyBindings() {
|
||||
if err := viper.BindPFlag("data", exitVerifyCmd.Flags().Lookup("data")); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,3 +37,13 @@ func getPassphrase() string {
|
||||
assert(len(passphrases) == 1, "multiple passphrases supplied; cannot continue")
|
||||
return passphrases[0]
|
||||
}
|
||||
|
||||
// getOptionalPassphrase fetches the passphrase if supplied by the user.
|
||||
func getOptionalPassphrase() string {
|
||||
passphrases := getPassphrases()
|
||||
if len(passphrases) == 0 {
|
||||
return ""
|
||||
}
|
||||
assert(len(passphrases) == 1, "multiple passphrases supplied; cannot continue")
|
||||
return passphrases[0]
|
||||
}
|
||||
|
||||
19
cmd/root.go
19
cmd/root.go
@@ -72,11 +72,22 @@ func persistentPreRun(cmd *cobra.Command, args []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// We bind viper here so that we bind to the correct command
|
||||
// We bind viper here so that we bind to the correct command.
|
||||
quiet = viper.GetBool("quiet")
|
||||
verbose = viper.GetBool("verbose")
|
||||
debug = viper.GetBool("debug")
|
||||
rootStore = viper.GetString("store")
|
||||
// Command-specific bindings.
|
||||
switch fmt.Sprintf("%s/%s", cmd.Parent().Name(), cmd.Name()) {
|
||||
case "account/create":
|
||||
accountCreateBindings()
|
||||
case "attester/inclusion":
|
||||
attesterInclusionBindings()
|
||||
case "exit/verify":
|
||||
exitVerifyBindings()
|
||||
case "wallet/create":
|
||||
walletCreateBindings()
|
||||
}
|
||||
|
||||
if quiet && verbose {
|
||||
fmt.Println("Cannot supply both quiet and verbose flags")
|
||||
@@ -233,8 +244,12 @@ func outputIf(condition bool, msg string) {
|
||||
}
|
||||
}
|
||||
|
||||
// walletFromInput obtains a wallet given the information in the viper variable "wallet".
|
||||
// walletFromInput obtains a wallet given the information in the viper variable
|
||||
// "account", or if not present the viper variable "wallet".
|
||||
func walletFromInput(ctx context.Context) (e2wtypes.Wallet, error) {
|
||||
if viper.GetString("account") != "" {
|
||||
return walletFromPath(ctx, viper.GetString("account"))
|
||||
}
|
||||
return walletFromPath(ctx, viper.GetString("wallet"))
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ var validatorDepositDataWithdrawalPubKey string
|
||||
var validatorDepositDataDepositValue string
|
||||
var validatorDepositDataRaw bool
|
||||
var validatorDepositDataForkVersion string
|
||||
var validatorDepositDataLaunchpad bool
|
||||
|
||||
var validatorDepositDataCmd = &cobra.Command{
|
||||
Use: "depositdata",
|
||||
@@ -156,7 +157,8 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
errCheck(err, "Failed to generate deposit data root")
|
||||
outputIf(debug, fmt.Sprintf("Deposit data root is %x", depositDataRoot))
|
||||
|
||||
if validatorDepositDataRaw {
|
||||
switch {
|
||||
case validatorDepositDataRaw:
|
||||
// Build a raw transaction by hand
|
||||
txData := []byte{0x22, 0x89, 0x51, 0x18}
|
||||
// Pointer to validator public key
|
||||
@@ -178,7 +180,20 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
|
||||
txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}...)
|
||||
txData = append(txData, signedDepositData.Signature...)
|
||||
outputs = append(outputs, fmt.Sprintf("%#x", txData))
|
||||
} else {
|
||||
case validatorDepositDataLaunchpad:
|
||||
depositMessage := struct {
|
||||
PubKey []byte `ssz-size:"48"`
|
||||
WithdrawalCredentials []byte `ssz-size:"32"`
|
||||
Value uint64
|
||||
}{
|
||||
PubKey: validatorPubKey.Marshal(),
|
||||
WithdrawalCredentials: withdrawalCredentials,
|
||||
Value: val,
|
||||
}
|
||||
depositMessageRoot, err := ssz.HashTreeRoot(depositMessage)
|
||||
errCheck(err, "Failed to generate deposit message root")
|
||||
outputs = append(outputs, fmt.Sprintf(`{"pubkey":"%x","withdrawal_credentials":"%x","amount":%d,"signature":"%x","deposit_message_root":"%x","deposit_data_root":"%x","fork_version":"%x"}`, signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, val, signedDepositData.Signature, depositMessageRoot, depositDataRoot, forkVersion))
|
||||
default:
|
||||
outputs = append(outputs, fmt.Sprintf(`{"name":"Deposit for %s","account":"%s","pubkey":"%#x","withdrawal_credentials":"%#x","signature":"%#x","value":%d,"deposit_data_root":"%#x","version":2}`, fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Signature, val, depositDataRoot))
|
||||
}
|
||||
}
|
||||
@@ -206,4 +221,5 @@ func init() {
|
||||
validatorDepositDataCmd.Flags().StringVar(&validatorDepositDataDepositValue, "depositvalue", "", "Value of the amount to be deposited")
|
||||
validatorDepositDataCmd.Flags().BoolVar(&validatorDepositDataRaw, "raw", false, "Print raw deposit data transaction data")
|
||||
validatorDepositDataCmd.Flags().StringVar(&validatorDepositDataForkVersion, "forkversion", "", "Use a hard-coded fork version (default is to fetch it from the node)")
|
||||
validatorDepositDataCmd.Flags().BoolVar(&validatorDepositDataLaunchpad, "launchpad", false, "Print launchpad-compatible JSON")
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var ReleaseVersion = "local build from v1.5.5"
|
||||
var ReleaseVersion = "local build from v1.6.0"
|
||||
|
||||
// versionCmd represents the version command
|
||||
var versionCmd = &cobra.Command{
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
hd "github.com/wealdtech/go-eth2-wallet-hd/v2"
|
||||
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
var walletCreateCmd = &cobra.Command{
|
||||
@@ -106,6 +107,9 @@ func walletCreateHD(ctx context.Context, name string, passphrase string, mnemoni
|
||||
mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ")
|
||||
}
|
||||
}
|
||||
// Normalise the input.
|
||||
mnemonic = string(norm.NFKD.Bytes([]byte(mnemonic)))
|
||||
mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase)))
|
||||
|
||||
// Ensure the mnemonic is valid
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
@@ -135,10 +139,13 @@ func init() {
|
||||
walletCmd.AddCommand(walletCreateCmd)
|
||||
walletFlags(walletCreateCmd)
|
||||
walletCreateCmd.Flags().String("type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)")
|
||||
walletCreateCmd.Flags().String("mnemonic", "", "The 24-word mnemonic for a hierarchical deterministic wallet")
|
||||
}
|
||||
|
||||
func walletCreateBindings() {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -65,3 +65,21 @@ ethdo wallet info --verbose --wallet="My wallet"
|
||||
```
|
||||
|
||||
This will provide, amongst other information, a `Location` line giving the directory where the wallet information resides.
|
||||
|
||||
## Recreate launchpad wallet and accounts
|
||||
|
||||
Recreating launchpad accounts requires two steps: recreating the wallet, and recreating the individual accounts. All that is required is the mnemonic from the launchpad process.
|
||||
|
||||
To recreate the wallet with the given mnemonic run the following command (changing the wallet name, passphrase and mnemonic as required):
|
||||
|
||||
```sh
|
||||
ethdo wallet create --wallet="Launchpad" --type=hd --walletpassphrase=walletsecret --mnemonic="faculty key lamp panel appear choose express off absent dance strike twenty elephant expect swift that resist bicycle kind sun favorite evoke engage thumb"
|
||||
```
|
||||
|
||||
Launchpad accounts are identified by their path. The path can be seen in the filename of the keystore, for example the filename `keystore-m_12381_3600_1_0_0-1596891358.json` relates to a path of `m/12381/3600/1/0/0`. It is also present directly in the keystore under the `path` key.
|
||||
|
||||
To create an account corresponding to this key with the account name "Account 1" you would use the command:
|
||||
|
||||
```sh
|
||||
ethdo account create --account="Launchpad/Account 1" --walletpassphrase=walletsecret --passphrase=secret --path=m/12381/3600/1/0/0
|
||||
```
|
||||
|
||||
@@ -112,9 +112,12 @@ Account commands focus on information about local accounts, generally those used
|
||||
`ethdo account create` creates a new account with the given parameters. Options for creating an account include:
|
||||
- `account`: the name of the account to create
|
||||
- `passphrase`: the passphrase for the account
|
||||
- `path`: the HD path for the account (only for hierarchical deterministic accounts)
|
||||
|
||||
Note that for hierarchical deterministic wallets you will also need to supply `--walletpassphrase` to unlock the wallet seed.
|
||||
|
||||
For distributed accounts you will also need to supply `--participants` and `--signing-threshold`.
|
||||
|
||||
```sh
|
||||
$ ethdo account create --account="Personal wallet/Operations" --walletpassphrase="my wallet secret" --passphrase="my account secret"
|
||||
```
|
||||
@@ -314,7 +317,7 @@ Deposit commands focus on information about deposit data information in a JSON f
|
||||
#### `verify`
|
||||
|
||||
`ethdo deposit verify` verifies one or more deposit data information in a JSON file generated by the `ethdo validator depositdata` command. Options include:
|
||||
- `data`: either a path to the JSON file or the JSON itself
|
||||
- `data`: either a path to the JSON file, the JSON itself, or a hex string representing a deposit transaction
|
||||
- `withdrawalpubkey`: the public key of the withdrawal for the deposit. If no value is supplied then withdrawal credentials for deposits will not be checked
|
||||
- `validatorpubkey`: the public key of the validator for the deposit. If no value is supplied then validator public keys will not be checked
|
||||
- `depositvalue`: the value of the Ether being deposited. If no value is supplied then deposit values will not be checked.
|
||||
@@ -363,6 +366,7 @@ Current slot: 178
|
||||
Current epoch: 5
|
||||
Genesis timestamp: 1587020563
|
||||
```
|
||||
|
||||
### `validator` commands
|
||||
|
||||
Validator commands focus on interaction with Ethereum 2 validators.
|
||||
@@ -428,6 +432,22 @@ Balance: 3.201850307 Ether
|
||||
Effective balance: 3.1 Ether
|
||||
```
|
||||
|
||||
### `attester` commands
|
||||
|
||||
Attester commands focus on Ethereum 2 validators' actions as attesters.
|
||||
|
||||
#### `inclusion`
|
||||
|
||||
`ethdo attester inclusion` finds the block with wihch an attestation is included on the chain. Options include:
|
||||
- `epoch` the epoch in which to obtain the inclusion information (defaults to current epoch)
|
||||
- `account` the account for which to fetch the inclusion information
|
||||
- `pubkey` the public key for which to fetch the inclusion information
|
||||
|
||||
```sh
|
||||
$ ethdo attester inclusion --account=Validators/1 --epoch=6484
|
||||
Attestation included in block 207492 (inclusion delay 1)
|
||||
```
|
||||
|
||||
## Maintainers
|
||||
|
||||
Jim McDonald: [@mcdee](https://github.com/mcdee).
|
||||
|
||||
35
go.mod
35
go.mod
@@ -4,45 +4,48 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
||||
github.com/aws/aws-sdk-go v1.33.11 // indirect
|
||||
github.com/aws/aws-sdk-go v1.34.9 // indirect
|
||||
github.com/ferranbt/fastssz v0.0.0-20200818222714-826c7ef45b30 // 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/grpc-ecosystem/grpc-gateway v1.14.7 // indirect
|
||||
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.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-20200709024211-e8095222f77b
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200812153649-a842fc47c2c3
|
||||
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.2 // indirect
|
||||
github.com/spf13/afero v1.3.4 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/cobra v1.0.0
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.7.0
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/tyler-smith/go-bip39 v1.0.2
|
||||
github.com/wealdtech/eth2-signer-api v1.5.2
|
||||
github.com/wealdtech/go-bytesutil v1.1.1
|
||||
github.com/wealdtech/go-ecodec v1.1.0
|
||||
github.com/wealdtech/go-eth2-types/v2 v2.5.0
|
||||
github.com/wealdtech/go-eth2-util v1.5.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-util v1.6.0
|
||||
github.com/wealdtech/go-eth2-wallet v1.14.0
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.3
|
||||
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-hd/v2 v2.5.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.6.0
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.0
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.7.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
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
|
||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29 // indirect
|
||||
golang.org/x/text v0.3.3
|
||||
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70 // indirect
|
||||
google.golang.org/grpc v1.31.0
|
||||
gopkg.in/ini.v1 v1.60.1 // indirect
|
||||
)
|
||||
|
||||
57
go.sum
57
go.sum
@@ -31,6 +31,10 @@ 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/aws/aws-sdk-go v1.34.5 h1:FwubVVX9u+kW9qDCjVzyWOdsL+W5wPq683wMk2R2GXk=
|
||||
github.com/aws/aws-sdk-go v1.34.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
|
||||
github.com/aws/aws-sdk-go v1.34.9 h1:cUGBW9CVdi0mS7K1hDzxIqTpfeWhpoQiguq81M1tjK0=
|
||||
github.com/aws/aws-sdk-go v1.34.9/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=
|
||||
@@ -67,6 +71,11 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472 h1:maoKvILdMk6CSWHanFcUdxXIZGKD9YpWIaVbUQ/4kfg=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200514094935-99fccaf93472/go.mod h1:LlFXPmgrgVYsuoFDwV8rDJ9tvt1pLQdjKvU1b5IRES0=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200728110133-0b6e349af87a/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200803113354-a18be873a4b6 h1:P440pnxSHIQI8gg7lQNNo+/F88EzUzS3Os0Xkhta7OQ=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200803113354-a18be873a4b6/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200818222714-826c7ef45b30 h1:Sbm5yhPObRc+RCZa9fAR/Px/j1qYwuqawF0X8dR2gAw=
|
||||
github.com/ferranbt/fastssz v0.0.0-20200818222714-826c7ef45b30/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
@@ -126,6 +135,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.13.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6 h1:8ERzHx8aj1Sc47mu9n/AksaKCSWrMchFtkdrS4BIj5o=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.7 h1:Nk5kuHrnWUTf/0GL1a/vchH/om9Ap2/HnVna+jYZgTY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.14.7/go.mod h1:oYZKL012gGh6LMyg/xA7Q2yq6j8bu0wa+9w14EEthWU=
|
||||
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=
|
||||
@@ -243,6 +254,8 @@ github.com/prysmaticlabs/ethereumapis v0.0.0-20200619200018-174e3b90d786 h1:bJiO
|
||||
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/ethereumapis v0.0.0-20200812153649-a842fc47c2c3 h1:0f++UXRfp4/Mrmlfj3UaCnYj2lPr6El0gWWTBb9MD2Y=
|
||||
github.com/prysmaticlabs/ethereumapis v0.0.0-20200812153649-a842fc47c2c3/go.mod h1:k7b2dxy6RppCG6kmOJkNOXzRpEoTdsPygc2aQhsUsZk=
|
||||
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=
|
||||
@@ -275,6 +288,8 @@ 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/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
|
||||
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
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=
|
||||
@@ -289,6 +304,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -328,16 +345,26 @@ github.com/wealdtech/go-eth2-util v1.3.0 h1:aX1+PnxB904GIf5JE9GRKYPuGQJsCT+Q7PG9
|
||||
github.com/wealdtech/go-eth2-util v1.3.0/go.mod h1:nSHpt/mdwn1LyLiNzjGPH1DDIYdBENLFaY1fSRr+aKg=
|
||||
github.com/wealdtech/go-eth2-util v1.5.0 h1:b3fgyvoq/WocW9LkWT7zcO5VCKzKLCc97rPrk/B9oIc=
|
||||
github.com/wealdtech/go-eth2-util v1.5.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk=
|
||||
github.com/wealdtech/go-eth2-util v1.6.0 h1:l2OR0SqfYdEnb1I1Ggnk0w+B9/LA5aHdQ2KK2FPnGkY=
|
||||
github.com/wealdtech/go-eth2-util v1.6.0/go.mod h1:0PGWeWWc6qjky/aNjdPdguJdZ2HSEHHCA+3cTjvT+Hk=
|
||||
github.com/wealdtech/go-eth2-wallet v1.10.2 h1:oUgi6Ih5fA9thhIipzXMSaLkiwDQXwT8q3bCOLpCr7s=
|
||||
github.com/wealdtech/go-eth2-wallet v1.10.2/go.mod h1:8H9pgp5K7X1kU1cJMS/B3DrMZF74ZlwBThownrcRYgk=
|
||||
github.com/wealdtech/go-eth2-wallet v1.11.0 h1:2KfrWDqF4sWGgk4N5+DaYmh0hOnqiCl0P4vCz5mx17U=
|
||||
github.com/wealdtech/go-eth2-wallet v1.11.0/go.mod h1:E9ZRNO4JNdi27ys7oc+xWWucXu4IGfV5q1vWC9X3oqg=
|
||||
github.com/wealdtech/go-eth2-wallet 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 v1.13.0 h1:ayy/jBcKVZhqU4OMlZDieRzhwSiF3Ozmc3e3LrdpWro=
|
||||
github.com/wealdtech/go-eth2-wallet v1.13.0/go.mod h1:O4efkfrSBRRa7Q8vZQ8usUCBRki+/zE531b3JqScIII=
|
||||
github.com/wealdtech/go-eth2-wallet v1.14.0 h1:eZjopWDMlCHCE9SLydAXBr0Cqtm2HWL3O56ELfeGK9c=
|
||||
github.com/wealdtech/go-eth2-wallet v1.14.0/go.mod h1:HrJ4hLcTPZPjhdkZKZd07OFxA+r7d3i+7XKjYJbxdxk=
|
||||
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-dirk v1.0.2 h1:ZxAdF6iTOzYHtQlWd1nzVevZ+HtXS/LLn580t+NXT3A=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.2/go.mod h1:5jK/aEAjYAVRBKKjYAvJWSmOWxiECs4asYXHwloNI+w=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.3 h1:NWwxzYjFG3k7S9mzVOvj02A5S9QOak4uh+MJF2Ae37w=
|
||||
github.com/wealdtech/go-eth2-wallet-dirk v1.0.3/go.mod h1:WIy6Xx0FgTNG5bP7IytxsEt8y1Yl46HbsWVFbE4Yc94=
|
||||
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=
|
||||
@@ -351,6 +378,10 @@ github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0 h1:L+yrAn8TC9DQUw+S7moOJxQTp2jr
|
||||
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-hd/v2 v2.4.0 h1:bqG/i1fpDpnQFgJ+NBLgOLdmGhXiinwlrFVD1OAgZlo=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.4.0/go.mod h1:xBbzc+aRD06dTL5phnMshpM4sryyWYM8m86sjQKG5u0=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.0 h1:OhJm7hn6vlO+dazs5S1EBrZu/ZVQUQcaNw1ncfy0/xI=
|
||||
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.0/go.mod h1:LfgcOnQeBcqBEoHd4VNqwZhwqzz0Xh1DqnDmjHWONGs=
|
||||
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=
|
||||
@@ -366,6 +397,8 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2 h1:a7GWfFd139CODvvkuTbRIuRwA
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2/go.mod h1:VWvXScZKUWHbhQpadLX8Yj+mc8U/i4zGthQJee+o3xg=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 h1:+q7p58NvOEfEDw8NgEoNaSG/s1eFHpyg91NEobA6RF0=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0/go.mod h1:OxYD+d79StAOHigNaI5bWuvjhanEyrD4MqTj8hIvt2Y=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.0 h1:O5211UskLbK1WDecTXwugUlINDBQ26MqtiFn6u66fmA=
|
||||
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.0/go.mod h1:dcQPLsRRYDiMV0DFYzTX6HRpP9WP+gWreAX5SLBOJ0I=
|
||||
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=
|
||||
@@ -380,6 +413,8 @@ github.com/wealdtech/go-eth2-wallet-types/v2 v2.5.0 h1:J29mbkSCUMl2xdu8Lg6U+JptF
|
||||
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-eth2-wallet-types/v2 v2.7.0 h1:pquFQdIWEiSYrpIpFuvsRuialI8t9KhFsPvbIBPnzic=
|
||||
github.com/wealdtech/go-eth2-wallet-types/v2 v2.7.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=
|
||||
@@ -406,6 +441,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnk
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899 h1:DZhuSZLsGlFL4CmhA8BcRA0mnthyA/nZ00AqCUo7vHg=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -446,6 +485,10 @@ golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYc
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc h1:zK/HqS5bZxDptfPJNq8v7vJfXtkU7r9TLIoSr1bXaP4=
|
||||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -478,6 +521,10 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae h1:Ih9Yo4hSPImZOpfGuA4bR/ORK
|
||||
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/sys v0.0.0-20200814200057-3d37ad5750ed h1:J22ig1FUekjjkmZUM7pTKixYm8DvrYsvrBZdunYeIuQ=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29 h1:mNuhGagCf3lDDm5C0376C/sxh6V7fy9WbdEu/YDNA04=
|
||||
golang.org/x/sys v0.0.0-20200821140526-fda516888d29/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=
|
||||
@@ -540,6 +587,10 @@ google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c h1:6DWnZZ6EY/59QRR
|
||||
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/genproto v0.0.0-20200814021100-8c09557e8a18 h1:hjnc4GP1IeBnHi+u3sp8be4ELyIHmFSO5p8DUdJUVt4=
|
||||
google.golang.org/genproto v0.0.0-20200814021100-8c09557e8a18/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70 h1:wboULUXGF3c5qdUnKp+6gLAccE6PRpa/czkYvQ4UXv8=
|
||||
google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/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=
|
||||
@@ -553,6 +604,8 @@ google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -574,6 +627,10 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.58.0 h1:VdDvTzv/005R8vEFyQ56bpEnOKTNPbpJhL0VCohxlQw=
|
||||
gopkg.in/ini.v1 v1.58.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.60.1 h1:P5y5shSkb0CFe44qEeMBgn8JLow09MP17jlJHanke5g=
|
||||
gopkg.in/ini.v1 v1.60.1/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=
|
||||
|
||||
@@ -287,8 +287,11 @@ func FetchBlock(conn *grpc.ClientConn, slot uint64) (*ethpb.SignedBeaconBlock, e
|
||||
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
|
||||
defer cancel()
|
||||
|
||||
req := ðpb.ListBlocksRequest{
|
||||
QueryFilter: ðpb.ListBlocksRequest_Slot{Slot: slot},
|
||||
req := ðpb.ListBlocksRequest{}
|
||||
if slot == 0 {
|
||||
req.QueryFilter = ðpb.ListBlocksRequest_Genesis{Genesis: true}
|
||||
} else {
|
||||
req.QueryFilter = ðpb.ListBlocksRequest_Slot{Slot: slot}
|
||||
}
|
||||
resp, err := beaconClient.ListBlocks(ctx, req)
|
||||
if err != nil {
|
||||
|
||||
282
util/depositinfo.go
Normal file
282
util/depositinfo.go
Normal file
@@ -0,0 +1,282 @@
|
||||
// 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 util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DepositInfo is a generic deposit structure.
|
||||
type DepositInfo struct {
|
||||
Name string
|
||||
Account string
|
||||
PublicKey []byte
|
||||
WithdrawalCredentials []byte
|
||||
Signature []byte
|
||||
DepositDataRoot []byte
|
||||
DepositMessageRoot []byte
|
||||
ForkVersion []byte
|
||||
Amount uint64
|
||||
Version uint64
|
||||
}
|
||||
|
||||
// depositInfoV1 is an ethdo V1 deposit structure.
|
||||
type depositInfoV1 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"`
|
||||
}
|
||||
|
||||
// depositInfoV3 is an ethdo V3 deposit structure.
|
||||
type depositInfoV3 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"`
|
||||
DepositMessageRoot string `json:"deposit_message_root"`
|
||||
ForkVersion string `json:"fork_version"`
|
||||
Amount uint64 `json:"amount"`
|
||||
Version uint64 `json:"version"`
|
||||
}
|
||||
|
||||
// depositInfoCLI is a deposit structure from the eth2 deposit CLI.
|
||||
type depositInfoCLI struct {
|
||||
PublicKey string `json:"pubkey"`
|
||||
WithdrawalCredentials string `json:"withdrawal_credentials"`
|
||||
Signature string `json:"signature"`
|
||||
DepositDataRoot string `json:"deposit_data_root"`
|
||||
DepositMessageRoot string `json:"deposit_message_root"`
|
||||
ForkVersion string `json:"fork_version"`
|
||||
Amount uint64 `json:"amount"`
|
||||
}
|
||||
|
||||
func DepositInfoFromJSON(input []byte) ([]*DepositInfo, error) {
|
||||
// Work out the type of data that we're dealing with, and decode it appropriately.
|
||||
depositInfo, err := tryRawTxData(input)
|
||||
if err != nil {
|
||||
depositInfo, err = tryV3DepositInfoFromJSON(input)
|
||||
if err != nil {
|
||||
depositInfo, err = tryV1DepositInfoFromJSON(input)
|
||||
if err != nil {
|
||||
depositInfo, err = tryCLIDepositInfoFromJSON(input)
|
||||
if err != nil {
|
||||
// Give up
|
||||
return nil, errors.New("unknown deposit data format")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(depositInfo) == 0 {
|
||||
return nil, errors.New("no deposits supplied")
|
||||
}
|
||||
|
||||
for i := range depositInfo {
|
||||
if len(depositInfo[i].PublicKey) == 0 {
|
||||
return nil, fmt.Errorf("no public key for deposit %d", i)
|
||||
}
|
||||
if len(depositInfo[i].DepositDataRoot) == 0 {
|
||||
return nil, fmt.Errorf("no data root for deposit %d", i)
|
||||
}
|
||||
if len(depositInfo[i].Signature) == 0 {
|
||||
return nil, fmt.Errorf("no signature for deposit %d", i)
|
||||
}
|
||||
if len(depositInfo[i].WithdrawalCredentials) == 0 {
|
||||
return nil, fmt.Errorf("no withdrawal credentials for deposit %d", i)
|
||||
}
|
||||
}
|
||||
return depositInfo, nil
|
||||
}
|
||||
|
||||
func tryV3DepositInfoFromJSON(data []byte) ([]*DepositInfo, error) {
|
||||
var depositData []*depositInfoV3
|
||||
err := json.Unmarshal(data, &depositData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
depositInfos := make([]*DepositInfo, len(depositData))
|
||||
for i, deposit := range depositData {
|
||||
if deposit.Version != 3 {
|
||||
return nil, errors.New("incorrect V3 deposit version")
|
||||
}
|
||||
publicKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("public key invalid")
|
||||
}
|
||||
withdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("withdrawal credentials invalid")
|
||||
}
|
||||
signature, err := hex.DecodeString(strings.TrimPrefix(deposit.Signature, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("signature invalid")
|
||||
}
|
||||
depositDataRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositDataRoot, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("deposit data root invalid")
|
||||
}
|
||||
depositMessageRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositMessageRoot, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("deposit message root invalid")
|
||||
}
|
||||
forkVersion, err := hex.DecodeString(strings.TrimPrefix(deposit.ForkVersion, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("fork version invalid")
|
||||
}
|
||||
depositInfos[i] = &DepositInfo{
|
||||
Name: deposit.Name,
|
||||
Account: deposit.Account,
|
||||
PublicKey: publicKey,
|
||||
WithdrawalCredentials: withdrawalCredentials,
|
||||
Signature: signature,
|
||||
DepositDataRoot: depositDataRoot,
|
||||
DepositMessageRoot: depositMessageRoot,
|
||||
ForkVersion: forkVersion,
|
||||
Amount: deposit.Amount,
|
||||
Version: 3,
|
||||
}
|
||||
}
|
||||
|
||||
return depositInfos, nil
|
||||
}
|
||||
|
||||
func tryCLIDepositInfoFromJSON(data []byte) ([]*DepositInfo, error) {
|
||||
var depositData []*depositInfoCLI
|
||||
err := json.Unmarshal(data, &depositData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
depositInfos := make([]*DepositInfo, len(depositData))
|
||||
for i, deposit := range depositData {
|
||||
publicKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("public key invalid")
|
||||
}
|
||||
withdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("withdrawal credentials invalid")
|
||||
}
|
||||
signature, err := hex.DecodeString(strings.TrimPrefix(deposit.Signature, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("signature invalid")
|
||||
}
|
||||
depositDataRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositDataRoot, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("deposit data root invalid")
|
||||
}
|
||||
depositMessageRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositMessageRoot, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("deposit message root invalid")
|
||||
}
|
||||
forkVersion, err := hex.DecodeString(strings.TrimPrefix(deposit.ForkVersion, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("fork version invalid")
|
||||
}
|
||||
depositInfos[i] = &DepositInfo{
|
||||
PublicKey: publicKey,
|
||||
WithdrawalCredentials: withdrawalCredentials,
|
||||
Signature: signature,
|
||||
DepositDataRoot: depositDataRoot,
|
||||
DepositMessageRoot: depositMessageRoot,
|
||||
ForkVersion: forkVersion,
|
||||
Amount: deposit.Amount,
|
||||
Version: 3,
|
||||
}
|
||||
}
|
||||
|
||||
return depositInfos, nil
|
||||
}
|
||||
|
||||
func tryV1DepositInfoFromJSON(data []byte) ([]*DepositInfo, error) {
|
||||
var depositData []*depositInfoV1
|
||||
err := json.Unmarshal(data, &depositData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
depositInfos := make([]*DepositInfo, len(depositData))
|
||||
for i, deposit := range depositData {
|
||||
if deposit.Version < 1 || deposit.Version > 2 {
|
||||
return nil, errors.New("incorrect deposit version")
|
||||
}
|
||||
publicKey, err := hex.DecodeString(strings.TrimPrefix(deposit.PublicKey, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("public key invalid")
|
||||
}
|
||||
withdrawalCredentials, err := hex.DecodeString(strings.TrimPrefix(deposit.WithdrawalCredentials, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("withdrawal credentials invalid")
|
||||
}
|
||||
signature, err := hex.DecodeString(strings.TrimPrefix(deposit.Signature, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("signature invalid")
|
||||
}
|
||||
depositDataRoot, err := hex.DecodeString(strings.TrimPrefix(deposit.DepositDataRoot, "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("deposit data root invalid")
|
||||
}
|
||||
depositInfos[i] = &DepositInfo{
|
||||
Name: deposit.Name,
|
||||
Account: deposit.Account,
|
||||
PublicKey: publicKey,
|
||||
WithdrawalCredentials: withdrawalCredentials,
|
||||
Signature: signature,
|
||||
DepositDataRoot: depositDataRoot,
|
||||
Amount: deposit.Value,
|
||||
Version: 3,
|
||||
}
|
||||
}
|
||||
|
||||
return depositInfos, nil
|
||||
}
|
||||
|
||||
func tryRawTxData(data []byte) ([]*DepositInfo, error) {
|
||||
txData, err := hex.DecodeString(strings.TrimPrefix(string(data), "0x"))
|
||||
if err != nil {
|
||||
return nil, errors.New("public key invalid")
|
||||
}
|
||||
|
||||
depositInfos := make([]*DepositInfo, 1)
|
||||
|
||||
if len(txData) != 420 {
|
||||
return nil, errors.New("invalid transaction length")
|
||||
}
|
||||
if !bytes.Equal(txData[0:4], []byte{0x22, 0x89, 0x51, 0x18}) {
|
||||
return nil, errors.New("invalid function signature")
|
||||
}
|
||||
|
||||
depositInfos[0] = &DepositInfo{
|
||||
PublicKey: txData[164:212],
|
||||
WithdrawalCredentials: txData[260:292],
|
||||
Signature: txData[324:420],
|
||||
DepositDataRoot: txData[100:132],
|
||||
}
|
||||
|
||||
return depositInfos, nil
|
||||
}
|
||||
Reference in New Issue
Block a user