Compare commits

...

24 Commits

Author SHA1 Message Date
Jim McDonald
6551db8f9a Updates for v0.11 2020-04-15 14:27:42 +01:00
Jim McDonald
d0f944eacc Merge functionality for v0.11 2020-04-15 08:37:55 +01:00
Jim McDonald
be3fd8edd2 Use 0.11 style domains 2020-04-09 21:03:10 +01:00
Jim McDonald
afcbd177a3 Tidy-ups 2020-04-08 10:20:51 +01:00
Jim McDonald
a38ff57508 Add remote access 2020-03-31 11:31:54 +01:00
Jim McDonald
7d4ead9640 Add node info and block info commands 2020-03-27 15:19:55 +00:00
Jim McDonald
945f2ca47c Add slot/epoch option for chain status 2020-03-12 19:52:38 +00:00
Jim McDonald
b61eaefb0d Add chain status 2020-03-12 15:32:01 +00:00
Jim McDonald
6786742004 Add more chain information 2020-03-12 13:47:27 +00:00
Jim McDonald
6cb8886672 Merge branch 'master' of github.com:wealdtech/ethdo 2020-03-12 13:39:52 +00:00
Jim McDonald
ab5c6317ca Add chain info command 2020-03-12 13:39:41 +00:00
Jim McDonald
5896579496 Update install doc 2020-03-03 17:28:20 +00:00
Jim McDonald
8df1b74a79 Use unix format for displaying date/time 2020-02-25 11:55:48 +00:00
Jim McDonald
47cdd8402a Additional documentation 2020-02-19 00:03:21 +00:00
Jim McDonald
432967c14c Fixes for validator info 2020-02-14 21:26:07 +00:00
Jim McDonald
36033d66d2 Add ability to query with public key 2020-02-14 18:13:26 +00:00
Jim McDonald
0b354c3ec5 Testing 2020-02-13 15:21:07 +00:00
Jim McDonald
b3e6178149 Add validator info command 2020-02-13 14:37:32 +00:00
Jim McDonald
12bd0e303f Add store type and location to wallet information where possible 2020-02-08 23:57:34 +00:00
Jim McDonald
502d9a9bd0 Update dependencies 2020-02-07 14:12:08 +00:00
Jim McDonald
6f863bce9a Allow creation of multiple validator deposits in one command 2020-02-06 15:10:50 +00:00
Jim McDonald
d1d54989c2 Add voluntary exit 2020-02-05 13:04:09 +00:00
Jim McDonald
eb813475c0 Add voluntary exit 2020-01-29 23:45:40 +00:00
Jim McDonald
93e828f256 Update dependencies 2020-01-13 21:15:11 +00:00
35 changed files with 2008 additions and 304 deletions

View File

@@ -21,7 +21,7 @@ A command-line tool for managing common tasks in Ethereum 2.
`ethdo` is a standard Go program which can be installed with:
```sh
go get github.com/wealdtech/ethdo
GO111MODULE=on go get github.com/wealdtech/ethdo
```
## Usage
@@ -200,7 +200,7 @@ Public key: 0x8e2f9e8cc29658ff37ecc30e95a0807579b224586c185d128cb7a7490784c1ad9b
Signature commands focus on generation and verification of data signatures.
### `signature sign`
#### `signature sign`
`ethdo signature sign` signs provided data. Options include:
- `data`: the data to sign, as a hex string
@@ -213,7 +213,7 @@ $ ethdo signature sign --data="0x08140077a94642919041503caf5cc1795b23ecf2" --acc
0x89abe2e544ef3eafe397db036103b1d066ba86497f36ed4ab0264162eadc89c7744a2a08d43cec91df128660e70ecbbe11031b4c2e53682d2b91e67b886429bf8fac9bad8c7b63c5f231cc8d66b1377e06e27138b1ddc64b27c6e593e07ebb4b
```
### `signature verify`
#### `signature verify`
`ethdo signature verify` verifies signed data. Options include:
- `data`: the data whose signature to verify, as a hex string
@@ -241,6 +241,55 @@ $ ethdo version
1.0.0
```
### `validator` commands
Validator commands focus on interaction with Ethereum 2 validators.
#### `depositdata`
`validator depositdata` generates the data required to deposit one or more Ethereum 2 validators.
#### `exit`
`validator exit` sends a transaction to the chain to tell an active validator to exit the validation queue.
```sh
$ ethdo validator exit --account=Validators/1 --passphrase="my validator secret"
```
#### `info`
`validator info` provides information for a given validator.
```sh
$ ethdo validator info --account=Validators/1
Status: Active
Balance: 3.203823585 Ether
Effective balance: 3.1 Ether
```
Additional information is supplied when using `--verbose`
```sh
$ ethdo validator info --account=Validators/1 --verbose
Epoch of data: 3398
Index: 26913
Public key: 0xb3bb6b7a8d809e59544472853d219499765bf01d14de1e0549bd6fc2a86627ac9033264c84cd503b6339e3334726562f
Status: Active
Balance: 3.204026813 Ether
Effective balance: 3.1 Ether
Withdrawal credentials: 0x0033ef3cb10b36d0771ffe8a02bc5bfc7e64ea2f398ce77e25bb78989edbee36
```
If the validator is not an account it can be queried directly with `--pubkey`.
```sh
$ ethdo validator info --pubkey=0x842dd66cfeaeff4397fc7c94f7350d2131ca0c4ad14ff727963be9a1edb4526604970df6010c3da6474a9820fa81642b
Status: Active
Balance: 3.201850307 Ether
Effective balance: 3.1 Ether
```
## Maintainers
Jim McDonald: [@mcdee](https://github.com/mcdee).
@@ -251,5 +300,5 @@ Contributions welcome. Please check out [the issues](https://github.com/wealdtec
## License
[Apache-2.0](LICENSE) © 2019 Weald Technology Trading Ltd
[Apache-2.0](LICENSE) © 2019, 2020 Weald Technology Trading Ltd

View File

@@ -29,6 +29,7 @@ var accountCreateCmd = &cobra.Command{
In quiet mode this will return 0 if the account is created successfully, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "account create not available with remote wallets")
assert(rootAccount != "", "--account is required")
assert(rootAccountPassphrase != "", "--passphrase is required")
@@ -51,7 +52,7 @@ In quiet mode this will return 0 if the account is created successfully, otherwi
errCheck(err, "Failed to create account")
outputIf(verbose, fmt.Sprintf("0x%048x", account.PublicKey().Marshal()))
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -19,7 +19,7 @@ import (
"github.com/spf13/cobra"
"github.com/wealdtech/go-bytesutil"
types "github.com/wealdtech/go-eth2-wallet-types"
types "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var accountImportKey string
@@ -33,6 +33,7 @@ var accountImportCmd = &cobra.Command{
In quiet mode this will return 0 if the account is imported successfully, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "account import not available with remote wallets")
assert(rootAccount != "", "--account is required")
assert(rootAccountPassphrase != "", "--passphrase is required")
assert(accountImportKey != "", "--key is required")
@@ -59,7 +60,7 @@ In quiet mode this will return 0 if the account is imported successfully, otherw
errCheck(err, "Failed to create account")
outputIf(verbose, fmt.Sprintf("0x%048x", account.PublicKey().Marshal()))
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -1,4 +1,4 @@
// Copyright © 2019 Weald Technology Trading
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -14,10 +14,12 @@
package cmd
import (
"context"
"fmt"
"os"
"github.com/spf13/cobra"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
)
var accountInfoCmd = &cobra.Command{
@@ -31,13 +33,28 @@ 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")
account, err := accountFromPath(rootAccount)
errCheck(err, "Failed to access wallet")
if remote {
listerClient := pb.NewListerClient(remoteGRPCConn)
listAccountsReq := &pb.ListAccountsRequest{
Paths: []string{
rootAccount,
},
}
resp, err := listerClient.ListAccounts(context.Background(), listAccountsReq)
errCheck(err, "Failed to access account")
assert(resp.State == pb.ResponseState_SUCCEEDED, "No such account")
assert(len(resp.Accounts) == 1, "No such account")
fmt.Printf("Public key: %#048x\n", resp.Accounts[0].PublicKey)
outputIf(verbose, fmt.Sprintf("UUID: %v", account.ID()))
outputIf(!quiet, fmt.Sprintf("Public key: %#048x", account.PublicKey().Marshal()))
outputIf(verbose && account.Path() != "", fmt.Sprintf("Path: %s", account.Path()))
os.Exit(_exit_success)
} 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(verbose && account.Path() != "", fmt.Sprintf("Path: %s", account.Path()))
}
os.Exit(_exitSuccess)
},
}

View File

@@ -18,7 +18,7 @@ import (
"os"
"github.com/spf13/cobra"
types "github.com/wealdtech/go-eth2-wallet-types"
types "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// accountKeyCmd represents the account key command
@@ -31,7 +31,9 @@ var accountKeyCmd = &cobra.Command{
In quiet mode this will return 0 if the key can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "account keys not available with remote wallets")
assert(rootAccount != "", "--account is required")
account, err := accountFromPath(rootAccount)
errCheck(err, "Failed to access account")
@@ -47,7 +49,7 @@ In quiet mode this will return 0 if the key can be obtained, otherwise 1.`,
account.Lock()
outputIf(!quiet, fmt.Sprintf("%#064x", privateKey.Marshal()))
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

60
cmd/accountlock.go Normal file
View File

@@ -0,0 +1,60 @@
// 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"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
)
var accountLockCmd = &cobra.Command{
Use: "lock",
Short: "Lock a remote account",
Long: `Lock a remote account. For example:
ethdo account lock --account="primary/my funds"
In quiet mode this will return 0 if the account is locked, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(remote, "account lock only works with remote wallets")
assert(rootAccount != "", "--account is required")
client := pb.NewAccountManagerClient(remoteGRPCConn)
lockReq := &pb.LockAccountRequest{
Account: rootAccount,
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
resp, err := client.Lock(ctx, lockReq)
errCheck(err, "Failed in attempt to lock account")
switch resp.State {
case pb.ResponseState_DENIED:
die("Lock request denied")
case pb.ResponseState_FAILED:
die("Lock request failed")
case pb.ResponseState_SUCCEEDED:
outputIf(!quiet, "Lock request succeeded")
os.Exit(_exitSuccess)
}
},
}
func init() {
accountCmd.AddCommand(accountLockCmd)
accountFlags(accountLockCmd)
}

61
cmd/accountunlock.go Normal file
View File

@@ -0,0 +1,61 @@
// 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"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
)
var accountUnlockCmd = &cobra.Command{
Use: "unlock",
Short: "Unlock a remote account",
Long: `Unlock a remote account. For example:
ethdo account unlock --account="primary/my funds" --passphrase="secret"
In quiet mode this will return 0 if the account is unlocked, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(remote, "account unlock only works with remote wallets")
assert(rootAccount != "", "--account is required")
client := pb.NewAccountManagerClient(remoteGRPCConn)
unlockReq := &pb.UnlockAccountRequest{
Account: rootAccount,
Passphrase: []byte(rootAccountPassphrase),
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
resp, err := client.Unlock(ctx, unlockReq)
errCheck(err, "Failed in attempt to unlock account")
switch resp.State {
case pb.ResponseState_DENIED:
die("Unlock request denied")
case pb.ResponseState_FAILED:
die("Unlock request failed")
case pb.ResponseState_SUCCEEDED:
outputIf(!quiet, "Unlock request succeeded")
os.Exit(_exitSuccess)
}
},
}
func init() {
accountCmd.AddCommand(accountUnlockCmd)
accountFlags(accountUnlockCmd)
}

32
cmd/block.go Normal file
View 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"
)
// blockCmd represents the block command
var blockCmd = &cobra.Command{
Use: "block",
Short: "Obtain information about an Ethereum 2 block",
Long: "Obtain information about an Ethereum 2 block",
}
func init() {
RootCmd.AddCommand(blockCmd)
}
func blockFlags(cmd *cobra.Command) {
}

237
cmd/blockinfo.go Normal file
View File

@@ -0,0 +1,237 @@
// 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 (
"bytes"
"fmt"
"os"
"sort"
"strings"
"unicode/utf8"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/grpc"
string2eth "github.com/wealdtech/go-string2eth"
)
var blockInfoSlot int64
var blockInfoCmd = &cobra.Command{
Use: "info",
Short: "Obtain information about a block",
Long: `Obtain information about a block. For example:
ethdo block info --slot=12345
In quiet mode this will return 0 if the block information is present and not skipped, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain block")
assert(blockInfoSlot != 0, "--slot is required")
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.
outputIf(verbose, fmt.Sprintf("Parent root: %#x", block.ParentRoot))
outputIf(verbose, fmt.Sprintf("State root: %#x", block.StateRoot))
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
fmt.Printf("Ethereum 1 deposit count: %d\n", 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\n", countSetBits(att.AggregationBits))
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 {
fmt.Printf("\t%d:\n", i)
// Say what was slashed.
att1 := slashing.Attestation_1
att2 := slashing.Attestation_2
slashedIndices := intersection(att1.AttestingIndices, att2.AttestingIndices)
if len(slashedIndices) == 0 {
continue
}
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)
}
}
os.Exit(_exitSuccess)
},
}
// 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] })
sort.Slice(set2, func(i, j int) bool { return set2[i] < set2[j] })
res := make([]uint64, 0)
if len(set1) < len(set2) {
set1, set2 = set2, set1
}
set2Pos := 0
set2LastIndex := len(set2) - 1
for set1Pos := range set1 {
for set1[set1Pos] == set2[set2Pos] {
res = append(res, set1[set1Pos])
if set2Pos == set2LastIndex {
break
}
set2Pos++
}
for set1[set1Pos] > set2[set2Pos] {
if set2Pos == set2LastIndex {
break
}
set2Pos++
}
}
return res
}
// countSetBits counts the number of bits that are set in the given byte array.
func countSetBits(input []byte) int {
total := 0
for _, x := range input {
item := uint8(x)
for item > 0 {
if item&0x01 == 1 {
total++
}
item >>= 1
}
}
return total
}
func bitsToString(input []byte) string {
elements := make([]string, len(input))
for i, x := range input {
item := uint8(x)
mask := uint8(0x80)
element := ""
for mask > 0 {
if item&mask != 0 {
element = fmt.Sprintf("%s✓", element)
} else {
element = fmt.Sprintf("%s✕", element)
}
mask >>= 1
}
elements[i] = element
}
return strings.Join(elements, " ")
}
func init() {
blockCmd.AddCommand(blockInfoCmd)
blockFlags(blockInfoCmd)
blockInfoCmd.Flags().Int64Var(&blockInfoSlot, "slot", -1, "the default slot")
}

32
cmd/chain.go Normal file
View 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"
)
// chainCmd represents the chain command
var chainCmd = &cobra.Command{
Use: "chain",
Short: "Obtain information about an Ethereum 2 chain",
Long: "Obtain information about an Ethereum 2 chain",
}
func init() {
RootCmd.AddCommand(chainCmd)
}
func chainFlags(cmd *cobra.Command) {
}

69
cmd/chaininfo.go Normal file
View File

@@ -0,0 +1,69 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"time"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/grpc"
)
var chainInfoCmd = &cobra.Command{
Use: "info",
Short: "Obtain information about a chain",
Long: `Obtain information about a chain. For example:
ethdo chain info
In quiet mode this will return 0 if the chain information can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
config, err := grpc.FetchChainConfig(eth2GRPCConn)
errCheck(err, "Failed to obtain beacon chain configuration")
genesisTime, err := grpc.FetchGenesis(eth2GRPCConn)
errCheck(err, "Failed to obtain genesis time")
if quiet {
os.Exit(_exitSuccess)
}
fmt.Printf("Genesis time:\t\t%s\n", genesisTime.Format(time.UnixDate))
slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64))
fmt.Printf("Current slot:\t\t%d\n", slot)
fmt.Printf("Current epoch:\t\t%d\n", slot/config["SlotsPerEpoch"].(uint64))
outputIf(verbose, fmt.Sprintf("Genesis fork version:\t%0x", config["GenesisForkVersion"].([]byte)))
outputIf(verbose, fmt.Sprintf("Genesis timestamp:\t%v", genesisTime.Unix()))
outputIf(verbose, fmt.Sprintf("Seconds per slot:\t%v", config["SecondsPerSlot"].(uint64)))
outputIf(verbose, fmt.Sprintf("Slots per epoch:\t%v", config["SlotsPerEpoch"].(uint64)))
os.Exit(_exitSuccess)
},
}
func init() {
chainCmd.AddCommand(chainInfoCmd)
chainFlags(chainInfoCmd)
}
func timestampToSlot(genesis int64, timestamp int64, secondsPerSlot uint64) uint64 {
if timestamp < genesis {
return 0
}
return uint64(timestamp-genesis) / secondsPerSlot
}

94
cmd/chainstatus.go Normal file
View File

@@ -0,0 +1,94 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"time"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/grpc"
)
var chainStatusSlot bool
var chainStatusCmd = &cobra.Command{
Use: "status",
Short: "Obtain status about a chain",
Long: `Obtain status about a chain. For example:
ethdo chain status
In quiet mode this will return 0 if the chain status can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
config, err := grpc.FetchChainConfig(eth2GRPCConn)
errCheck(err, "Failed to obtain beacon chain configuration")
genesisTime, err := grpc.FetchGenesis(eth2GRPCConn)
errCheck(err, "Failed to obtain genesis time")
info, err := grpc.FetchChainInfo(eth2GRPCConn)
errCheck(err, "Failed to obtain chain info")
if quiet {
os.Exit(_exitSuccess)
}
slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64))
if chainStatusSlot {
fmt.Printf("Current slot:\t\t%d\n", slot)
fmt.Printf("Justified slot:\t\t%d", info.GetJustifiedSlot())
if verbose {
distance := slot - info.GetJustifiedSlot()
fmt.Printf(" (%d)", distance)
}
fmt.Printf("\n")
fmt.Printf("Finalized slot:\t\t%d", info.GetFinalizedSlot())
if verbose {
distance := slot - info.GetFinalizedSlot()
fmt.Printf(" (%d)", distance)
}
fmt.Printf("\n")
outputIf(verbose, fmt.Sprintf("Prior justified slot:\t%v (%d)", info.GetPreviousJustifiedSlot(), slot-info.GetPreviousJustifiedSlot()))
} else {
slotsPerEpoch := config["SlotsPerEpoch"].(uint64)
fmt.Printf("Current epoch:\t\t%d\n", slot/slotsPerEpoch)
fmt.Printf("Justified epoch:\t%d", info.GetJustifiedSlot()/slotsPerEpoch)
if verbose {
distance := (slot - info.GetJustifiedSlot()) / slotsPerEpoch
fmt.Printf(" (%d)", distance)
}
fmt.Printf("\n")
fmt.Printf("Finalized epoch:\t%d", info.GetFinalizedSlot()/slotsPerEpoch)
if verbose {
distance := (slot - info.GetFinalizedSlot()) / slotsPerEpoch
fmt.Printf(" (%d)", distance)
}
fmt.Printf("\n")
outputIf(verbose, fmt.Sprintf("Prior justified epoch:\t%v (%d)", info.GetPreviousJustifiedSlot()/slotsPerEpoch, (slot-info.GetPreviousJustifiedSlot())/slotsPerEpoch))
}
os.Exit(_exitSuccess)
},
}
func init() {
chainCmd.AddCommand(chainStatusCmd)
chainFlags(chainStatusCmd)
chainStatusCmd.Flags().BoolVar(&chainStatusSlot, "slot", false, "Print slot-based values")
}

View File

@@ -14,6 +14,6 @@
package cmd
const (
_exit_success = 0
_exit_failure = 1
_exitSuccess = 0
_exitFailure = 1
)

32
cmd/node.go Normal file
View 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"
)
// nodeCmd represents the node command
var nodeCmd = &cobra.Command{
Use: "node",
Short: "Obtain information about an Ethereum 2 node",
Long: "Obtain information about an Ethereum 2 node",
}
func init() {
RootCmd.AddCommand(nodeCmd)
}
func nodeFlags(cmd *cobra.Command) {
}

74
cmd/nodeinfo.go Normal file
View File

@@ -0,0 +1,74 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"os"
"time"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/grpc"
)
var nodeInfoCmd = &cobra.Command{
Use: "info",
Short: "Obtain information about a node",
Long: `Obtain information about a node. For example:
ethdo node info
In quiet mode this will return 0 if the node information can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
config, err := grpc.FetchChainConfig(eth2GRPCConn)
errCheck(err, "Failed to obtain beacon chain configuration")
genesisTime, err := grpc.FetchGenesis(eth2GRPCConn)
errCheck(err, "Failed to obtain genesis time")
if quiet {
os.Exit(_exitSuccess)
}
if verbose {
version, metadata, err := grpc.FetchVersion(eth2GRPCConn)
errCheck(err, "Failed to obtain version")
fmt.Printf("Version:\t\t%s\n", version)
if metadata != "" {
fmt.Printf("Metadata:\t%s\n", metadata)
}
}
syncing, err := grpc.FetchSyncing(eth2GRPCConn)
errCheck(err, "Failed to obtain syncing state")
fmt.Printf("Syncing:\t\t%v\n", syncing)
fmt.Printf("Genesis time:\t\t%s\n", genesisTime.Format(time.UnixDate))
slot := timestampToSlot(genesisTime.Unix(), time.Now().Unix(), config["SecondsPerSlot"].(uint64))
fmt.Printf("Current slot:\t\t%d\n", slot)
fmt.Printf("Current epoch:\t\t%d\n", slot/config["SlotsPerEpoch"].(uint64))
outputIf(verbose, fmt.Sprintf("Genesis fork version:\t%0x", config["GenesisForkVersion"].([]byte)))
outputIf(verbose, fmt.Sprintf("Genesis timestamp:\t%v", genesisTime.Unix()))
outputIf(verbose, fmt.Sprintf("Seconds per slot:\t%v", config["SecondsPerSlot"].(uint64)))
outputIf(verbose, fmt.Sprintf("Slots per epoch:\t%v", config["SlotsPerEpoch"].(uint64)))
os.Exit(_exitSuccess)
},
}
func init() {
nodeCmd.AddCommand(nodeInfoCmd)
nodeFlags(nodeInfoCmd)
}

View File

@@ -14,18 +14,28 @@
package cmd
import (
"errors"
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"regexp"
"sort"
"strings"
"time"
homedir "github.com/mitchellh/go-homedir"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
"github.com/spf13/viper"
types "github.com/wealdtech/go-eth2-types"
e2types "github.com/wealdtech/go-eth2-types/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
wallet "github.com/wealdtech/go-eth2-wallet"
wtypes "github.com/wealdtech/go-eth2-wallet-types"
wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var cfgFile string
@@ -33,13 +43,28 @@ var quiet bool
var verbose bool
var debug bool
// Root variables, present for all commands
// For transaction commands.
var wait bool
var generate bool
// Root variables, present for all commands.
var rootStore string
var rootAccount string
var rootStorePassphrase string
var rootWalletPassphrase string
var rootAccountPassphrase string
// Remote connection.
var remote bool
var remoteAddr string
var clientCert string
var clientKey string
var serverCACert string
var remoteGRPCConn *grpc.ClientConn
// Prysm connection.
var eth2GRPCConn *grpc.ClientConn
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "ethdo",
@@ -69,16 +94,38 @@ 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")
}
if quiet && debug {
die("Cannot supply both quiet and debug flags")
}
if generate && wait {
die("Cannot supply both generate and wait flags")
}
// Set up our wallet store
err := wallet.SetStore(rootStore, []byte(rootStorePassphrase))
errCheck(err, "Failed to set up wallet store")
if viper.GetString("remote") == "" {
// Set up our wallet store
err := wallet.SetStore(rootStore, []byte(rootStorePassphrase))
errCheck(err, "Failed to set up wallet store")
} else {
err := initRemote()
errCheck(err, "Failed to connect to remote wallet")
}
}
// Execute adds all child commands to the root command and sets flags appropriately.
@@ -86,11 +133,17 @@ func persistentPreRun(cmd *cobra.Command, args []string) {
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(_exit_failure)
os.Exit(_exitFailure)
}
}
func init() {
// Initialise our BLS library.
if err := e2types.InitBLS(); err != nil {
fmt.Println(err)
os.Exit(_exitFailure)
}
cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.ethdo.yaml)")
@@ -130,6 +183,30 @@ func init() {
if err := viper.BindPFlag("debug", RootCmd.PersistentFlags().Lookup("debug")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().String("connection", "localhost:4000", "connection to Ethereum 2 node via GRPC")
if err := viper.BindPFlag("connection", RootCmd.PersistentFlags().Lookup("connection")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().Duration("timeout", 10*time.Second, "the time after which a network request will be considered failed. Increase this if you are running on an error-prone, high-latency or low-bandwidth connection")
if err := viper.BindPFlag("timeout", RootCmd.PersistentFlags().Lookup("timeout")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().String("remote", "", "connection to a remote wallet daemon")
if err := viper.BindPFlag("remote", RootCmd.PersistentFlags().Lookup("remote")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().String("client-cert", "", "location of a client certificate file when connecting to the remote wallet daemon")
if err := viper.BindPFlag("client-cert", RootCmd.PersistentFlags().Lookup("client-cert")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().String("client-key", "", "location of a client key file when connecting to the remote wallet daemon")
if err := viper.BindPFlag("client-key", RootCmd.PersistentFlags().Lookup("client-key")); err != nil {
panic(err)
}
RootCmd.PersistentFlags().String("server-ca-cert", "", "location of the server certificate authority certificate when connecting to the remote wallet daemon")
if err := viper.BindPFlag("server-ca-cert", RootCmd.PersistentFlags().Lookup("server-ca-cert")); err != nil {
panic(err)
}
}
// initConfig reads in config file and ENV variables if set.
@@ -140,10 +217,7 @@ func initConfig() {
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(_exit_failure)
}
errCheck(err, "could not find home directory")
// Search config in home directory with name ".ethdo" (without extension).
viper.AddConfigPath(home)
@@ -156,10 +230,7 @@ func initConfig() {
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err != nil {
// Don't report lack of config file...
if !strings.Contains(err.Error(), "Not Found") {
fmt.Println(err)
os.Exit(_exit_failure)
}
assert(strings.Contains(err.Error(), "Not Found"), "failed to read configuration")
}
}
@@ -230,17 +301,154 @@ func accountFromPath(path string) (wtypes.Account, error) {
return wallet.AccountByName(accountName)
}
func sign(path string, data []byte, domain uint64) (types.Signature, error) {
assert(rootAccountPassphrase != "", "--passphrase is required")
// accountsFromPath obtains 0 or more accounts given a path specification.
func accountsFromPath(path string) ([]wtypes.Account, error) {
accounts := make([]wtypes.Account, 0)
// Quick check to see if it's a single account
account, err := accountFromPath(path)
if err == nil && account != nil {
accounts = append(accounts, account)
return accounts, nil
}
wallet, err := walletFromPath(path)
if err != nil {
return nil, err
}
err = account.Unlock([]byte(rootAccountPassphrase))
_, accountSpec, err := walletAndAccountNamesFromPath(path)
if err != nil {
return nil, err
}
defer account.Lock()
return account.Sign(data, domain)
if accountSpec == "" {
accountSpec = "^.*$"
} else {
accountSpec = fmt.Sprintf("^%s$", accountSpec)
}
re := regexp.MustCompile(accountSpec)
for account := range wallet.Accounts() {
if re.Match([]byte(account.Name())) {
accounts = append(accounts, account)
}
}
// Tidy up accounts by name.
sort.Slice(accounts, func(i, j int) bool {
return accounts[i].Name() < accounts[j].Name()
})
return accounts, nil
}
// signStruct signs an arbitrary structure.
func signStruct(account wtypes.Account, data interface{}, domain []byte) (e2types.Signature, error) {
objRoot, err := ssz.HashTreeRoot(data)
outputIf(debug, fmt.Sprintf("Object root is %x", objRoot))
if err != nil {
return nil, err
}
return signRoot(account, objRoot, domain)
}
// SigningContainer is the container for signing roots with a domain.
// Contains SSZ sizes to allow for correct calculation of root.
type SigningContainer struct {
Root []byte `ssz-size:"32"`
Domain []byte `ssz-size:"32"`
}
// signRoot signs a root.
func signRoot(account wtypes.Account, root [32]byte, domain []byte) (e2types.Signature, error) {
container := &SigningContainer{
Root: root[:],
Domain: domain,
}
outputIf(debug, fmt.Sprintf("Signing container:\n\troot: %x\n\tdomain: %x", container.Root, container.Domain))
signingRoot, err := ssz.HashTreeRoot(container)
if err != nil {
return nil, err
}
outputIf(debug, fmt.Sprintf("Signing root: %x", signingRoot))
return sign(account, signingRoot[:])
}
// sign signs arbitrary data.
func sign(account wtypes.Account, data []byte) (e2types.Signature, error) {
if !account.IsUnlocked() {
return nil, errors.New("account must be unlocked to sign")
}
outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data)))
return account.Sign(data)
}
// 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 := ""
if viper.GetString("connection") != "" {
connection = viper.GetString("connection")
}
if connection == "" {
return errors.New("no connection")
}
outputIf(debug, fmt.Sprintf("Connecting to %s", connection))
opts := []grpc.DialOption{grpc.WithInsecure()}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
var err error
eth2GRPCConn, err = grpc.DialContext(ctx, connection, opts...)
return err
}
func initRemote() error {
remote = true
remoteAddr = viper.GetString("remote")
clientCert = viper.GetString("client-cert")
clientKey = viper.GetString("client-key")
serverCACert = viper.GetString("server-ca-cert")
// Load the client certificates.
clientPair, err := tls.LoadX509KeyPair(clientCert, clientKey)
if err != nil {
return errors.Wrap(err, "failed to access client certificate/key")
}
tlsCfg := &tls.Config{
Certificates: []tls.Certificate{clientPair},
}
if serverCACert != "" {
// Load the CA for the server certificate.
serverCA, err := ioutil.ReadFile(serverCACert)
if err != nil {
return errors.Wrap(err, "failed to access CA certificate")
}
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM(serverCA) {
return errors.Wrap(err, "failed to add CA certificate")
}
tlsCfg.RootCAs = cp
}
clientCreds := credentials.NewTLS(tlsCfg)
opts := []grpc.DialOption{
// Require TLS.
grpc.WithTransportCredentials(clientCreds),
// Block until server responds.
grpc.WithBlock(),
}
remoteGRPCConn, err = grpc.Dial(remoteAddr, opts...)
return err
}

View File

@@ -1,4 +1,4 @@
// Copyright © 2017-2019 Weald Technology Trading
// Copyright © 2017-2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -14,48 +14,77 @@
package cmd
import (
"context"
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/spf13/viper"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
"github.com/wealdtech/go-bytesutil"
types "github.com/wealdtech/go-eth2-types"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
// signatureSignCmd represents the signature sign command
var signatureSignCmd = &cobra.Command{
Use: "sign",
Short: "Sign data",
Short: "Sign a 32-byte piece of data",
Long: `Sign presented data. For example:
ethereal signature sign --data="0x5FfC014343cd971B7eb70732021E26C35B744cc4" --account="Personal wallet/Operations" --passphrase="my account passphrase"
ethereal signature sign --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --account="Personal wallet/Operations" --passphrase="my account passphrase"
In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(signatureData != "", "--data is required")
data, err := bytesutil.FromHexString(signatureData)
errCheck(err, "Failed to parse data")
assert(len(data) == 32, "data to sign must be 32 bytes")
domain := types.Domain([]byte{0, 0, 0, 0}, []byte{0, 0, 0, 0})
domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
if signatureDomain != "" {
domainBytes, err := bytesutil.FromHexString(signatureDomain)
errCheck(err, "Failed to parse domain")
assert(len(domainBytes) == 8, "Domain data invalid")
assert(len(domainBytes) == 32, "Domain data invalid")
domain = domainBytes
}
assert(rootAccount != "", "--account is required")
account, err := accountFromPath(rootAccount)
errCheck(err, "Failed to access account for signing")
err = account.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock account for signing")
defer account.Lock()
signature, err := account.Sign(data, domain)
errCheck(err, "Failed to sign data")
var signature e2types.Signature
if remote {
signClient := pb.NewSignerClient(remoteGRPCConn)
signReq := &pb.SignRequest{
Id: &pb.SignRequest_Account{Account: rootAccount},
Data: data,
Domain: domain,
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
resp, err := signClient.Sign(ctx, signReq)
errCheck(err, "Failed to sign")
switch resp.State {
case pb.ResponseState_DENIED:
die("Signing request denied")
case pb.ResponseState_FAILED:
die("Signing request failed")
case pb.ResponseState_SUCCEEDED:
signature, err = e2types.BLSSignatureFromBytes(resp.Signature)
errCheck(err, "Invalid signature")
}
} else {
account, err := accountFromPath(rootAccount)
errCheck(err, "Failed to access account for signing")
err = account.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock account for signing")
var fixedSizeData [32]byte
copy(fixedSizeData[:], data)
defer account.Lock()
signature, err = signRoot(account, fixedSizeData, domain)
errCheck(err, "Failed to sign data")
}
outputIf(!quiet, fmt.Sprintf("0x%096x", signature.Marshal()))
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -1,4 +1,4 @@
// Copyright © 2017-2019 Weald Technology Trading
// Copyright © 2017-2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -14,11 +14,14 @@
package cmd
import (
"context"
"os"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
"github.com/wealdtech/go-bytesutil"
types "github.com/wealdtech/go-eth2-types"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
var signatureVerifySignature string
@@ -30,46 +33,69 @@ var signatureVerifyCmd = &cobra.Command{
Short: "Verify signed data",
Long: `Verify signed data. For example:
ethereal signature verify --data="0x5FfC014343cd971B7eb70732021E26C35B744cc4" --signature="0x8888..." --account="Personal wallet/Operations"
ethereal signature verify --data=0x5f24e819400c6a8ee2bfc014343cd971b7eb707320025a7bcd83e621e26c35b7 --signature=0x8888... --account="Personal wallet/Operations"
In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(signatureData != "", "--data is required")
data, err := bytesutil.FromHexString(signatureData)
errCheck(err, "Failed to parse data")
assert(len(data) == 32, "data to verify must be 32 bytes")
assert(signatureVerifySignature != "", "--signature is required")
signatureBytes, err := bytesutil.FromHexString(signatureVerifySignature)
errCheck(err, "Failed to parse signature")
signature, err := types.BLSSignatureFromBytes(signatureBytes)
signature, err := e2types.BLSSignatureFromBytes(signatureBytes)
errCheck(err, "Invalid signature")
domain := types.Domain([]byte{0, 0, 0, 0}, []byte{0, 0, 0, 0})
domain := e2types.Domain(e2types.DomainType([4]byte{0, 0, 0, 0}), e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
if signatureDomain != "" {
domainBytes, err := bytesutil.FromHexString(signatureDomain)
errCheck(err, "Failed to parse domain")
assert(len(domainBytes) == 8, "Domain data invalid")
assert(len(domainBytes) == 32, "Domain data invalid")
}
var pubKey types.PublicKey
var pubKey e2types.PublicKey
assert(signatureVerifyPubKey == "" || rootAccount == "", "Either --pubkey or --account should be supplied")
if rootAccount != "" {
account, err := accountFromPath(rootAccount)
errCheck(err, "Unknown account")
pubKey = account.PublicKey()
if remote {
listerClient := pb.NewListerClient(remoteGRPCConn)
listAccountsReq := &pb.ListAccountsRequest{
Paths: []string{
rootAccount,
},
}
resp, err := listerClient.ListAccounts(context.Background(), listAccountsReq)
errCheck(err, "Failed to access account")
assert(resp.State == pb.ResponseState_SUCCEEDED, "Failed to obtain account")
assert(len(resp.Accounts) == 1, "No such account")
pubKey, err = e2types.BLSPublicKeyFromBytes(resp.Accounts[0].PublicKey)
errCheck(err, "Invalid public key provided for account")
} else {
account, err := accountFromPath(rootAccount)
errCheck(err, "Unknown account")
pubKey = account.PublicKey()
}
} else {
pubKeyBytes, err := bytesutil.FromHexString(signatureVerifyPubKey)
errCheck(err, "Invalid public key")
pubKey, err = types.BLSPublicKeyFromBytes(pubKeyBytes)
pubKey, err = e2types.BLSPublicKeyFromBytes(pubKeyBytes)
errCheck(err, "Invalid public key")
}
verified := signature.Verify(data, pubKey, domain)
container := &SigningContainer{
Root: data,
Domain: domain,
}
root, err := ssz.HashTreeRoot(container)
errCheck(err, "Failed to create signing root")
verified := signature.Verify(root[:], pubKey)
if !verified {
outputIf(!quiet, "Not verified")
os.Exit(_exit_failure)
os.Exit(_exitFailure)
}
outputIf(!quiet, "Verified")
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -1,4 +1,4 @@
// Copyright © 2019 Weald Technology Trading
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -16,10 +16,11 @@ package cmd
import (
"fmt"
"os"
"strings"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/cobra"
types "github.com/wealdtech/go-eth2-types"
e2types "github.com/wealdtech/go-eth2-types/v2"
util "github.com/wealdtech/go-eth2-util"
string2eth "github.com/wealdtech/go-string2eth"
)
@@ -27,24 +28,35 @@ import (
var validatorDepositDataValidatorAccount string
var validatorDepositDataWithdrawalAccount string
var validatorDepositDataDepositValue string
var validatorDepositDataRaw bool
var validatorDepositDataCmd = &cobra.Command{
Use: "depositdata",
Short: "Generate deposit data for a validator",
Long: `Generate data for a deposit to the Ethereum 1 validator contract. For example:
Short: "Generate deposit data for one or more validators",
Long: `Generate data for deposits to the Ethereum 1 validator contract. For example:
ethdo validator depositdata --validatoraccount=primary/validator --withdrawalaccount=primary/current --value="32 Ether"
In quiet mode this will return 0 if the the data can be generated correctly, otherwise 1.
If validatoraccount is provided with an account path it will generate deposit data for all matching accounts.
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(validatorDepositDataValidatorAccount != "", "--validatoraccount is required")
validatorAccount, err := accountFromPath(validatorDepositDataValidatorAccount)
validatorWallet, err := walletFromPath(validatorDepositDataValidatorAccount)
errCheck(err, "Failed to obtain validator wallet")
validatorAccounts, err := accountsFromPath(validatorDepositDataValidatorAccount)
errCheck(err, "Failed to obtain validator account")
outputIf(debug, fmt.Sprintf("Validator public key is %048x", validatorAccount.PublicKey().Marshal()))
assert(len(validatorAccounts) > 0, "Failed to obtain validator account")
if len(validatorAccounts) == 1 {
outputIf(debug, fmt.Sprintf("Validator public key is %048x", validatorAccounts[0].PublicKey().Marshal()))
} else {
for _, validatorAccount := range validatorAccounts {
outputIf(verbose, fmt.Sprintf("Creating deposit for %s/%s", validatorWallet.Name(), validatorAccount.Name()))
outputIf(debug, fmt.Sprintf("Validator public key is %048x", validatorAccount.PublicKey().Marshal()))
}
}
assert(validatorDepositDataWithdrawalAccount != "", "--withdrawalaccount is required")
withdrawalAccount, err := accountFromPath(validatorDepositDataWithdrawalAccount)
@@ -53,50 +65,92 @@ In quiet mode this will return 0 if the the data can be generated correctly, oth
withdrawalCredentials := util.SHA256(withdrawalAccount.PublicKey().Marshal())
errCheck(err, "Failed to hash withdrawal credentials")
// TODO fetch this from the node.
withdrawalCredentials[0] = byte(0) // BLSWithdrawalPrefix
outputIf(debug, fmt.Sprintf("Withdrawal credentials are %032x", withdrawalCredentials))
assert(validatorDepositDataDepositValue != "", "--depositvalue is required")
val, err := string2eth.StringToGWei(validatorDepositDataDepositValue)
errCheck(err, "Invalid value")
// TODO fetch this from the node.
assert(val >= 1000000000, "deposit value must be at least 1 Ether")
depositData := struct {
PubKey []byte `ssz-size:"48"`
WithdrawalCredentials []byte `ssz-size:"32"`
Value uint64
}{
PubKey: validatorAccount.PublicKey().Marshal(),
WithdrawalCredentials: withdrawalCredentials,
Value: val,
}
signingRoot, err := ssz.HashTreeRoot(depositData)
errCheck(err, "Failed to generate deposit data signing root")
outputIf(debug, fmt.Sprintf("Signing root is %x", signingRoot))
domain := types.Domain(types.DomainDeposit, []byte{0, 0, 0, 0})
signature, err := sign(validatorDepositDataValidatorAccount, signingRoot[:], domain)
errCheck(err, "Failed to sign deposit data signing root")
// For each key, generate deposit data
outputs := make([]string, 0)
for _, validatorAccount := range validatorAccounts {
depositData := struct {
PubKey []byte `ssz-size:"48"`
WithdrawalCredentials []byte `ssz-size:"32"`
Value uint64
}{
PubKey: validatorAccount.PublicKey().Marshal(),
WithdrawalCredentials: withdrawalCredentials,
Value: val,
}
outputIf(debug, fmt.Sprintf("Deposit data:\n\tPublic key: %x\n\tWithdrawal credentials: %x\n\tValue: %d", depositData.PubKey, depositData.WithdrawalCredentials, depositData.Value))
domain := e2types.Domain(e2types.DomainDeposit, e2types.ZeroForkVersion, e2types.ZeroGenesisValidatorsRoot)
outputIf(debug, fmt.Sprintf("Domain is %x", domain))
err = validatorAccount.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock validator account")
signature, err := signStruct(validatorAccount, depositData, domain)
validatorAccount.Lock()
errCheck(err, "Failed to generate deposit data signature")
signedDepositData := struct {
PubKey []byte `ssz-size:"48"`
WithdrawalCredentials []byte `ssz-size:"32"`
Value uint64
Signature []byte `ssz-size:"96"`
}{
PubKey: validatorAccount.PublicKey().Marshal(),
WithdrawalCredentials: withdrawalCredentials,
Value: val,
Signature: signature.Marshal(),
signedDepositData := struct {
PubKey []byte `ssz-size:"48"`
WithdrawalCredentials []byte `ssz-size:"32"`
Value uint64
Signature []byte `ssz-size:"96"`
}{
PubKey: validatorAccount.PublicKey().Marshal(),
WithdrawalCredentials: withdrawalCredentials,
Value: val,
Signature: signature.Marshal(),
}
outputIf(debug, fmt.Sprintf("Signed deposit data:\n\tPublic key: %x\n\tWithdrawal credentials: %x\n\tValue: %d\n\tSignature: %x", signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Value, signedDepositData.Signature))
depositDataRoot, err := ssz.HashTreeRoot(signedDepositData)
errCheck(err, "Failed to generate deposit data root")
outputIf(debug, fmt.Sprintf("Deposit data root is %x", depositDataRoot))
if validatorDepositDataRaw {
// Build a raw transaction by hand
txData := []byte{0x22, 0x89, 0x51, 0x18}
// Pointer to validator public key
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, 0x80}...)
// Pointer to withdrawal credentials
txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0}...)
// Pointer to validator signature
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, 0x01, 0x20}...)
// Deposit data root
txData = append(txData, depositDataRoot[:]...)
// Validator public key (pad to 32-byte boundary)
txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30}...)
txData = append(txData, validatorAccount.PublicKey().Marshal()...)
txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...)
// Withdrawal credentials
txData = append(txData, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20}...)
txData = append(txData, withdrawalCredentials...)
// Deposit signature
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 {
outputs = append(outputs, fmt.Sprintf(`{"account":"%s","pubkey":"%048x","withdrawal_credentials":"%032x","signature":"%096x","value":%d,"deposit_data_root":"%032x"}`, fmt.Sprintf("%s/%s", validatorWallet.Name(), validatorAccount.Name()), signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Signature, val, depositDataRoot))
}
}
outputIf(debug, fmt.Sprintf("Deposit data signature is %x", signedDepositData.Signature))
if quiet {
os.Exit(0)
}
depositDataRoot, err := ssz.HashTreeRoot(signedDepositData)
errCheck(err, "Failed to generate deposit data root")
outputIf(debug, fmt.Sprintf("Deposit data root is %x", depositDataRoot))
outputIf(!quiet, fmt.Sprintf(`{"pubkey":"%048x","withdrawal_credentials":"%032x","signature":"%096x","value":%d,"deposit_data_root":"%032x"}`, signedDepositData.PubKey, signedDepositData.WithdrawalCredentials, signedDepositData.Signature, val, depositDataRoot))
os.Exit(0)
if len(outputs) == 1 {
fmt.Printf("%s\n", outputs[0])
} else {
fmt.Printf("[")
fmt.Print(strings.Join(outputs, ","))
fmt.Println("]")
}
},
}
@@ -106,4 +160,5 @@ func init() {
validatorDepositDataCmd.Flags().StringVar(&validatorDepositDataValidatorAccount, "validatoraccount", "", "Account of the account carrying out the validation")
validatorDepositDataCmd.Flags().StringVar(&validatorDepositDataWithdrawalAccount, "withdrawalaccount", "", "Account of the account to which the validator funds will be withdrawn")
validatorDepositDataCmd.Flags().StringVar(&validatorDepositDataDepositValue, "depositvalue", "", "Value of the amount to be deposited")
validatorDepositDataCmd.Flags().BoolVar(&validatorDepositDataRaw, "raw", false, "Print raw deposit data transaction data")
}

113
cmd/validatorexit.go Normal file
View File

@@ -0,0 +1,113 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"context"
"fmt"
"os"
"time"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/grpc"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
var validatorExitEpoch int64
var validatorExitCmd = &cobra.Command{
Use: "exit",
Short: "Send an exit request for a validator",
Long: `Send an exit request for a validator. For example:
ethdo validator exit --account=primary/validator --passphrase=secret
In quiet mode this will return 0 if the transaction has been sent, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
// Sanity checking and setup.
assert(rootAccount != "", "--account is required")
account, err := accountFromPath(rootAccount)
errCheck(err, "Failed to access account")
err = connect()
errCheck(err, "Failed to obtain connect to Ethereum 2 beacon chain node")
// Beacon chain config required for later work.
config, err := grpc.FetchChainConfig(eth2GRPCConn)
errCheck(err, "Failed to obtain beacon chain configuration")
// Fetch the validator's index.
index, err := grpc.FetchValidatorIndex(eth2GRPCConn, account)
errCheck(err, "Failed to obtain validator index")
outputIf(debug, fmt.Sprintf("Validator index is %d", index))
// Ensure the validator is active.
state, err := grpc.FetchValidatorState(eth2GRPCConn, account)
errCheck(err, "Failed to obtain validator state")
outputIf(debug, fmt.Sprintf("Validator state is %v", state))
assert(state == ethpb.ValidatorStatus_ACTIVE, "Validator must be active to exit")
// Ensure the validator has been active long enough to exit.
validator, err := grpc.FetchValidator(eth2GRPCConn, account)
errCheck(err, "Failed to obtain validator information")
outputIf(debug, fmt.Sprintf("Activation epoch is %v", validator.ActivationEpoch))
earliestExitEpoch := validator.ActivationEpoch + config["PersistentCommitteePeriod"].(uint64)
secondsPerEpoch := config["SecondsPerSlot"].(uint64) * config["SlotsPerEpoch"].(uint64)
genesisTime, err := grpc.FetchGenesis(eth2GRPCConn)
errCheck(err, "Failed to obtain genesis time")
currentEpoch := uint64(time.Since(genesisTime).Seconds()) / secondsPerEpoch
assert(currentEpoch >= earliestExitEpoch, fmt.Sprintf("Validator cannot exit until %s ( epoch %d)", genesisTime.Add(time.Duration(secondsPerEpoch*earliestExitEpoch)*time.Second).Format(time.UnixDate), earliestExitEpoch))
outputIf(verbose, "Validator confirmed to be in a suitable state")
// Set up the transaction.
exit := &ethpb.VoluntaryExit{
Epoch: currentEpoch,
ValidatorIndex: index,
}
// TODO fetch current fork version from config (currently using genesis fork version)
currentForkVersion := config["GenesisForkVersion"].([]byte)
// TODO fetch genesis validators root from somewhere.
//domain := e2types.Domain(e2types.DomainVoluntaryExit, currentForkVersion, genesisValidatorsRoot)
domain := e2types.Domain(e2types.DomainVoluntaryExit, currentForkVersion, e2types.ZeroGenesisValidatorsRoot)
err = account.Unlock([]byte(rootAccountPassphrase))
errCheck(err, "Failed to unlock account; please confirm passphrase is correct")
signature, err := signStruct(account, exit, domain)
errCheck(err, "Failed to sign exit proposal")
proposal := &ethpb.SignedVoluntaryExit{
Exit: exit,
Signature: signature.Marshal(),
}
validatorClient := ethpb.NewBeaconNodeValidatorClient(eth2GRPCConn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, err = validatorClient.ProposeExit(ctx, proposal)
errCheck(err, "Failed to propose exit")
outputIf(!quiet, "Validator exit transaction sent")
os.Exit(_exitSuccess)
},
}
func init() {
validatorCmd.AddCommand(validatorExitCmd)
validatorFlags(validatorExitCmd)
validatorExitCmd.Flags().Int64Var(&validatorExitEpoch, "epoch", -1, "Epoch at which to exit (defaults to now)")
addTransactionFlags(validatorExitCmd)
}

113
cmd/validatorinfo.go Normal file
View File

@@ -0,0 +1,113 @@
// 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 (
"encoding/hex"
"fmt"
"os"
"strings"
"time"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/grpc"
"github.com/wealdtech/ethdo/util"
types "github.com/wealdtech/go-eth2-wallet-types/v2"
string2eth "github.com/wealdtech/go-string2eth"
)
var validatorInfoPubKey string
var validatorInfoCmd = &cobra.Command{
Use: "info",
Short: "Obtain information about a validator",
Long: `Obtain information about validator. For example:
ethdo validator info --account=primary/validator
In quiet mode this will return 0 if the validator information can be obtained, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
// Sanity checking and setup.
assert(rootAccount != "" || validatorInfoPubKey != "", "--account or --pubkey is required")
err := connect()
errCheck(err, "Failed to obtain connection to Ethereum 2 beacon chain node")
var account types.Account
if rootAccount != "" {
account, err = accountFromPath(rootAccount)
errCheck(err, "Failed to access account")
} else {
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(validatorInfoPubKey, "0x"))
errCheck(err, fmt.Sprintf("Failed to decode public key %s", validatorInfoPubKey))
account, err = util.NewScratchAccount(pubKeyBytes)
errCheck(err, fmt.Sprintf("Invalid public key %s", validatorInfoPubKey))
}
validatorInfo, err := grpc.FetchValidatorInfo(eth2GRPCConn, account)
errCheck(err, "Failed to obtain validator information")
validatorDef, err := grpc.FetchValidator(eth2GRPCConn, account)
if validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED &&
validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
errCheck(err, "Failed to obtain validator definition")
}
assert(validatorInfo.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS, "Not known as a validator")
if quiet {
os.Exit(_exitSuccess)
}
outputIf(verbose, fmt.Sprintf("Epoch of data:\t\t%v", validatorInfo.Epoch))
outputIf(verbose && validatorInfo.Status != ethpb.ValidatorStatus_DEPOSITED, fmt.Sprintf("Index:\t\t\t%v", validatorInfo.Index))
outputIf(verbose, fmt.Sprintf("Public key:\t\t%#x", validatorInfo.PublicKey))
fmt.Printf("Status:\t\t\t%s\n", strings.Title(strings.ToLower(validatorInfo.Status.String())))
fmt.Printf("Balance:\t\t%s\n", string2eth.GWeiToString(validatorInfo.Balance, true))
if validatorInfo.Status == ethpb.ValidatorStatus_ACTIVE ||
validatorInfo.Status == ethpb.ValidatorStatus_EXITING ||
validatorInfo.Status == ethpb.ValidatorStatus_SLASHING {
fmt.Printf("Effective balance:\t%s\n", string2eth.GWeiToString(validatorInfo.EffectiveBalance, true))
}
if validatorDef != nil {
outputIf(verbose, fmt.Sprintf("Withdrawal credentials:\t%#x", validatorDef.WithdrawalCredentials))
}
transition := time.Unix(int64(validatorInfo.TransitionTimestamp), 0)
transitionPassed := int64(validatorInfo.TransitionTimestamp) <= time.Now().Unix()
switch validatorInfo.Status {
case ethpb.ValidatorStatus_DEPOSITED:
if validatorInfo.TransitionTimestamp != 0 {
fmt.Printf("Inclusion in chain:\t%s\n", transition)
}
case ethpb.ValidatorStatus_PENDING:
fmt.Printf("Activation:\t\t%s\n", transition)
case ethpb.ValidatorStatus_EXITING, ethpb.ValidatorStatus_SLASHING:
fmt.Printf("Attesting finishes:\t%s\n", transition)
case ethpb.ValidatorStatus_EXITED:
if transitionPassed {
fmt.Printf("Funds withdrawable:\tNow\n")
} else {
fmt.Printf("Funds withdrawable:\t%s\n", transition)
}
}
os.Exit(_exitSuccess)
},
}
func init() {
validatorCmd.AddCommand(validatorInfoCmd)
validatorInfoCmd.Flags().StringVar(&validatorInfoPubKey, "pubkey", "", "Public key for which to obtain status")
validatorFlags(validatorInfoCmd)
}

View File

@@ -30,7 +30,7 @@ var versionCmd = &cobra.Command{
ethdo version.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("1.1.0")
fmt.Println("1.4.0")
if viper.GetBool("verbose") {
buildInfo, ok := dbg.ReadBuildInfo()
if ok {
@@ -44,7 +44,7 @@ var versionCmd = &cobra.Command{
}
}
}
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -14,13 +14,13 @@
package cmd
import (
"context"
"fmt"
"os"
"sort"
"github.com/google/uuid"
"github.com/spf13/cobra"
types "github.com/wealdtech/go-eth2-types"
"github.com/spf13/viper"
pb "github.com/wealdtech/eth2-signer-api/pb/v1"
)
var walletAccountsCmd = &cobra.Command{
@@ -34,31 +34,49 @@ 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")
wallet, err := walletFromPath(walletWallet)
errCheck(err, "Failed to access wallet")
hasAccounts := false
// List the accounts. They come to us in random order and we want them in name order, so store them in an array and sort
output := make([]addressListResult, 0)
for account := range wallet.Accounts() {
output = append(output, addressListResult{id: account.ID(), name: account.Name(), pubkey: account.PublicKey()})
if remote {
listerClient := pb.NewListerClient(remoteGRPCConn)
listAccountsReq := &pb.ListAccountsRequest{
Paths: []string{
walletWallet,
},
}
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
accountsResp, err := listerClient.ListAccounts(ctx, listAccountsReq)
errCheck(err, "Failed to access wallet")
assert(accountsResp.State == pb.ResponseState_SUCCEEDED, "Request to list wallet accounts failed")
walletPrefixLen := len(walletWallet) + 1
for _, account := range accountsResp.Accounts {
hasAccounts = true
if verbose {
fmt.Printf("%s\n", account.Name[walletPrefixLen:])
fmt.Printf("\tPublic key: %#048x\n", account.PublicKey)
} else if !quiet {
fmt.Printf("%s\n", account.Name[walletPrefixLen:])
}
}
} else {
wallet, err := walletFromPath(walletWallet)
errCheck(err, "Failed to access wallet")
for account := range wallet.Accounts() {
hasAccounts = true
if verbose {
fmt.Printf("%s\n\tUUID:\t\t%s\n\tPublic key:\t0x%048x\n", account.Name(), account.ID(), account.PublicKey().Marshal())
} else if !quiet {
fmt.Printf("%s\n", account.Name())
}
}
}
if quiet {
if len(output) == 0 {
os.Exit(1)
}
os.Exit(0)
}
sort.Slice(output, func(i, j int) bool {
return output[i].name < output[j].name
})
for _, out := range output {
if verbose {
fmt.Printf("%s\n\tUUID:\t\t%s\n\tPublic key:\t0x%048x\n", out.name, out.id, out.pubkey.Marshal())
} else if !quiet {
fmt.Printf("%s\n", out.name)
if hasAccounts {
os.Exit(_exitSuccess)
}
os.Exit(_exitFailure)
}
},
}
@@ -67,9 +85,3 @@ func init() {
walletCmd.AddCommand(walletAccountsCmd)
walletFlags(walletAccountsCmd)
}
type addressListResult struct {
id uuid.UUID
name string
pubkey types.PublicKey
}

View File

@@ -31,6 +31,7 @@ var walletCreateCmd = &cobra.Command{
In quiet mode this will return 0 if the wallet is created successfully, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "wallet create not available with remote wallets")
assert(walletWallet != "", "--wallet is required")
assert(walletCreateType != "", "--type is required")

View File

@@ -18,7 +18,7 @@ import (
"os"
"github.com/spf13/cobra"
types "github.com/wealdtech/go-eth2-wallet-types"
types "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var walletExportPassphrase string
@@ -32,6 +32,7 @@ var walletExportCmd = &cobra.Command{
In quiet mode this will return 0 if the wallet is able to be exported, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "wallet export not available with remote wallets")
assert(walletWallet != "", "--wallet is required")
assert(walletExportPassphrase != "", "--exportpassphrase is required")
@@ -45,7 +46,7 @@ In quiet mode this will return 0 if the wallet is able to be exported, otherwise
errCheck(err, "Failed to export wallet")
outputIf(!quiet, fmt.Sprintf("0x%x", exportData))
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -14,7 +14,10 @@
package cmd
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/wealdtech/go-bytesutil"
@@ -33,22 +36,31 @@ var walletImportCmd = &cobra.Command{
In quiet mode this will return 0 if the wallet is imported successfully, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "wallet import not available with remote wallets")
assert(walletImportData != "", "--walletimportdata is required")
assert(walletImportPassphrase != "", "--importpassphrase is required")
if !strings.HasPrefix(walletImportData, "0x") {
outputIf(debug, fmt.Sprintf("Reading wallet import from file %s", walletImportData))
// Assume this is a path
fileData, err := ioutil.ReadFile(walletImportData)
errCheck(err, "Failed to read wallet import data")
walletImportData = strings.TrimSpace(string(fileData))
}
outputIf(debug, fmt.Sprintf("Wallet import data is of length %d", len(walletImportData)))
importData, err := bytesutil.FromHexString(walletImportData)
errCheck(err, "Failed to decode wallet data")
_, err = wallet.ImportWallet(importData, []byte(walletImportPassphrase))
errCheck(err, "Failed to import wallet")
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}
func init() {
walletCmd.AddCommand(walletImportCmd)
walletFlags(walletImportCmd)
walletImportCmd.Flags().StringVar(&walletImportData, "importdata", "", "The data to import")
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")
}

View File

@@ -18,6 +18,7 @@ import (
"os"
"github.com/spf13/cobra"
wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var walletInfoCmd = &cobra.Command{
@@ -29,6 +30,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")
wallet, err := walletFromPath(walletWallet)
@@ -40,6 +42,15 @@ In quiet mode this will return 0 if the wallet exists, otherwise 1.`,
outputIf(verbose, fmt.Sprintf("UUID: %v", wallet.ID()))
fmt.Printf("Type: %s\n", wallet.Type())
if verbose {
if storeProvider, ok := wallet.(wtypes.StoreProvider); ok {
store := storeProvider.Store()
fmt.Printf("Store: %s\n", store.Name())
if storeLocationProvider, ok := store.(wtypes.StoreLocationProvider); ok {
fmt.Printf("Location: %s\n", storeLocationProvider.Location())
}
}
}
// Count the accounts.
accounts := 0

View File

@@ -30,17 +30,23 @@ var walletListCmd = &cobra.Command{
In quiet mode this will return 0 if any wallets are found, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "wallet list not available with remote wallets")
walletsFound := false
for w := range wallet.Wallets() {
walletsFound = true
outputIf(!quiet && !verbose, w.Name())
outputIf(verbose, fmt.Sprintf("%s\n\tUUID:\t\t%s", w.Name(), w.ID().String()))
if remote {
die("Remote wallets cannot be listed")
} else {
for w := range wallet.Wallets() {
walletsFound = true
outputIf(!quiet && !verbose, w.Name())
outputIf(verbose, fmt.Sprintf("%s\n\tUUID:\t\t%s", w.Name(), w.ID().String()))
}
}
if !walletsFound {
os.Exit(_exit_failure)
os.Exit(_exitFailure)
}
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

View File

@@ -19,7 +19,7 @@ import (
bip39 "github.com/FactomProject/go-bip39"
"github.com/spf13/cobra"
types "github.com/wealdtech/go-eth2-wallet-types"
types "github.com/wealdtech/go-eth2-wallet-types/v2"
)
var walletSeedCmd = &cobra.Command{
@@ -31,6 +31,7 @@ var walletSeedCmd = &cobra.Command{
In quiet mode this will return 0 if the wallet is a hierarchical deterministic wallet, otherwise 1.`,
Run: func(cmd *cobra.Command, args []string) {
assert(!remote, "wallet seed not available with remote wallets")
assert(walletWallet != "", "--wallet is required")
assert(rootWalletPassphrase != "", "--walletpassphrase is required")
@@ -48,7 +49,7 @@ In quiet mode this will return 0 if the wallet is a hierarchical deterministic w
errCheck(err, "Failed to generate seed mnemonic")
outputIf(!quiet, seedStr)
os.Exit(_exit_success)
os.Exit(_exitSuccess)
},
}

39
go.mod
View File

@@ -4,31 +4,34 @@ go 1.13
require (
github.com/FactomProject/go-bip39 v0.3.5
github.com/dgraph-io/ristretto v0.0.1 // indirect
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/golang/protobuf v1.4.0
github.com/google/uuid v1.1.1
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/minio/highwayhash v1.0.0 // indirect
github.com/minio/sha256-simd v0.1.1 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.14.3 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/pelletier/go-toml v1.6.0 // indirect
github.com/protolambda/zssz v0.1.4 // indirect
github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52 // indirect
github.com/mitchellh/mapstructure v1.2.2 // indirect
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/pkg/errors v0.9.1
github.com/prysmaticlabs/ethereumapis v0.0.0-20200414190010-6607cc86ddb7
github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963
github.com/sirupsen/logrus v1.4.2
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v0.0.5
github.com/spf13/cobra v1.0.0
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.6.1
github.com/wealdtech/go-bytesutil v1.1.0
github.com/wealdtech/go-eth2-types v1.0.0
github.com/wealdtech/go-eth2-util v1.1.0
github.com/wealdtech/go-eth2-wallet v1.8.0
github.com/wealdtech/go-eth2-wallet-types v1.8.0
github.com/spf13/viper v1.6.3
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.0
github.com/wealdtech/go-eth2-util v1.1.4
github.com/wealdtech/go-eth2-wallet v1.9.3
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.1
github.com/wealdtech/go-string2eth v1.1.0
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/ini.v1 v1.51.1 // indirect
gopkg.in/yaml.v2 v2.2.7 // indirect
google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36 // indirect
google.golang.org/grpc v1.28.1
gopkg.in/ini.v1 v1.55.0 // indirect
)

281
go.sum
View File

@@ -5,60 +5,81 @@ github.com/FactomProject/go-bip39 v0.3.5 h1:l9g92TeqCkC5NZhm72igTpf5yaYDp3Sy4Cvn
github.com/FactomProject/go-bip39 v0.3.5/go.mod h1:ygPVOtW424QxnJMze9XYDeh4wT19V3iVDOqVUl/USkE=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/aws/aws-sdk-go v1.25.25 h1:j3HLOqcDWjNox1DyvJRs+kVQF42Ghtv6oL6cVBfXS3U=
github.com/aws/aws-sdk-go v1.25.25/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.25.33 h1:8muvpP+Bq5e0CDkM9PDZ6tN74fVUq5v3zSCRaZ93ykM=
github.com/aws/aws-sdk-go v1.25.33/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.25.50 h1:fTCp6qKnf1WLZGZtL0hh5PykCUaLZQBxlkTNG6fOK4I=
github.com/aws/aws-sdk-go v1.25.50/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.2 h1:MzYLmCeny4bMQcAbYcucIduVZKp0sEf1eRLvHpKI5Is=
github.com/aws/aws-sdk-go v1.26.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.28.0 h1:NkmnHFVEMTRYTleRLm5xUaL1mHKKkYQl4rCd+jzD58c=
github.com/aws/aws-sdk-go v1.28.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY=
github.com/aws/aws-sdk-go v1.30.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/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.0.1 h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs=
github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
github.com/dgraph-io/ristretto v0.0.2 h1:a5WaUrDa0qm0YrAAS1tUykT5El3kt62KNZZeMxQn3po=
github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlespiau/covertool v0.0.0-20180314162135-b0c4c6d0583a/go.mod h1:/eQMcW3eA1bzKx23ZYI2H3tXPdJB5JWYTHzoUPBvQY4=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4 h1:+EOh4OY6tjM6ZueeUKinl1f0U2820HzQOuf1iqMnsks=
github.com/golang/protobuf v1.4.0-rc.4/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/pprof v0.0.0-20190309163659-77426154d546/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -66,23 +87,26 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0 h1:bM6ZAFZmc/wPFaRDi0d5L7hGEZEx/2u+Tmr2evNHDiI=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=
github.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/herumi/bls-eth-go-binary v0.0.0-20200326062426-f58f8b8bd66f h1:fTtKw31DtXHqxb3D9Oqt+CDVXEbyLs7yqa+RNKYw+3I=
github.com/herumi/bls-eth-go-binary v0.0.0-20200326062426-f58f8b8bd66f/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.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -93,8 +117,6 @@ github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/highwayhash v1.0.0 h1:iMSDhgUILCr0TNm8LWlSjF8N0ZIj2qbO8WHp6Q/J2BA=
github.com/minio/highwayhash v1.0.0/go.mod h1:xQboMTeM9nY9v/LlAOxFctujiv5+Aq2hR5dxBpaMbdc=
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
@@ -103,31 +125,28 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mmcloughlin/avo v0.0.0-20190318053554-7a0eb66183da/go.mod h1:lf5GMZxA5kz8dnCweJuER5Rmbx6dDu6qvw0fO3uYKK8=
github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
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=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/phoreproject/bls v0.0.0-20190821133044-da95d4798b09 h1:f0WZnMl5hMHNpfUPR+klp00ZaIL1dLPZigpJUWupreI=
github.com/phoreproject/bls v0.0.0-20190821133044-da95d4798b09/go.mod h1:7pK0Ldy91shCmI47LLTn3i3rfTQcHiJJvPqGqzvN5nE=
github.com/phoreproject/bls v0.0.0-20191016230924-b2e57acce2ed h1:pX150rn565RorbtQWv2pR0SGd5rr9iHSGCSR26dg5Wk=
github.com/phoreproject/bls v0.0.0-20191016230924-b2e57acce2ed/go.mod h1:7pK0Ldy91shCmI47LLTn3i3rfTQcHiJJvPqGqzvN5nE=
github.com/phoreproject/bls v0.0.0-20191113194321-fef763a1a842 h1:SFS72hX189sQC+kZzAcNv7ENTLJHddmokEM39RsLA24=
github.com/phoreproject/bls v0.0.0-20191113194321-fef763a1a842/go.mod h1:xHJKf2TLXUA39Dhv8k5QmQOxLsbrb1KeTS/3ERfLeqc=
github.com/phoreproject/bls v0.0.0-20191211001008-9d5f85bf4a9b h1:tE/F54uL3jp0ZGSKNMPGCTF003pSmtD/sQojpKADAxY=
github.com/phoreproject/bls v0.0.0-20191211001008-9d5f85bf4a9b/go.mod h1:xHJKf2TLXUA39Dhv8k5QmQOxLsbrb1KeTS/3ERfLeqc=
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/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k=
github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@@ -135,19 +154,19 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/protolambda/zssz v0.1.4 h1:4jkt8sqwhOVR8B1JebREU/gVX0Ply4GypsV8+RWrDuw=
github.com/protolambda/zssz v0.1.4/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag=
github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52 h1:kxZ+xSWX0qbxoiDXQBLztKeEmEQg6TgCYWAOa7gSGGU=
github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-ssz v0.0.0-20191204195639-142dfef39d12 h1:bfPIvWvA7QSmIYARnHM9tgGx1LDeSKa2bYW5QGGArxQ=
github.com/prysmaticlabs/go-ssz v0.0.0-20191204195639-142dfef39d12/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200414190010-6607cc86ddb7 h1:p1WbKbIHr4tXK6wclFrM78P61Ai2qSWMQGkljbP4H1A=
github.com/prysmaticlabs/ethereumapis v0.0.0-20200414190010-6607cc86ddb7/go.mod h1:5OkRN6UmvgtP+kIewitcEKC7S5KOzLOGtya/Tz+HBns=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669 h1:cX6YRZnZ9sgMqM5U14llxUiXVNJ3u07Res1IIjTOgtI=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963 h1:Th5ufPIaL5s/7i3gXHTgiTwfsUhWDP/PwFRiI6qV6v0=
github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w=
github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@@ -155,6 +174,8 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@@ -162,8 +183,8 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@@ -171,75 +192,49 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk=
github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
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=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/wealdtech/go-bytesutil v1.0.0/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
github.com/wealdtech/eth2-signer-api v1.3.0 h1:Fs0GfrdhboBKW7zaMvIvUHJaOB1ibpAmRG3lkB53in4=
github.com/wealdtech/eth2-signer-api v1.3.0/go.mod h1:H8OpAoTBl6CaBvZEnhxWDjjWXNc3kwVFKWMAZd6sHlk=
github.com/wealdtech/go-bytesutil v1.0.1 h1:6xzMM+VEHf5WNh1PsIFcRwScgcno+CP8Rw1rGvT6Cew=
github.com/wealdtech/go-bytesutil v1.0.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
github.com/wealdtech/go-bytesutil v1.1.0 h1:6XrN7OIQhhBjQy/PZ1HZ3ySE8v8UDyxzERkOgmsIc1g=
github.com/wealdtech/go-bytesutil v1.1.0/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
github.com/wealdtech/go-ecodec v1.0.0 h1:QQj1t/yOGLsx8WUJaCTN+RrivgdWlP+r5ixzGzhlXVU=
github.com/wealdtech/go-ecodec v1.0.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4=
github.com/wealdtech/go-bytesutil v1.1.1 h1:ocEg3Ke2GkZ4vQw5lp46rmO+pfqCCTgq35gqOy8JKVc=
github.com/wealdtech/go-bytesutil v1.1.1/go.mod h1:jENeMqeTEU8FNZyDFRVc7KqBdRKSnJ9CCh26TcuNb9s=
github.com/wealdtech/go-ecodec v1.1.0 h1:yggrTSckcPJRaxxOxQF7FPm21kgE8WA6+f5jdq5Kr8o=
github.com/wealdtech/go-ecodec v1.1.0/go.mod h1:PSdBFEB6cltdT7V4E1jbboufMZTZXcQOKG/2PeEjKK4=
github.com/wealdtech/go-eth2-types v1.0.0 h1:ggrbQ5HeFcxVm20zxVWr8Sc3uCditaetzWB/Ax/4g0w=
github.com/wealdtech/go-eth2-types v1.0.0/go.mod h1:fWUgtKQ7hiNVl6263bGeyjlydYuaxkxcUIPIopgz2CM=
github.com/wealdtech/go-eth2-util v1.0.0 h1:sKnZ84xLzj1PntxaWeiGmA+1LZ6vOeIXqCHDkVvzRGU=
github.com/wealdtech/go-eth2-util v1.0.0/go.mod h1:ZodZI58Seya6uhbMLe3cLydsV0AhneyWCHzmkJCKlIM=
github.com/wealdtech/go-eth2-util v1.1.0 h1:bDgNEtH5LoxI1JaBPUgHoPKmfPwtGuLw487U7AoMO6E=
github.com/wealdtech/go-eth2-util v1.1.0/go.mod h1:mX11133nOroRPHp3qXyAqT5iLmsZXQmpH2DZWWeFWP8=
github.com/wealdtech/go-eth2-wallet v1.5.0 h1:6QFNfXyX009C8WIxnflyEctogx1QzQ8cBb7Vftyp5VE=
github.com/wealdtech/go-eth2-wallet v1.5.0/go.mod h1:jpYP8snFvI3/rTS+zdfyyUsyf6EXoSHl5ByWmFYq72Q=
github.com/wealdtech/go-eth2-wallet v1.8.0 h1:QO8HzHDXNgc8AEBulz0IFdk+U9SDc0+UX3dNVstB8wY=
github.com/wealdtech/go-eth2-wallet v1.8.0/go.mod h1:PWvCjr8NXZbEIIpFYAc7tgjc50X9PCo7K4LzXn3//bY=
github.com/wealdtech/go-eth2-types/v2 v2.3.0 h1:qfmgaCBkH2N11LHCXsRWYz7OOxc+1QXrKHlS9yDnFsw=
github.com/wealdtech/go-eth2-types/v2 v2.3.0/go.mod h1:jDvQ0j5EUtI7x/c3Vscq8TaFzBGlj6DrKz0CABuugkI=
github.com/wealdtech/go-eth2-util v1.1.4 h1:MyM16V7Qhd9q2ZaRa0WteBg2bWb8UplIKjZr8aeBZP0=
github.com/wealdtech/go-eth2-util v1.1.4/go.mod h1:rvkccTN0inLcI76Gq8FBdkuv3tmX+XSJxBr9gdm1WUE=
github.com/wealdtech/go-eth2-wallet v1.9.3 h1:Hna/w4EKBJIs86VprIq7ez063A6kwk31d/O3Gs+MpYc=
github.com/wealdtech/go-eth2-wallet v1.9.3/go.mod h1:ylsiNrJen1Nw8m+c0fWZKp823E87p7RbrFwcI4V2S18=
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 v1.6.0 h1:01G1IzKmpO33+jUEmdAU5My/PmoKjSoxsli9LpXQl9w=
github.com/wealdtech/go-eth2-wallet-hd v1.6.0/go.mod h1:Fmr23uSPnsPp9kDV7A3W816qzxU15QS0cq4qm2Cbc+I=
github.com/wealdtech/go-eth2-wallet-hd v1.7.0 h1:q4YyUOAkbRPK84uBFPVg+jVuLCo1VVh7KE8ZgIW6aUU=
github.com/wealdtech/go-eth2-wallet-hd v1.7.0/go.mod h1:sDiIKeBg8zz1lBVJYdks8my4Qj/+Q5j4mZ8OcyA1mCM=
github.com/wealdtech/go-eth2-wallet-hd v1.8.0 h1:3oYkM6H94vA5y5RUtiBErrZSOxZnwgqRC2Yg6ZnABVg=
github.com/wealdtech/go-eth2-wallet-hd v1.8.0/go.mod h1:EgleYFBLF2AFAPkoNiEsVJkfRMjOj76zKtKEx38bjuk=
github.com/wealdtech/go-eth2-wallet-hd v1.9.0 h1:AtBkFvE4Usrzz+jkLgThfSW5kiXKKbQLK8rHS9OXu5I=
github.com/wealdtech/go-eth2-wallet-hd v1.9.0/go.mod h1:QGIkXF1AtI9cLByFlnnRXDoK01/SuunRfGLzhWDMnCU=
github.com/wealdtech/go-eth2-wallet-nd v1.5.0 h1:0nOOD0TpvGTSbRF7NGxAzgFPoEdM0Awnr9Mx3mroOm4=
github.com/wealdtech/go-eth2-wallet-nd v1.5.0/go.mod h1:KiORm3eoIq+XR043MPekEPebU8I12918bE7ldrqk9iw=
github.com/wealdtech/go-eth2-wallet-nd v1.6.0 h1:uMX6K/LdJdo56vaR8pIDrwGDX8w+e/MxA88B19Ys/gw=
github.com/wealdtech/go-eth2-wallet-nd v1.6.0/go.mod h1:oVsPJTBSHnBphYush38VQYCuLwYi/HViqvZByh9vqJ0=
github.com/wealdtech/go-eth2-wallet-nd v1.7.0 h1:hdQ1XTbz/d1ySY5/kDNQokVP7nM3i6pe/tLgVJqhlxk=
github.com/wealdtech/go-eth2-wallet-nd v1.7.0/go.mod h1:3vaCTMI2yPndhgjXqM6ynv3yrU0VvqksQ4MaQLCgZIo=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.4.0 h1:IH9ncOXxd10A4C6EAptnycuRcoenRmf60oKq5yirfpc=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.4.0/go.mod h1:FCzZpqn1KqU1ezKKjjxh6l9NjmCAiTwZksgE+bnTD68=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.5.0 h1:bVOahxWdk0qkZ6xseQBw8fNmCDIbmIM/4KHY+cUSWj8=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.5.0/go.mod h1:8zwb4tAWxGF4PZCNNYdkjlGQYbTEadkKwCkSNyCOfm4=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.3.0 h1:Cl/XoJUwUPPO1pq8PpFg+UWSO4XyJC5h+kKYBpgQtMM=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.3.0/go.mod h1:bW+mIEvCitsc3+ZYIIzaawCjrCtI+CpGUAIrevesOSw=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.4.0 h1:7M5pJeMUhTTAjKFNd7//clwV5c8IDbbmBQJiMOPmFu8=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.4.0/go.mod h1:XDUlPyp6q2X53yIktwP4gRXk6JLbegr4dp67GBgO5T0=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.5.0 h1:ZbG99FcnBJrZhVWIfcWS/qe4C8dcog0Amjj6v+RraSE=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.5.0/go.mod h1:NTchwZDLDZhrzF3ENkC890m4SKt5SI8mHdn5XJryVL0=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.2.0 h1:GzwNLhfHlR25PXSNWPFBQwMA4nQS80WLTp9DWKhUDXU=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.2.0/go.mod h1:Rmi0S69tuts1YbVXcimw/4yvYUSiLNIUE9gIT3i1h4E=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.3.0/go.mod h1:NaV/et5zTaqHhTpdpSveUYE2czCFAD8f07eABh/0pso=
github.com/wealdtech/go-eth2-wallet-types v1.5.0 h1:9uRdSws4Wg42lQ63AEg4X/1Mt/si5MIZOBaVpuCyrLU=
github.com/wealdtech/go-eth2-wallet-types v1.5.0/go.mod h1:OQqqr/hWOwNHe9NyXI0cYGQI6CBBmAlcusqWnJCf7T8=
github.com/wealdtech/go-eth2-wallet-types v1.7.0 h1:wzIrTpD31rFWJIU2rWGOowoaDBpl7nTSHL8W0tjv2oo=
github.com/wealdtech/go-eth2-wallet-types v1.7.0/go.mod h1:5A83MUBhmLgxpg9X5eqvnDIOYfn329caf5DOcv7pcY0=
github.com/wealdtech/go-eth2-wallet-types v1.8.0 h1:6K/u5CTcUavgzoABeeuBAZ0jp1qEOdK/9U8gaMJUlVE=
github.com/wealdtech/go-eth2-wallet-types v1.8.0/go.mod h1:5A83MUBhmLgxpg9X5eqvnDIOYfn329caf5DOcv7pcY0=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.0.1 h1:kiCvdexK3zRC2GwZHSHq+hS+irVNtMs5pNADyumeeRM=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.0.1/go.mod h1:jqmt8pGMm2WCzqiHkPW8ib/GAFNaQzNhqToOGN0qBDs=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.0.1 h1:4lB6GY5oHQn5xwn/Sxm1e9SeVCaxa7q/0hqXUQYUNwU=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.0.1/go.mod h1:jJ3AUHWR0NlPrE6qlOL86pJe14x6K2xFzfmX1brB9Ws=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.7.2 h1:Lc6wVTjIYeD+2hLAIzq1SugTWR527vEX4tEr5v3zxJc=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.7.2/go.mod h1:fyA+GmdE7bd/P93TBcb3aqQ83i0AmcQHu9qPg4HnLlg=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.6.2 h1:xzyQDxbe5nr7xG0ByevTV2S8qkeOZvvjp+leBJcpxXQ=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.6.2/go.mod h1:C+NWsx9AdAfrn5zLbru+ctO+lljVTVCJYcXgFsN7Q9o=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.3.2 h1:vR9ATFkkUAA4Os9wxF/GhN8Rg3HA/1COMRdzqIg/evY=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.3.2/go.mod h1:BQ8aeThx3O7ByvAB2E1FDiHbAlJXAir7nUg5liJw0W4=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.1 h1:Ct3RrNJTapBiG2GxVl53Kfgy96f0GEUV7bediTu91u8=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.0.1/go.mod h1:y2XAyxb01jyGq3w2hyVgXadgl+KtlDwq8A9RQt2DE3g=
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=
@@ -250,76 +245,89 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
golang.org/x/arch v0.0.0-20190312162104-788fe5ffcd8c/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59 h1:PyXRxSVbvzDGuqYXjHndV7xDzJ7w2K8KD9Ef8GB7KOE=
golang.org/x/crypto v0.0.0-20191105034135-c7e5f84aec59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191111213947-16651526fdb4 h1:AGVXd+IAyeAb3FuQvYDYQ9+WR2JHm0+C0oYJaU1C4rs=
golang.org/x/crypto v0.0.0-20191111213947-16651526fdb4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 h1:pXVtWnwHkrWD9ru3sDxY/qFK/bfc0egRovX91EjWjf4=
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c h1:/nJuwDLoL/zrqY6gf57vxC+Pi+pZ8bfhpPkicO5H7W4=
golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0=
golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190326090315-15845e8f865b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
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=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 h1:Hynbrlo6LbYI3H1IqXpkVDOcX/3HiPdhVEuyj5a59RM=
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea h1:Mz1TMnfJDRJLk8S8OPCoJYgrsp/Se/2TBre2+vwX128=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY=
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190106171756-3ef68632349c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190325223049-1d95b17f1b04/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36 h1:j7CmVRD4Kec0+f8VuBAc2Ak2MFfXm5Q2/RxuJLL+76E=
google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k=
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.20.1 h1:ESRXHgpUBG5D2I5mmsQIyYxB/tQIZfSZ8wLyFDf/N/U=
google.golang.org/protobuf v1.20.1/go.mod h1:KqelGeouBkcbcuB3HCk4/YH2tmNLk6YSWA5LIWeI/lY=
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
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=
@@ -327,15 +335,16 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
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.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho=
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/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=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

151
grpc/beaconchain.go Normal file
View File

@@ -0,0 +1,151 @@
// 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 grpc
import (
"context"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/spf13/viper"
"google.golang.org/grpc"
"github.com/golang/protobuf/ptypes/empty"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// FetchChainConfig fetches the chain configuration from the beacon node.
// It tweaks the output to make it easier to work with by setting appropriate
// types.
func FetchChainConfig(conn *grpc.ClientConn) (map[string]interface{}, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
config, err := beaconClient.GetBeaconConfig(ctx, &empty.Empty{})
if err != nil {
return nil, err
}
results := make(map[string]interface{})
for k, v := range config.Config {
// Handle integers
if v == "0" {
results[k] = uint64(0)
continue
}
intVal, err := strconv.ParseUint(v, 10, 64)
if err == nil && intVal != 0 {
results[k] = intVal
continue
}
// Handle byte arrays
if strings.HasPrefix(v, "[") {
vals := strings.Split(v[1:len(v)-1], " ")
res := make([]byte, len(vals))
for i, val := range vals {
intVal, err := strconv.Atoi(val)
if err != nil {
return nil, errors.Wrapf(err, "failed to convert value %q for %s", v, k)
}
res[i] = byte(intVal)
}
results[k] = res
continue
}
// String (or unhandled format)
results[k] = v
}
return results, nil
}
// FetchValidator fetches the validator definition from the beacon node.
func FetchValidator(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.Validator, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
req := &ethpb.GetValidatorRequest{
QueryFilter: &ethpb.GetValidatorRequest_PublicKey{
PublicKey: account.PublicKey().Marshal(),
},
}
return beaconClient.GetValidator(ctx, req)
}
// FetchValidatorByIndex fetches the validator definition from the beacon node.
func FetchValidatorByIndex(conn *grpc.ClientConn, index uint64) (*ethpb.Validator, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
req := &ethpb.GetValidatorRequest{
QueryFilter: &ethpb.GetValidatorRequest_Index{
Index: index,
},
}
return beaconClient.GetValidator(ctx, req)
}
// FetchValidatorInfo fetches current validator info from the beacon node.
func FetchValidatorInfo(conn *grpc.ClientConn, account wtypes.Account) (*ethpb.ValidatorInfo, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
stream, err := beaconClient.StreamValidatorsInfo(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to contact beacon node")
}
changeSet := &ethpb.ValidatorChangeSet{
Action: ethpb.SetAction_SET_VALIDATOR_KEYS,
PublicKeys: [][]byte{account.PublicKey().Marshal()},
}
err = stream.Send(changeSet)
if err != nil {
return nil, errors.Wrap(err, "failed to send validator public key")
}
return stream.Recv()
}
// FetchChainInfo fetches current chain info from the beacon node.
func FetchChainInfo(conn *grpc.ClientConn) (*ethpb.ChainHead, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
return beaconClient.GetChainHead(ctx, &empty.Empty{})
}
// FetchBlock fetches a block at a given slot from the beacon node.
func FetchBlock(conn *grpc.ClientConn, slot uint64) (*ethpb.SignedBeaconBlock, error) {
beaconClient := ethpb.NewBeaconChainClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
req := &ethpb.ListBlocksRequest{
QueryFilter: &ethpb.ListBlocksRequest_Slot{Slot: slot},
}
resp, err := beaconClient.ListBlocks(ctx, req)
if err != nil {
return nil, err
}
if len(resp.BlockContainers) == 0 {
return nil, nil
}
return resp.BlockContainers[0].Block, nil
}

60
grpc/beaconnode.go Normal file
View File

@@ -0,0 +1,60 @@
// 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 grpc
import (
"context"
"github.com/spf13/viper"
"google.golang.org/grpc"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// FetchValidatorIndex fetches the index of a validator.
func FetchValidatorIndex(conn *grpc.ClientConn, account wtypes.Account) (uint64, error) {
validatorClient := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
// Fetch the account.
req := &ethpb.ValidatorIndexRequest{
PublicKey: account.PublicKey().Marshal(),
}
resp, err := validatorClient.ValidatorIndex(ctx, req)
if err != nil {
return 0, err
}
return resp.Index, nil
}
// FetchValidatorState fetches the state of a validator.
func FetchValidatorState(conn *grpc.ClientConn, account wtypes.Account) (ethpb.ValidatorStatus, error) {
validatorClient := ethpb.NewBeaconNodeValidatorClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
// Fetch the account.
req := &ethpb.ValidatorStatusRequest{
PublicKey: account.PublicKey().Marshal(),
}
resp, err := validatorClient.ValidatorStatus(ctx, req)
if err != nil {
return 0, err
}
return resp.Status, nil
}

61
grpc/node.go Normal file
View File

@@ -0,0 +1,61 @@
// 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 grpc
import (
"context"
"time"
"github.com/spf13/viper"
"google.golang.org/grpc"
"github.com/golang/protobuf/ptypes/empty"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
)
// FetchGenesis fetches the genesis time.
func FetchGenesis(conn *grpc.ClientConn) (time.Time, error) {
client := ethpb.NewNodeClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
res, err := client.GetGenesis(ctx, &empty.Empty{})
if err != nil {
return time.Now(), err
}
return time.Unix(res.GetGenesisTime().Seconds, 0), nil
}
// FetchVersion fetches the version and metadata from the server.
func FetchVersion(conn *grpc.ClientConn) (string, string, error) {
client := ethpb.NewNodeClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
version, err := client.GetVersion(ctx, &empty.Empty{})
if err != nil {
return "", "", err
}
return version.Version, version.Metadata, nil
}
// FetchSyncing returns true if the node is syncing, otherwise false.
func FetchSyncing(conn *grpc.ClientConn) (bool, error) {
client := ethpb.NewNodeClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
syncStatus, err := client.GetSyncStatus(ctx, &empty.Empty{})
if err != nil {
return false, err
}
return syncStatus.Syncing, nil
}

71
util/scratchaccount.go Normal file
View File

@@ -0,0 +1,71 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"errors"
"github.com/google/uuid"
types "github.com/wealdtech/go-eth2-types/v2"
)
// ScratchAccount is an account that exists temporarily.
type ScratchAccount struct {
id uuid.UUID
pubKey types.PublicKey
}
// NewScratchAccount creates a new local account.
func NewScratchAccount(pubKey []byte) (*ScratchAccount, error) {
key, err := types.BLSPublicKeyFromBytes(pubKey)
if err != nil {
return nil, err
}
return &ScratchAccount{
id: uuid.New(),
pubKey: key,
}, nil
}
func (a *ScratchAccount) ID() uuid.UUID {
return a.id
}
func (a *ScratchAccount) Name() string {
return "scratch"
}
func (a *ScratchAccount) PublicKey() types.PublicKey {
return a.pubKey
}
func (a *ScratchAccount) Path() string {
return ""
}
func (a *ScratchAccount) Lock() {
}
func (a *ScratchAccount) Unlock([]byte) error {
return nil
}
func (a *ScratchAccount) IsUnlocked() bool {
return false
}
func (a *ScratchAccount) Sign(data []byte) (types.Signature, error) {
return nil, errors.New("Not implemented")
}