Compare commits

...

23 Commits

Author SHA1 Message Date
Jim McDonald
5c741d2b27 Update dependencies. 2021-02-01 19:13:18 +00:00
Jim McDonald
52c76deb5e Add attester duties and slot time commands. 2021-01-24 13:46:35 +00:00
Jim McDonald
c986118f16 Fix typo 2021-01-24 12:25:47 +00:00
Jim McDonald
df6694e3b7 Update tests. 2021-01-02 15:21:56 +00:00
Jim McDonald
a55ad238e6 Add 'node events' command. 2021-01-02 15:20:42 +00:00
Jim McDonald
be21db030e Update chain info fork version type 2021-01-02 10:15:07 +00:00
Jim McDonald
16488c8a40 Add activation epoch to validator info. 2021-01-02 10:13:29 +00:00
Jim McDonald
a7489aa675 Reformat changelog 2020-12-10 07:14:04 +00:00
Jim McDonald
b1647d2f3d Update version. 2020-12-10 00:10:46 +00:00
Jim McDonald
c7f3275dfa Add validtor duties; update validator exit 2020-12-09 20:38:21 +00:00
Jim McDonald
7aeba43338 Add validtor duties; update validator exit 2020-12-09 20:33:30 +00:00
Jim McDonald
688db9ef8c Update dependencies. 2020-12-07 15:21:37 +00:00
Jim McDonald
173883da3e Move core functions to util 2020-12-07 15:18:23 +00:00
Jim McDonald
6077e04619 Move core functions to util 2020-12-07 14:52:08 +00:00
Jim McDonald
95c57363a2 Release 1.7.2 2020-11-23 09:36:28 +00:00
Jim McDonald
9b96b4e34f Update workflow 2020-11-23 09:34:48 +00:00
Jim McDonald
40ba1987cd Add ability to show withdrawal credentials 2020-11-23 08:57:59 +00:00
Jim McDonald
9c08c0a1a4 Add "account derive" command 2020-11-20 19:59:49 +00:00
Jim McDonald
b2360fa2f6 Do not fail verification on missing fork version 2020-11-20 12:21:06 +00:00
Jim McDonald
e7cc6ce18b Merge pull request #26 from OisinKyne/master
Update import/export usage examples to 1.7.0
2020-11-20 00:11:56 +00:00
Jim McDonald
a83e206c89 Additional checks and chattiness for deposit verification 2020-11-19 23:32:27 +00:00
Jim McDonald
947dbdaef6 Bump version 2020-11-19 10:33:56 +00:00
Oisín Kyne
ac87f51047 Update usage examples to 1.7.0 2020-11-18 12:57:20 +00:00
77 changed files with 3452 additions and 232 deletions

View File

@@ -60,19 +60,22 @@ jobs:
run: |
xgo -v -x -ldflags="-X github.com/wealdtech/ethdo/cmd.ReleaseVersion=${RELEASE_VERSION} -s -w -extldflags -static" --targets="windows/amd64" github.com/wealdtech/ethdo
- name: Create windows zip file
- name: Create windows release files
run: |
mv ethdo-windows-4.0-amd64.exe ethdo.exe
sha256sum ethdo.exe >ethdo-${RELEASE_VERSION}-windows.sha256
zip --junk-paths ethdo-${RELEASE_VERSION}-windows-exe.zip ethdo.exe
- name: Create linux AMD64 tgz file
run: |
mv ethdo-linux-amd64 ethdo
sha256sum ethdo >ethdo-${RELEASE_VERSION}-linux-amd64.sha256
tar zcf ethdo-${RELEASE_VERSION}-linux-amd64.tar.gz ethdo
- name: Create linux ARM64 tgz file
run: |
mv ethdo-linux-arm64 ethdo
sha256sum ethdo >ethdo-${RELEASE_VERSION}-linux-arm64.sha256
tar zcf ethdo-${RELEASE_VERSION}-linux-arm64.tar.gz ethdo
- name: Create release
@@ -83,9 +86,20 @@ jobs:
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ env.RELEASE_VERSION }}
draft: false
draft: true
prerelease: false
- name: Upload windows checksum file
id: upload-release-asset-windows-checksum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-windows.sha256
asset_name: ethdo-${{ env.RELEASE_VERSION }}-windows.sha256
asset_content_type: text/plain
- name: Upload windows zip file
id: upload-release-asset-windows
uses: actions/upload-release-asset@v1
@@ -96,7 +110,18 @@ jobs:
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-windows-exe.zip
asset_name: ethdo-${{ env.RELEASE_VERSION }}-windows-exe.zip
asset_content_type: application/zip
- name: Upload linux AMD64 checksum file
id: upload-release-asset-linux-amd64-checksum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-amd64.sha256
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-amd64.sha256
asset_content_type: text/plain
- name: Upload linux AMD64 tgz file
id: upload-release-asset-linux-amd64
uses: actions/upload-release-asset@v1
@@ -107,7 +132,18 @@ jobs:
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-amd64.tar.gz
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-amd64.tar.gz
asset_content_type: application/gzip
- name: Upload linux ARM64 checksum file
id: upload-release-asset-linux-arm64-checksum
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
asset_name: ethdo-${{ env.RELEASE_VERSION }}-linux-arm64.sha256
asset_content_type: text/plain
- name: Upload linux ARM64 tgz file
id: upload-release-asset-linux-arm64
uses: actions/upload-release-asset@v1

View File

@@ -1,3 +1,21 @@
1.7.4:
- add "slot time"
- add "attester duties"
- add "node events"
- add activation epoch to "validator info"
1.7.3:
- fix issue where base directory was ignored for wallet creation
- new "validator duties" command to display known duties for a given validator
- update go-eth2-client to display correct validator status from prysm
1.7.2:
- new "account derive" command to derive keys directly from a mnemonic and derivation path
- add more output to "deposit verify" to explain operation
1.7.1:
- fix "store not set" issue
1.7.0:
- "validator depositdata" now defaults to mainnet, does not silently fetch fork version from chain
- update deposit data output to version 3, to allow for better deposit checking
@@ -8,12 +26,15 @@
- renamed "--exportpassphrase" and "--importpassphrase" flags to "--passphrase"
- reworked internal structure of account-related commands
- reject weak passphrases by default
1.6.1:
- "attester inclusion" defaults to previous epoch
- output array for launchpad deposit data JSON in all situations
1.6.0:
- update BLS HKDF function to match spec 04
- add --launchpad option to "validator depositdata" to output data in launchpad format
1.5.9:
- fix issue where wallet mnemonics were not normalised to NFKD
- "block info" supports fetching the gensis block (--slot=0)

View File

@@ -19,7 +19,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wallet "github.com/wealdtech/go-eth2-wallet"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
@@ -63,7 +62,7 @@ func input(ctx context.Context) (*dataIn, error) {
// Wallet.
ctx, cancel := context.WithTimeout(ctx, data.timeout)
defer cancel()
data.wallet, err = core.WalletFromInput(ctx)
data.wallet, err = util.WalletFromInput(ctx)
cancel()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain wallet")

View File

@@ -0,0 +1,58 @@
// 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 accountderive
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
type dataIn struct {
quiet bool
// Derivation information.
mnemonic string
path string
// Output options.
showPrivateKey bool
showWithdrawalCredentials bool
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
// Quiet.
data.quiet = viper.GetBool("quiet")
// Mnemonic.
if viper.GetString("mnemonic") == "" {
return nil, errors.New("mnemonic is required")
}
data.mnemonic = viper.GetString("mnemonic")
// Path.
if viper.GetString("path") == "" {
return nil, errors.New("path is required")
}
data.path = viper.GetString("path")
// Show private key.
data.showPrivateKey = viper.GetBool("show-private-key")
// Show withdrawal credentials.
data.showWithdrawalCredentials = viper.GetBool("show-withdrawal-credentials")
return data, nil
}

View File

@@ -0,0 +1,78 @@
// 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 accountderive
import (
"context"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
func TestInput(t *testing.T) {
require.NoError(t, e2types.InitBLS())
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "MnemonicMissing",
vars: map[string]interface{}{
"path": "m/12381/3600/0/0",
},
err: "mnemonic is required",
},
{
name: "PathMissing",
vars: map[string]interface{}{
"mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
},
err: "path is required",
},
{
name: "Good",
vars: map[string]interface{}{
"mnemonic": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
"path": "m/12381/3600/0/0",
},
res: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
path: "m/12381/3600/0/0",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
// Cannot compare accounts directly, so need to check each element individually.
require.Equal(t, test.res.mnemonic, res.mnemonic)
require.Equal(t, test.res.path, res.path)
}
})
}
}

View File

@@ -0,0 +1,53 @@
// 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 accountderive
import (
"context"
"fmt"
"strings"
"github.com/pkg/errors"
e2types "github.com/wealdtech/go-eth2-types/v2"
util "github.com/wealdtech/go-eth2-util"
)
type dataOut struct {
showPrivateKey bool
showWithdrawalCredentials bool
key *e2types.BLSPrivateKey
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.key == nil {
return "", errors.New("no key")
}
builder := strings.Builder{}
if data.showPrivateKey {
builder.WriteString(fmt.Sprintf("Private key: %#x\n", data.key.Marshal()))
}
builder.WriteString(fmt.Sprintf("Public key: %#x", data.key.PublicKey().Marshal()))
if data.showWithdrawalCredentials {
withdrawalCredentials := util.SHA256(data.key.PublicKey().Marshal())
withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX
builder.WriteString(fmt.Sprintf("\nWithdrawal credentials: %#x", withdrawalCredentials))
}
return builder.String(), nil
}

View File

@@ -0,0 +1,98 @@
// 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 accountderive
import (
"context"
"encoding/hex"
"strings"
"testing"
"github.com/stretchr/testify/require"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
func blsPrivateKey(input string) *e2types.BLSPrivateKey {
data, err := hex.DecodeString(strings.TrimPrefix(input, "0x"))
key, err := e2types.BLSPrivateKeyFromBytes(data)
if err != nil {
panic(err)
}
return key
}
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
needs []string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "KeyMissing",
dataOut: &dataOut{},
err: "no key",
},
{
name: "Good",
dataOut: &dataOut{
key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"),
},
needs: []string{"Public key"},
},
{
name: "PrivatKey",
dataOut: &dataOut{
key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"),
showPrivateKey: true,
},
needs: []string{"Public key", "Private key"},
},
{
name: "WithdrawalCredentials",
dataOut: &dataOut{
key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"),
showWithdrawalCredentials: true,
},
needs: []string{"Public key", "Withdrawal credentials"},
},
{
name: "All",
dataOut: &dataOut{
key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"),
showPrivateKey: true,
showWithdrawalCredentials: true,
},
needs: []string{"Public key", "Private key", "Withdrawal credentials"},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
for _, need := range test.needs {
require.Contains(t, res, need)
}
}
})
}
}

View File

@@ -0,0 +1,72 @@
// 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 accountderive
import (
"context"
"regexp"
"strings"
"github.com/pkg/errors"
"github.com/tyler-smith/go-bip39"
util "github.com/wealdtech/go-eth2-util"
"golang.org/x/text/unicode/norm"
)
// pathRegex is the regular expression that matches an HD path.
var pathRegex = regexp.MustCompile("^m/[0-9]+/[0-9]+(/[0-9+])+")
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
// If there are more than 24 words we treat the additional characters as the passphrase.
mnemonicParts := strings.Split(data.mnemonic, " ")
mnemonicPassphrase := ""
if len(mnemonicParts) > 24 {
data.mnemonic = strings.Join(mnemonicParts[:24], " ")
mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ")
}
// Normalise the input.
data.mnemonic = string(norm.NFKD.Bytes([]byte(data.mnemonic)))
mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase)))
if !bip39.IsMnemonicValid(data.mnemonic) {
return nil, errors.New("mnemonic is invalid")
}
// Create seed from mnemonic and passphrase.
seed := bip39.NewSeed(data.mnemonic, mnemonicPassphrase)
// Ensure the path is valid.
match := pathRegex.Match([]byte(data.path))
if !match {
return nil, errors.New("path does not match expected format m/…")
}
// Derive private key from seed and path.
key, err := util.PrivateKeyFromSeedAndPath(seed, data.path)
if err != nil {
return nil, errors.Wrap(err, "failed to generate key")
}
results := &dataOut{
showPrivateKey: data.showPrivateKey,
showWithdrawalCredentials: data.showWithdrawalCredentials,
key: key,
}
return results, nil
}

View File

@@ -0,0 +1,97 @@
// 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 accountderive
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
func TestProcess(t *testing.T) {
require.NoError(t, e2types.InitBLS())
tests := []struct {
name string
dataIn *dataIn
privKey []byte
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "MnemonicMissing",
dataIn: &dataIn{
path: "m/12381/3600/0/0",
},
err: "mnemonic is invalid",
},
{
name: "MnemonicInvalid",
dataIn: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
path: "m/12381/3600/0/0",
},
err: "mnemonic is invalid",
},
{
name: "PathMissing",
dataIn: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
},
err: "path does not match expected format m/…",
},
{
name: "PathInvalid",
dataIn: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
path: "n/12381/3600/0/0",
},
err: "path does not match expected format m/…",
},
{
name: "Good",
dataIn: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art",
path: "m/12381/3600/0/0",
},
privKey: testutil.HexToBytes("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"),
},
{
name: "Extended",
dataIn: &dataIn{
mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art extended",
path: "m/12381/3600/0/0",
},
privKey: testutil.HexToBytes("0x58c8b280ae035de0452797b52fb62555f27f78541ea2f04b23e7bb0fcd0fc2d6"),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.privKey, res.key.Marshal())
}
})
}
}

49
cmd/account/derive/run.go Normal file
View File

@@ -0,0 +1,49 @@
// 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 accountderive
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// Run runs the account create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if dataIn.quiet {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

View File

@@ -21,7 +21,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wallet "github.com/wealdtech/go-eth2-wallet"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
@@ -60,7 +59,7 @@ func input(ctx context.Context) (*dataIn, error) {
// Wallet.
ctx, cancel := context.WithTimeout(ctx, data.timeout)
defer cancel()
data.wallet, err = core.WalletFromInput(ctx)
data.wallet, err = util.WalletFromInput(ctx)
cancel()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain wallet")

View File

@@ -19,7 +19,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -40,7 +39,7 @@ func input(ctx context.Context) (*dataIn, error) {
data.timeout = viper.GetDuration("timeout")
// Account.
_, data.account, err = core.WalletAndAccountFromInput(ctx)
_, data.account, err = util.WalletAndAccountFromInput(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain acount")
}

View File

@@ -65,7 +65,7 @@ func TestInput(t *testing.T) {
"account": "Unknown/Interop 0",
"passphrase": "ce%NohGhah4ye5ra",
},
err: "failed to obtain acount: faild to open wallet for account: wallet not found",
err: "failed to obtain acount: failed to open wallet for account: wallet not found",
},
{
name: "AccountMissing",
@@ -73,7 +73,7 @@ func TestInput(t *testing.T) {
"timeout": "5s",
"passphrase": "ce%NohGhah4ye5ra",
},
err: "failed to obtain acount: faild to open wallet for account: invalid account format",
err: "failed to obtain acount: failed to open wallet for account: invalid account format",
},
{
name: "AccountWalletOnly",
@@ -91,7 +91,7 @@ func TestInput(t *testing.T) {
"account": "//",
"passphrase": "ce%NohGhah4ye5ra",
},
err: "failed to obtain acount: faild to open wallet for account: invalid account format",
err: "failed to obtain acount: failed to open wallet for account: invalid account format",
},
{
name: "Good",

69
cmd/accountderive.go Normal file
View File

@@ -0,0 +1,69 @@
// 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 (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
accountderive "github.com/wealdtech/ethdo/cmd/account/derive"
)
var accountDeriveCmd = &cobra.Command{
Use: "derive",
Short: "Derive an account",
Long: `Derive an account from a mnemonic and path. For example:
ethdo account derive --mnemonic="..." --path="m/12381/3600/0/0"
In quiet mode this will return 0 if the inputs can derive an account account, otherwise 1.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := accountderive.Run(cmd)
if err != nil {
return err
}
if viper.GetBool("quiet") {
return nil
}
if res != "" {
fmt.Println(res)
}
return nil
},
}
func init() {
accountCmd.AddCommand(accountDeriveCmd)
accountFlags(accountDeriveCmd)
accountDeriveCmd.Flags().String("mnemonic", "", "mnemonic from which to derive the HD seed")
accountDeriveCmd.Flags().String("path", "", "path from which to derive the account")
accountDeriveCmd.Flags().Bool("show-private-key", false, "show private key for derived account")
accountDeriveCmd.Flags().Bool("show-withdrawal-credentials", false, "show withdrawal credentials for derived account")
}
func accountDeriveBindings() {
if err := viper.BindPFlag("mnemonic", accountDeriveCmd.Flags().Lookup("mnemonic")); err != nil {
panic(err)
}
if err := viper.BindPFlag("path", accountDeriveCmd.Flags().Lookup("path")); err != nil {
panic(err)
}
if err := viper.BindPFlag("show-private-key", accountDeriveCmd.Flags().Lookup("show-private-key")); err != nil {
panic(err)
}
if err := viper.BindPFlag("show-withdrawal-credentials", accountDeriveCmd.Flags().Lookup("show-withdrawal-credentials")); err != nil {
panic(err)
}
}

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

View File

@@ -0,0 +1,131 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"encoding/hex"
"fmt"
"strings"
"time"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
json bool
// Chain information.
slotsPerEpoch uint64
// Operation.
validator *api.Validator
eth2Client eth2client.Service
epoch spec.Epoch
account e2wtypes.Account
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
data.json = viper.GetBool("json")
// Account.
var err error
data.account, err = attesterDutiesAccount()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
// Ethereum 2 client.
data.eth2Client, err = util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
// Epoch
epoch := viper.GetInt64("epoch")
if epoch == -1 {
config, err := data.eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
data.slotsPerEpoch = config["SLOTS_PER_EPOCH"].(uint64)
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
genesis, err := data.eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain genesis data")
}
epoch = int64(time.Since(genesis.GenesisTime).Seconds()) / (int64(slotDuration.Seconds()) * int64(data.slotsPerEpoch))
}
data.epoch = spec.Epoch(epoch)
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := util.BestPublicKey(data.account)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain public key for account")
}
copy(pubKeys[0][:], pubKey.Marshal())
validators, err := data.eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, fmt.Sprintf("%d", uint64(data.epoch)*data.slotsPerEpoch), pubKeys)
if err != nil {
return nil, errors.New("failed to obtain validator information")
}
if len(validators) == 0 {
return nil, errors.New("validator is not known")
}
data.validator = validators[0]
return data, nil
}
// attesterDutiesAccount obtains the account for the attester duties command.
func attesterDutiesAccount() (e2wtypes.Account, error) {
var account e2wtypes.Account
var err error
if viper.GetString("account") != "" {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, account, err = util.WalletAndAccountFromPath(ctx, viper.GetString("account"))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
} else {
pubKey := viper.GetString("pubkey")
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(pubKey, "0x"))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", pubKey))
}
account, err = util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", pubKey))
}
}
return account, nil
}

View File

@@ -0,0 +1,96 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"os"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{},
err: "timeout is required",
},
{
name: "AccountMissing",
vars: map[string]interface{}{
"timeout": "5s",
},
err: "failed to obtain account: invalid public key : public key must be 48 bytes",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

View File

@@ -0,0 +1,55 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"encoding/json"
"fmt"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
json bool
duty *api.AttesterDuty
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
if data.duty == nil {
return "No duties found", nil
}
if data.json {
bytes, err := json.Marshal(data.duty)
if err != nil {
return "", errors.Wrap(err, "failed to marshalJSON")
}
return string(bytes), nil
}
return fmt.Sprintf("Validator attesting in slot %d committee %d", data.duty.Slot, data.duty.CommitteeIndex), nil
}

View File

@@ -0,0 +1,85 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"testing"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
)
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
res string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Empty",
dataOut: &dataOut{},
res: "No duties found",
},
{
name: "Present",
dataOut: &dataOut{
duty: &api.AttesterDuty{
PubKey: testutil.HexToPubKey("0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"),
Slot: 1,
ValidatorIndex: 2,
CommitteeIndex: 3,
CommitteeLength: 4,
CommitteesAtSlot: 5,
ValidatorCommitteeIndex: 6,
},
},
res: "Validator attesting in slot 1 committee 3",
},
{
name: "JSON",
dataOut: &dataOut{
json: true,
duty: &api.AttesterDuty{
PubKey: testutil.HexToPubKey("0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"),
Slot: 1,
ValidatorIndex: 2,
CommitteeIndex: 3,
CommitteeLength: 4,
CommitteesAtSlot: 5,
ValidatorCommitteeIndex: 6,
},
},
res: `{"pubkey":"0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95","slot":"1","validator_index":"2","committee_index":"3","committee_length":"4","committees_at_slot":"5","validator_committee_index":"6"}`,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res, res)
}
})
}
}

View File

@@ -0,0 +1,58 @@
// Copyright © 2021 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 attesterduties
import (
"context"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
)
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
duty, err := duty(ctx, data.eth2Client, data.validator, data.epoch, data.slotsPerEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain duty for validator")
}
results.duty = duty
return results, nil
}
func duty(ctx context.Context, eth2Client eth2client.Service, validator *api.Validator, epoch spec.Epoch, slotsPerEpoch uint64) (*api.AttesterDuty, error) {
// Find the attesting slot for the given epoch.
duties, err := eth2Client.(eth2client.AttesterDutiesProvider).AttesterDuties(ctx, epoch, []spec.ValidatorIndex{validator.Index})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain attester duties")
}
if len(duties) == 0 {
return nil, errors.New("validator does not have duty for that epoch")
}
return duties[0], nil
}

View File

@@ -0,0 +1,69 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"os"
"testing"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/attestantio/go-eth2-client/auto"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
eth2Client, err := auto.New(context.Background(),
auto.WithLogLevel(zerolog.Disabled),
auto.WithAddress(os.Getenv("ETHDO_TEST_CONNECTION")),
)
require.NoError(t, err)
tests := []struct {
name string
dataIn *dataIn
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Client",
dataIn: &dataIn{
eth2Client: eth2Client,
slotsPerEpoch: 32,
validator: &api.Validator{
Index: 0,
},
epoch: 100,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@@ -0,0 +1,50 @@
// Copyright © 2021 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 attesterduties
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

View File

@@ -25,7 +25,6 @@ import (
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -69,14 +68,15 @@ func input(ctx context.Context) (*dataIn, error) {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
// Epoch
config, err := data.eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
data.slotsPerEpoch = config["SLOTS_PER_EPOCH"].(uint64)
// Epoch.
epoch := viper.GetInt64("epoch")
if epoch == -1 {
config, err := data.eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
data.slotsPerEpoch = config["SLOTS_PER_EPOCH"].(uint64)
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
genesis, err := data.eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
@@ -89,17 +89,24 @@ func input(ctx context.Context) (*dataIn, error) {
}
data.epoch = spec.Epoch(epoch)
// Validator.
stateID := "head"
if viper.GetInt64("epoch") != -1 {
stateID = fmt.Sprintf("%d", uint64(data.epoch)*data.slotsPerEpoch)
}
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := core.BestPublicKey(data.account)
pubKey, err := util.BestPublicKey(data.account)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain public key for account")
}
copy(pubKeys[0][:], pubKey.Marshal())
validators, err := data.eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, fmt.Sprintf("%d", uint64(data.epoch)*data.slotsPerEpoch), pubKeys)
validators, err := data.eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, stateID, pubKeys)
if err != nil {
return nil, errors.New("failed to obtain validator information")
}
data.validator = validators[0]
for _, validator := range validators {
data.validator = validator
}
return data, nil
}
@@ -111,7 +118,7 @@ func attesterInclusionAccount() (e2wtypes.Account, error) {
if viper.GetString("account") != "" {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, account, err = core.WalletAndAccountFromPath(ctx, viper.GetString("account"))
_, account, err = util.WalletAndAccountFromPath(ctx, viper.GetString("account"))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}

View File

@@ -67,7 +67,7 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
}
}
}
return nil, errors.New("not found")
return results, nil
}
func duty(ctx context.Context, eth2Client eth2client.Service, validator *api.Validator, epoch spec.Epoch, slotsPerEpoch uint64) (*api.AttesterDuty, error) {

65
cmd/attesterduties.go Normal file
View File

@@ -0,0 +1,65 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
attesterduties "github.com/wealdtech/ethdo/cmd/attester/duties"
)
var attesterDutiesCmd = &cobra.Command{
Use: "duties",
Short: "Obtain information about duties of an attester",
Long: `Obtain information about dutes of an attester. For example:
ethdo attester duties --account=Validators/00001 --epoch=12345
In quiet mode this will return 0 if a duty from the attester is found, otherwise 1.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := attesterduties.Run(cmd)
if err != nil {
return err
}
if viper.GetBool("quiet") {
return nil
}
if res != "" {
fmt.Println(res)
}
return nil
},
}
func init() {
attesterCmd.AddCommand(attesterDutiesCmd)
attesterFlags(attesterDutiesCmd)
attesterDutiesCmd.Flags().Int64("epoch", -1, "the last complete epoch")
attesterDutiesCmd.Flags().String("pubkey", "", "the public key of the attester")
attesterDutiesCmd.Flags().Bool("json", false, "Generate JSON data for an exit; do not broadcast to network")
}
func attesterDutiesBindings() {
if err := viper.BindPFlag("epoch", attesterDutiesCmd.Flags().Lookup("epoch")); err != nil {
panic(err)
}
if err := viper.BindPFlag("pubkey", attesterDutiesCmd.Flags().Lookup("pubkey")); err != nil {
panic(err)
}
if err := viper.BindPFlag("json", attesterDutiesCmd.Flags().Lookup("json")); err != nil {
panic(err)
}
}

View File

@@ -57,7 +57,7 @@ In quiet mode this will return 0 if the chain information can be obtained, other
outputIf(verbose, fmt.Sprintf("Genesis timestamp: %v", genesis.GenesisTime.Unix()))
}
fmt.Printf("Genesis validators root: %#x\n", genesis.GenesisValidatorsRoot)
fmt.Printf("Genesis fork version: %#x\n", config["GENESIS_FORK_VERSION"].([]byte))
fmt.Printf("Genesis fork version: %x\n", config["GENESIS_FORK_VERSION"].(spec.Version))
fmt.Printf("Seconds per slot: %d\n", int(config["SECONDS_PER_SLOT"].(time.Duration).Seconds()))
fmt.Printf("Slots per epoch: %d\n", config["SLOTS_PER_EPOCH"].(uint64))

View File

@@ -21,8 +21,8 @@ import (
"os"
"strings"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/spf13/cobra"
"github.com/wealdtech/ethdo/util"
e2types "github.com/wealdtech/go-eth2-types/v2"
@@ -34,6 +34,7 @@ var depositVerifyData string
var depositVerifyWithdrawalPubKey string
var depositVerifyValidatorPubKey string
var depositVerifyDepositAmount string
var depositVerifyForkVersion string
var depositVerifyCmd = &cobra.Command{
Use: "verify",
@@ -98,17 +99,21 @@ In quiet mode this will return 0 if the the data is verified correctly, otherwis
}
failures := false
for i, deposit := range deposits {
for _, deposit := range deposits {
if deposit.Amount == 0 {
deposit.Amount = depositAmount
}
verified, err := verifyDeposit(deposit, withdrawalCredentials, validatorPubKeys, depositAmount)
errCheck(err, fmt.Sprintf("Error attempting to verify deposit %d", i))
errCheck(err, fmt.Sprintf("Error attempting to verify deposit %q", deposit.Name))
depositName := deposit.Name
if depositName == "" {
depositName = "Deposit"
}
if !verified {
failures = true
outputIf(!quiet, fmt.Sprintf("Deposit %q failed verification", deposit.Name))
outputIf(!quiet, fmt.Sprintf("%s failed verification", depositName))
} else {
outputIf(quiet, fmt.Sprintf("Deposit %q verified", deposit.Name))
outputIf(!quiet, fmt.Sprintf("%s verified", depositName))
}
}
@@ -175,44 +180,80 @@ func validatorPubKeysFromInput(input string) (map[[48]byte]bool, error) {
}
func verifyDeposit(deposit *util.DepositInfo, withdrawalCredentials []byte, validatorPubKeys map[[48]byte]bool, amount uint64) (bool, error) {
if withdrawalCredentials != nil {
if withdrawalCredentials == nil {
outputIf(!quiet, "Withdrawal public key not supplied; withdrawal credentials NOT checked")
} else {
if !bytes.Equal(deposit.WithdrawalCredentials, withdrawalCredentials) {
return false, errors.New("withdrawal credentials incorrect")
outputIf(!quiet, "Withdrawal public key incorrect")
return false, nil
}
outputIf(verbose, "Withdrawal credentials verified")
outputIf(!quiet, "Withdrawal credentials verified")
}
if amount != 0 {
if amount == 0 {
outputIf(!quiet, "Amount not supplied; NOT checked")
} else {
if deposit.Amount != amount {
return false, errors.New("deposit value incorrect")
outputIf(!quiet, "Amount incorrect")
return false, nil
}
outputIf(verbose, "Amount verified")
outputIf(!quiet, "Amount verified")
}
if len(validatorPubKeys) != 0 {
if len(validatorPubKeys) == 0 {
outputIf(!quiet, "Validator public key not suppled; NOT checked")
} else {
var key [48]byte
copy(key[:], deposit.PublicKey)
if _, exists := validatorPubKeys[key]; !exists {
return false, errors.New("validator public key incorrect")
outputIf(!quiet, "Validator public key incorrect")
return false, nil
}
outputIf(verbose, "Validator public key verified")
outputIf(!quiet, "Validator public key verified")
}
depositData := &ethpb.Deposit_Data{
PublicKey: deposit.PublicKey,
var pubKey spec.BLSPubKey
copy(pubKey[:], deposit.PublicKey)
var signature spec.BLSSignature
copy(signature[:], deposit.Signature)
depositData := &spec.DepositData{
PublicKey: pubKey,
WithdrawalCredentials: deposit.WithdrawalCredentials,
Amount: deposit.Amount,
Signature: deposit.Signature,
Amount: spec.Gwei(deposit.Amount),
Signature: signature,
}
depositDataRoot, err := depositData.HashTreeRoot()
if err != nil {
return false, errors.Wrap(err, "failed to generate deposit data root")
}
if !bytes.Equal(deposit.DepositDataRoot, depositDataRoot[:]) {
return false, errors.New("deposit data root incorrect")
}
outputIf(debug, "Deposit data root verified")
outputIf(verbose, "Deposit verified")
if bytes.Equal(deposit.DepositDataRoot, depositDataRoot[:]) {
outputIf(!quiet, "Deposit data root verified")
} else {
outputIf(!quiet, "Deposit data root incorrect")
return false, nil
}
if len(deposit.ForkVersion) == 0 {
if depositVerifyForkVersion != "" {
outputIf(!quiet, "Data format does not contain fork version for verification; NOT verified")
}
} else {
if depositVerifyForkVersion == "" {
outputIf(!quiet, "fork version not supplied; NOT checked")
} else {
forkVersion, err := hex.DecodeString(strings.TrimPrefix(depositVerifyForkVersion, "0x"))
if err != nil {
return false, errors.Wrap(err, "failed to decode fork version")
}
if bytes.Equal(deposit.ForkVersion, forkVersion[:]) {
outputIf(!quiet, "Fork version verified")
} else {
outputIf(!quiet, "Fork version incorrect")
return false, nil
}
}
}
return true, nil
}
@@ -222,6 +263,7 @@ func init() {
depositFlags(depositVerifyCmd)
depositVerifyCmd.Flags().StringVar(&depositVerifyData, "data", "", "JSON data, or path to JSON data")
depositVerifyCmd.Flags().StringVar(&depositVerifyWithdrawalPubKey, "withdrawalpubkey", "", "Public key of the account to which the validator funds will be withdrawn")
depositVerifyCmd.Flags().StringVar(&depositVerifyDepositAmount, "depositvalue", "", "Value of the amount to be deposited")
depositVerifyCmd.Flags().StringVar(&depositVerifyDepositAmount, "depositvalue", "32 Ether", "Value of the amount to be deposited")
depositVerifyCmd.Flags().StringVar(&depositVerifyValidatorPubKey, "validatorpubkey", "", "Public key(s) of the account(s) that will be carrying out validation")
depositVerifyCmd.Flags().StringVar(&depositVerifyForkVersion, "forkversion", "0x00000000", "Fork version of the chain of the deposit")
}

View File

@@ -50,8 +50,8 @@ In quiet mode this will return 0 if the the exit is verified correctly, otherwis
account, err := exitVerifyAccount(ctx)
errCheck(err, "Failed to obtain account")
assert(viper.GetString("exit.data") != "", "exit data is required")
data, err := obtainExitData(viper.GetString("exit.Data"))
assert(viper.GetString("exit") != "", "exit is required")
data, err := obtainExitData(viper.GetString("exit"))
errCheck(err, "Failed to obtain exit data")
// Confirm signature is good.
@@ -62,13 +62,17 @@ In quiet mode this will return 0 if the the exit is verified correctly, otherwis
errCheck(err, "Failed to obtain beacon chain genesis")
domain := e2types.Domain(e2types.DomainVoluntaryExit, data.ForkVersion[:], genesis.GenesisValidatorsRoot[:])
var exitDomain spec.Domain
copy(exitDomain[:], domain)
exit := &spec.VoluntaryExit{
Epoch: data.Data.Message.Epoch,
ValidatorIndex: data.Data.Message.ValidatorIndex,
Epoch: data.Exit.Message.Epoch,
ValidatorIndex: data.Exit.Message.ValidatorIndex,
}
sig, err := e2types.BLSSignatureFromBytes(data.Data.Signature[:])
exitRoot, err := exit.HashTreeRoot()
errCheck(err, "Failed to obtain exit hash tree root")
sig, err := e2types.BLSSignatureFromBytes(data.Exit.Signature[:])
errCheck(err, "Invalid signature")
verified, err := verifyStruct(account, exit, domain, sig)
verified, err := util.VerifyRoot(account, exitRoot, exitDomain, sig)
errCheck(err, "Failed to verify voluntary exit")
assert(verified, "Voluntary exit failed to verify")
@@ -130,12 +134,12 @@ func exitVerifyAccount(ctx context.Context) (e2wtypes.Account, error) {
func init() {
exitCmd.AddCommand(exitVerifyCmd)
exitFlags(exitVerifyCmd)
exitVerifyCmd.Flags().String("data", "", "JSON data, or path to JSON data")
exitVerifyCmd.Flags().String("exit", "", "JSON data, or path to JSON data")
exitVerifyCmd.Flags().StringVar(&exitVerifyPubKey, "pubkey", "", "Public key for which to verify exit")
}
func exitVerifyBindings() {
if err := viper.BindPFlag("data", exitVerifyCmd.Flags().Lookup("data")); err != nil {
if err := viper.BindPFlag("exit", exitVerifyCmd.Flags().Lookup("exit")); err != nil {
panic(err)
}
}

59
cmd/node/events/input.go Normal file
View File

@@ -0,0 +1,59 @@
// 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 nodeevents
import (
"context"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Operation.
topics []string
eth2Client eth2client.Service
jsonOutput bool
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
data.jsonOutput = viper.GetBool("json")
data.topics = viper.GetStringSlice("topics")
var err error
data.eth2Client, err = util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
return data, nil
}

View File

@@ -0,0 +1,109 @@
// 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 nodeevents
import (
"context"
"os"
"testing"
"time"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{},
err: "timeout is required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
{
name: "ConnectionBad",
vars: map[string]interface{}{
"timeout": "5s",
"connection": "localhost:1",
"topics": []string{"one", "two"},
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: failed to connect to Ethereum 2 client with any known method",
},
{
name: "TopicsNil",
vars: map[string]interface{}{
"timeout": "5s",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
},
res: &dataIn{
timeout: 5 * time.Second,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
require.Equal(t, test.res.topics, res.topics)
}
})
}
}

View File

@@ -0,0 +1,52 @@
// 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 nodeevents
import (
"context"
"encoding/json"
"fmt"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
var jsonOutput bool
func process(ctx context.Context, data *dataIn) error {
if data == nil {
return errors.New("no data")
}
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, data.topics, eventHandler)
if err != nil {
return errors.Wrap(err, "failed to connect for events")
}
<-ctx.Done()
return nil
}
func eventHandler(event *api.Event) {
if event.Data == nil {
return
}
data, err := json.Marshal(event)
if err == nil {
fmt.Println(string(data))
}
}

View File

@@ -0,0 +1,74 @@
// 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 nodeevents
import (
"context"
"os"
"testing"
"github.com/attestantio/go-eth2-client/auto"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
os.Setenv("ETHDO_ALLOW_INSECURE_CONNECTIONS", "true")
eth2Client, err := auto.New(context.Background(),
auto.WithLogLevel(zerolog.Disabled),
auto.WithAddress(os.Getenv("ETHDO_TEST_CONNECTION")),
)
require.NoError(t, err)
tests := []struct {
name string
dataIn *dataIn
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "TopicsNil",
dataIn: &dataIn{
eth2Client: eth2Client,
},
err: "failed to connect for events: no topics supplied",
},
{
name: "TopicsUnknown",
dataIn: &dataIn{
eth2Client: eth2Client,
topics: []string{"foo"},
},
err: "failed to connect for events: unsupported event topic foo",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

41
cmd/node/events/run.go Normal file
View File

@@ -0,0 +1,41 @@
// 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 nodeevents
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
if err := process(ctx, dataIn); err != nil {
return "", errors.Wrap(err, "failed to process")
}
// Process generates all output.
return "", nil
}

52
cmd/nodeevents.go Normal file
View File

@@ -0,0 +1,52 @@
// Copyright © 2019 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
nodeevents "github.com/wealdtech/ethdo/cmd/node/events"
)
var nodeEventsCmd = &cobra.Command{
Use: "events",
Short: "Report events from a node",
Long: `Report events from a node. For example:
ethdo node events --events=head,chain_reorg.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := nodeevents.Run(cmd)
if err != nil {
return err
}
if res != "" {
fmt.Println(res)
}
return nil
},
}
func init() {
nodeCmd.AddCommand(nodeEventsCmd)
nodeFlags(nodeEventsCmd)
nodeEventsCmd.Flags().StringSlice("topics", nil, "The topics of events for which to listen (attestation,block,chain_reorg,finalized_checkpoint,head,voluntary_exit)")
}
func nodeEventsBindings() {
if err := viper.BindPFlag("topics", nodeEventsCmd.Flags().Lookup("topics")); err != nil {
panic(err)
}
}

32
cmd/proposer.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"
)
// proposerCmd represents the proposer command
var proposerCmd = &cobra.Command{
Use: "proposer",
Short: "Obtain information about Ethereum 2 proposers",
Long: "Obtain information about Ethereum 2 proposers",
}
func init() {
RootCmd.AddCommand(proposerCmd)
}
func proposerFlags(cmd *cobra.Command) {
}

View File

@@ -25,7 +25,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
@@ -65,16 +64,26 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
switch fmt.Sprintf("%s/%s", cmd.Parent().Name(), cmd.Name()) {
case "account/create":
accountCreateBindings()
case "account/derive":
accountDeriveBindings()
case "account/import":
accountImportBindings()
case "attester/duties":
attesterDutiesBindings()
case "attester/inclusion":
attesterInclusionBindings()
case "block/info":
blockInfoBindings()
case "exit/verify":
exitVerifyBindings()
case "node/events":
nodeEventsBindings()
case "slot/time":
slotTimeBindings()
case "validator/depositdata":
validatorDepositdataBindings()
case "validator/duties":
validatorDutiesBindings()
case "validator/exit":
validatorExitBindings()
case "validator/info":
@@ -92,7 +101,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
fmt.Println("Cannot supply both quiet and debug flags")
}
if err := core.SetupStore(); err != nil {
if err := util.SetupStore(); err != nil {
return err
}
@@ -103,7 +112,6 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(_exitFailure)
}
}
@@ -298,7 +306,7 @@ func walletAndAccountFromInput(ctx context.Context) (e2wtypes.Wallet, e2wtypes.A
func walletAndAccountFromPath(ctx context.Context, path string) (e2wtypes.Wallet, e2wtypes.Account, error) {
wallet, err := walletFromPath(ctx, path)
if err != nil {
return nil, nil, errors.Wrap(err, "faild to open wallet for account")
return nil, nil, errors.Wrap(err, "failed to open wallet for account")
}
_, accountName, err := e2wallet.WalletAndAccountNames(path)
if err != nil {

View File

@@ -18,8 +18,10 @@ import (
"fmt"
"os"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
"github.com/wealdtech/go-bytesutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
)
@@ -54,9 +56,11 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
_, account, err := walletAndAccountFromInput(ctx)
errCheck(err, "Failed to obtain account")
var specDomain spec.Domain
copy(specDomain[:], domain)
var fixedSizeData [32]byte
copy(fixedSizeData[:], data)
signature, err := signRoot(account, fixedSizeData, domain)
signature, err := util.SignRoot(account, fixedSizeData, specDomain)
errCheck(err, "Failed to sign")
outputIf(!quiet, fmt.Sprintf("%#x", signature.Marshal()))

View File

@@ -20,6 +20,7 @@ import (
"os"
"strings"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
@@ -64,9 +65,11 @@ In quiet mode this will return 0 if the data can be signed, otherwise 1.`,
errCheck(err, "Failed to obtain account")
outputIf(debug, fmt.Sprintf("Public key is %#x", account.PublicKey().Marshal()))
var specDomain spec.Domain
copy(specDomain[:], domain)
var root [32]byte
copy(root[:], data)
verified, err := verifyRoot(account, root, domain, signature)
verified, err := util.VerifyRoot(account, root, specDomain, signature)
errCheck(err, "Failed to verify data")
assert(verified, "Failed to verify")

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

61
cmd/slot/time/input.go Normal file
View File

@@ -0,0 +1,61 @@
// Copyright © 2021 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 slottime
import (
"context"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Operation.
slot string
eth2Client eth2client.Service
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
if viper.GetString("slot") == "" {
return nil, errors.New("slot is required")
}
data.slot = viper.GetString("slot")
// Ethereum 2 client.
var err error
data.eth2Client, err = util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
return data, nil
}

View File

@@ -0,0 +1,96 @@
// Copyright © 2021 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 slottime
import (
"context"
"os"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{},
err: "timeout is required",
},
{
name: "SlotMissing",
vars: map[string]interface{}{
"timeout": "5s",
},
err: "slot is required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"slot": "1",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

44
cmd/slot/time/output.go Normal file
View File

@@ -0,0 +1,44 @@
// Copyright © 2021 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 slottime
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
startTime time.Time
endTime time.Time
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
if data.verbose {
return fmt.Sprintf("%s - %s", data.startTime, data.endTime), nil
}
return fmt.Sprintf("%s", data.startTime), nil
}

View File

@@ -0,0 +1,64 @@
// Copyright © 2021 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 slottime
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
res string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Normal",
dataOut: &dataOut{
startTime: time.Unix(1606824023, 0),
},
res: "2020-12-01 12:00:23 +0000 GMT",
},
{
name: "Verbose",
dataOut: &dataOut{
startTime: time.Unix(1606824023, 0),
endTime: time.Unix(1606824035, 0),
verbose: true,
},
res: "2020-12-01 12:00:23 +0000 GMT - 2020-12-01 12:00:35 +0000 GMT",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res, res)
}
})
}
}

60
cmd/slot/time/process.go Normal file
View File

@@ -0,0 +1,60 @@
// Copyright © 2021 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 slottime
import (
"context"
"strconv"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
)
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
slot, err := strconv.ParseInt(data.slot, 10, 64)
if err != nil {
return nil, errors.Wrap(err, "invalid slot specified")
}
if slot < 0 {
return nil, errors.New("slot must be a positive integer")
}
genesis, err := data.eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain genesis information")
}
config, err := data.eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain chain specifications")
}
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
results.startTime = genesis.GenesisTime.Add(time.Duration((time.Duration(slot*int64(slotDuration.Seconds())) * time.Second)))
results.endTime = results.startTime.Add(slotDuration)
return results, nil
}

View File

@@ -0,0 +1,76 @@
// Copyright © 2021 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 slottime
import (
"context"
"os"
"testing"
"time"
"github.com/attestantio/go-eth2-client/auto"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
eth2Client, err := auto.New(context.Background(),
auto.WithLogLevel(zerolog.Disabled),
auto.WithAddress(os.Getenv("ETHDO_TEST_CONNECTION")),
)
require.NoError(t, err)
tests := []struct {
name string
dataIn *dataIn
expected time.Time
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Slot0",
dataIn: &dataIn{
eth2Client: eth2Client,
slot: "0",
},
expected: time.Unix(1606824023, 0),
},
{
name: "Slot1",
dataIn: &dataIn{
eth2Client: eth2Client,
slot: "1",
},
expected: time.Unix(1606824035, 0),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.expected, res.startTime)
}
})
}
}

50
cmd/slot/time/run.go Normal file
View File

@@ -0,0 +1,50 @@
// Copyright © 2021 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 slottime
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

57
cmd/slottime.go Normal file
View File

@@ -0,0 +1,57 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
slottime "github.com/wealdtech/ethdo/cmd/slot/time"
)
var slotTimeCmd = &cobra.Command{
Use: "time",
Short: "Obtain the time for a slot",
Long: `Obtain the time(s) for a slot. For example:
ethdo slot time --slot=12345
In quiet mode this will return 0.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := slottime.Run(cmd)
if err != nil {
return err
}
if viper.GetBool("quiet") {
return nil
}
if res != "" {
fmt.Println(res)
}
return nil
},
}
func init() {
slotCmd.AddCommand(slotTimeCmd)
slotFlags(slotTimeCmd)
slotTimeCmd.Flags().String("slot", "", "the ID of the slot to fetch")
}
func slotTimeBindings() {
if err := viper.BindPFlag("slot", slotTimeCmd.Flags().Lookup("slot")); err != nil {
panic(err)
}
}

View File

@@ -21,7 +21,6 @@ import (
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
ethdoutil "github.com/wealdtech/ethdo/util"
e2types "github.com/wealdtech/go-eth2-types/v2"
util "github.com/wealdtech/go-eth2-util"
@@ -52,7 +51,7 @@ func input() (*dataIn, error) {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, data.validatorAccounts, err = core.WalletAndAccountsFromPath(ctx, viper.GetString("validatoraccount"))
_, data.validatorAccounts, err = ethdoutil.WalletAndAccountsFromPath(ctx, viper.GetString("validatoraccount"))
if err != nil {
return nil, errors.New("failed to obtain validator account")
}
@@ -75,11 +74,11 @@ func input() (*dataIn, error) {
case viper.GetString("withdrawalaccount") != "":
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, withdrawalAccount, err := core.WalletAndAccountFromPath(ctx, viper.GetString("withdrawalaccount"))
_, withdrawalAccount, err := ethdoutil.WalletAndAccountFromPath(ctx, viper.GetString("withdrawalaccount"))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain withdrawal account")
}
pubKey, err := core.BestPublicKey(withdrawalAccount)
pubKey, err := ethdoutil.BestPublicKey(withdrawalAccount)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain public key for withdrawal account")
}

View File

@@ -105,6 +105,12 @@ func validatorDepositDataOutputRaw(datum *dataOut) (string, error) {
}
func validatorDepositDataOutputLaunchpad(datum *dataOut) (string, error) {
// Map of fork version to network name.
forkVersionMap := map[spec.Version]string{
[4]byte{0x00, 0x00, 0x00, 0x00}: "mainnet",
[4]byte{0x00, 0x00, 0x20, 0x09}: "pyrmont",
}
if datum.validatorPubKey == nil {
return "", errors.New("validator public key required")
}
@@ -124,7 +130,11 @@ func validatorDepositDataOutputLaunchpad(datum *dataOut) (string, error) {
return "", errors.New("deposit data root required")
}
output := fmt.Sprintf(`{"pubkey":"%x","withdrawal_credentials":"%x","amount":%d,"signature":"%x","deposit_message_root":"%x","deposit_data_root":"%x","fork_version":"%x"}`,
networkName := "unknown"
if network, exists := forkVersionMap[*datum.forkVersion]; exists {
networkName = network
}
output := fmt.Sprintf(`{"pubkey":"%x","withdrawal_credentials":"%x","amount":%d,"signature":"%x","deposit_message_root":"%x","deposit_data_root":"%x","fork_version":"%x","eth2_network_name":"%s","deposit_cli_version":"1.1.0"}`,
*datum.validatorPubKey,
datum.withdrawalCredentials,
datum.amount,
@@ -132,6 +142,7 @@ func validatorDepositDataOutputLaunchpad(datum *dataOut) (string, error) {
*datum.depositMessageRoot,
*datum.depositDataRoot,
*datum.forkVersion,
networkName,
)
return output, nil
}

View File

@@ -255,7 +255,7 @@ func TestOutputLaunchpad(t *testing.T) {
}
var forkVersion *spec.Version
{
tmp := testutil.HexToVersion("0x01020304")
tmp := testutil.HexToVersion("0x00002009")
forkVersion = &tmp
}
var depositDataRoot *spec.Root
@@ -418,7 +418,7 @@ func TestOutputLaunchpad(t *testing.T) {
depositMessageRoot: depositMessageRoot,
},
},
res: `[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"}]`,
res: `[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"00002009","eth2_network_name":"pyrmont","deposit_cli_version":"1.1.0"}]`,
},
{
name: "Double",
@@ -446,7 +446,7 @@ func TestOutputLaunchpad(t *testing.T) {
depositMessageRoot: depositMessageRoot2,
},
},
res: `[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"01020304"},{"pubkey":"b89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b","withdrawal_credentials":"00ec7ef7780c9d151597924036262dd28dc60e1228f4da6fecf9d402cb3f3594","amount":32000000000,"signature":"911fe0766e8b79d711dde46bc2142eb51e35be99e5f7da505af9eaad85707bbb8013f0dea35e30403b3e57bb13054c1d0d389aceeba1d4160a148026212c7e017044e3ea69cd96fbd23b6aa9fd1e6f7e82494fbd5f8fc75856711a6b8998926e","deposit_message_root":"bb4b6184b25873cdf430df3838c8d3e3d16cf3dc3b214e2f3ab7df9e6d5a9b52","deposit_data_root":"3b51670e9f266d44c879682a230d60f0d534c64ab25ee68700fe3adb17ddfcab","fork_version":"01020304"}]`,
res: `[{"pubkey":"a99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c","withdrawal_credentials":"00fad2a6bfb0e7f1f0f45460944fbd8dfa7f37da06a4d13b3983cc90bb46963b","amount":32000000000,"signature":"b7a757a4c506ac6ac5f2d23e065de7d00dc9f5a6a3f9610a8b60b65f166379139ae382c91ecbbf5c9fabc34b1cd2cf8f0211488d50d8754716d8e72e17c1a00b5d9b37cc73767946790ebe66cf9669abfc5c25c67e1e2d1c2e11429d149c25a2","deposit_message_root":"139b510ea7f2788ab82da1f427d6cbe1db147c15a053db738ad5500cd83754a6","deposit_data_root":"9e51b386f4271c18149dd0f73297a26a4a8c15c3622c44af79c92446f44a3554","fork_version":"00002009","eth2_network_name":"pyrmont","deposit_cli_version":"1.1.0"},{"pubkey":"b89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b","withdrawal_credentials":"00ec7ef7780c9d151597924036262dd28dc60e1228f4da6fecf9d402cb3f3594","amount":32000000000,"signature":"911fe0766e8b79d711dde46bc2142eb51e35be99e5f7da505af9eaad85707bbb8013f0dea35e30403b3e57bb13054c1d0d389aceeba1d4160a148026212c7e017044e3ea69cd96fbd23b6aa9fd1e6f7e82494fbd5f8fc75856711a6b8998926e","deposit_message_root":"bb4b6184b25873cdf430df3838c8d3e3d16cf3dc3b214e2f3ab7df9e6d5a9b52","deposit_data_root":"3b51670e9f266d44c879682a230d60f0d534c64ab25ee68700fe3adb17ddfcab","fork_version":"00002009","eth2_network_name":"pyrmont","deposit_cli_version":"1.1.0"}]`,
},
}

View File

@@ -19,8 +19,8 @@ import (
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/signing"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -32,7 +32,7 @@ func process(data *dataIn) ([]*dataOut, error) {
results := make([]*dataOut, 0)
for _, validatorAccount := range data.validatorAccounts {
validatorPubKey, err := core.BestPublicKey(validatorAccount)
validatorPubKey, err := util.BestPublicKey(validatorAccount)
if err != nil {
return nil, errors.Wrap(err, "validator account does not provide a public key")
}

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 validatorduties
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Ethereum 2 connection.
eth2Client string
allowInsecure bool
// Operation.
account string
pubKey string
index string
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
// Ethereum 2 connection.
data.eth2Client = viper.GetString("connection")
if data.eth2Client == "" {
return nil, errors.New("connection is required")
}
data.allowInsecure = viper.GetBool("allow-insecure-connections")
// Account.
data.account = viper.GetString("account")
// PubKey.
data.pubKey = viper.GetString("pubkey")
// ID.
data.index = viper.GetString("index")
if data.account == "" && data.pubKey == "" && data.index == "" {
return nil, errors.New("account, pubkey or index required")
}
return data, nil
}

View File

@@ -0,0 +1,100 @@
// 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 validatorduties
import (
"context"
"os"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{
"connection": "http://locahost:4000",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "timeout is required",
},
{
name: "AccountMissing",
vars: map[string]interface{}{
"timeout": "5s",
"connection": "http://locahost:4000",
},
err: "account, pubkey or index required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "connection is required",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

View File

@@ -0,0 +1,112 @@
// 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 validatorduties
import (
"context"
"fmt"
"strings"
"time"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
genesisTime time.Time
slotDuration time.Duration
slotsPerEpoch uint64
thisEpochAttesterDuty *api.AttesterDuty
thisEpochProposerDuties []*api.ProposerDuty
nextEpochAttesterDuty *api.AttesterDuty
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
builder := strings.Builder{}
now := time.Now()
builder.WriteString("Current time: ")
builder.WriteString(now.Format("15:04:05\n"))
if data.thisEpochAttesterDuty != nil {
thisEpochAttesterSlot := data.thisEpochAttesterDuty.Slot
thisSlotStart := data.genesisTime.Add(time.Duration(thisEpochAttesterSlot) * data.slotDuration)
thisSlotEnd := thisSlotStart.Add(data.slotDuration)
if thisSlotEnd.After(now) {
builder.WriteString("Upcoming attestation slot this epoch: ")
builder.WriteString(thisSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(thisSlotEnd.Format("15:04:05 ("))
until := thisSlotStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
}
for _, proposerDuty := range data.thisEpochProposerDuties {
proposerSlot := proposerDuty.Slot
proposerSlotStart := data.genesisTime.Add(time.Duration(proposerSlot) * data.slotDuration)
proposerSlotEnd := proposerSlotStart.Add(data.slotDuration)
builder.WriteString("Upcoming proposer slot this epoch: ")
builder.WriteString(proposerSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(proposerSlotEnd.Format("15:04:05 ("))
until := proposerSlotStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
if data.nextEpochAttesterDuty != nil {
nextEpochAttesterSlot := data.nextEpochAttesterDuty.Slot
nextSlotStart := data.genesisTime.Add(time.Duration(nextEpochAttesterSlot) * data.slotDuration)
nextSlotEnd := nextSlotStart.Add(data.slotDuration)
builder.WriteString("Upcoming attestation slot next epoch: ")
builder.WriteString(nextSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(nextSlotEnd.Format("15:04:05 ("))
until := nextSlotStart.Sub(now)
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
nextEpoch := uint64(data.nextEpochAttesterDuty.Slot) / data.slotsPerEpoch
nextEpochStart := data.genesisTime.Add(time.Duration(nextEpoch*data.slotsPerEpoch) * data.slotDuration)
builder.WriteString("Next epoch starts ")
builder.WriteString(nextEpochStart.Format("15:04:05 ("))
until = nextEpochStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of epoch)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
return builder.String(), nil
}

View File

@@ -0,0 +1,83 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"strings"
"testing"
"time"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/stretchr/testify/require"
)
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
expected []string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Empty",
dataOut: &dataOut{},
expected: []string{"Current time"},
},
{
name: "Found",
dataOut: &dataOut{
genesisTime: time.Unix(16000000000, 0),
slotDuration: 12 * time.Second,
slotsPerEpoch: 32,
thisEpochAttesterDuty: &api.AttesterDuty{
Slot: spec.Slot(1),
},
thisEpochProposerDuties: []*api.ProposerDuty{
{
Slot: spec.Slot(2),
},
},
nextEpochAttesterDuty: &api.AttesterDuty{
Slot: spec.Slot(40),
},
},
expected: []string{
"Current time",
"Upcoming attestation slot this epoch",
"Upcoming proposer slot this epoch",
"Upcoming attestation slot next epoch",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
for _, expected := range test.expected {
require.True(t, strings.Contains(res, expected))
}
}
})
}
}

View File

@@ -0,0 +1,182 @@
// 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 validatorduties
import (
"context"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
// Ethereum 2 client.
eth2Client, err := util.ConnectToBeaconNode(ctx, data.eth2Client, data.timeout, data.allowInsecure)
if err != nil {
return nil, err
}
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
validatorIndex, err := validatorIndex(ctx, eth2Client, data)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain validator index")
}
// Fetch duties for this and next epoch.
thisEpoch, err := currentEpoch(ctx, eth2Client)
if err != nil {
return nil, errors.Wrap(err, "failed to calculate current epoch")
}
thisEpochAttesterDuty, err := attesterDuty(ctx, eth2Client, validatorIndex, thisEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain this epoch duty for validator")
}
results.thisEpochAttesterDuty = thisEpochAttesterDuty
thisEpochProposerDuties, err := proposerDuties(ctx, eth2Client, validatorIndex, thisEpoch)
results.thisEpochProposerDuties = thisEpochProposerDuties
nextEpoch := thisEpoch + 1
nextEpochAttesterDuty, err := attesterDuty(ctx, eth2Client, validatorIndex, nextEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain next epoch duty for validator")
}
results.nextEpochAttesterDuty = nextEpochAttesterDuty
genesis, err := eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain genesis data")
}
results.genesisTime = genesis.GenesisTime
config, err := eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
results.slotsPerEpoch = config["SLOTS_PER_EPOCH"].(uint64)
results.slotDuration = config["SECONDS_PER_SLOT"].(time.Duration)
return results, nil
}
func attesterDuty(ctx context.Context, eth2Client eth2client.Service, validatorIndex spec.ValidatorIndex, epoch spec.Epoch) (*api.AttesterDuty, error) {
// Find the attesting slot for the given epoch.
duties, err := eth2Client.(eth2client.AttesterDutiesProvider).AttesterDuties(ctx, epoch, []spec.ValidatorIndex{validatorIndex})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain attester duties")
}
if len(duties) == 0 {
return nil, errors.New("validator does not have duty for that epoch")
}
return duties[0], nil
}
func proposerDuties(ctx context.Context, eth2Client eth2client.Service, validatorIndex spec.ValidatorIndex, epoch spec.Epoch) ([]*api.ProposerDuty, error) {
// Fetch the proposer duties for this epoch.
proposerDuties, err := eth2Client.(eth2client.ProposerDutiesProvider).ProposerDuties(ctx, epoch, []spec.ValidatorIndex{validatorIndex})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain proposer duties")
}
return proposerDuties, nil
}
func currentEpoch(ctx context.Context, eth2Client eth2client.Service) (spec.Epoch, error) {
config, err := eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
slotsPerEpoch := config["SLOTS_PER_EPOCH"].(uint64)
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
genesis, err := eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain genesis data")
}
if genesis.GenesisTime.After(time.Now()) {
return spec.Epoch(0), nil
}
return spec.Epoch(uint64(time.Since(genesis.GenesisTime).Seconds()) / (uint64(slotDuration.Seconds()) * slotsPerEpoch)), nil
}
// validatorIndex obtains the index of a validator
func validatorIndex(ctx context.Context, eth2Client eth2client.Service, data *dataIn) (spec.ValidatorIndex, error) {
switch {
case data.account != "":
ctx, cancel := context.WithTimeout(context.Background(), data.timeout)
defer cancel()
_, account, err := util.WalletAndAccountFromPath(ctx, data.account)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain account")
}
return accountToIndex(ctx, account, eth2Client)
case data.pubKey != "":
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(data.pubKey, "0x"))
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", data.pubKey))
}
account, err := util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("invalid public key %s", data.pubKey))
}
return accountToIndex(ctx, account, eth2Client)
case data.index != "":
val, err := strconv.ParseUint(data.index, 10, 64)
if err != nil {
return 0, err
}
return spec.ValidatorIndex(val), nil
default:
return 0, errors.New("no validator")
}
}
func accountToIndex(ctx context.Context, account e2wtypes.Account, eth2Client eth2client.Service) (spec.ValidatorIndex, error) {
pubKey, err := util.BestPublicKey(account)
if err != nil {
return 0, err
}
pubKeys := make([]spec.BLSPubKey, 1)
copy(pubKeys[0][:], pubKey.Marshal())
validators, err := eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, "head", pubKeys)
if err != nil {
return 0, err
}
for index := range validators {
return index, nil
}
return 0, errors.New("validator not found")
}

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 validatorduties
import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
tests := []struct {
name string
dataIn *dataIn
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Client",
dataIn: &dataIn{
timeout: 5 * time.Second,
eth2Client: os.Getenv("ETHDO_TEST_CONNECTION"),
allowInsecure: true,
index: "1",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@@ -0,0 +1,50 @@
// 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 validatorduties
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

View File

@@ -24,7 +24,6 @@ import (
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -80,13 +79,13 @@ func inputJSON(ctx context.Context, data *dataIn) (*dataIn, error) {
if err != nil {
return nil, err
}
data.signedVoluntaryExit = validatorData.Data
data.signedVoluntaryExit = validatorData.Exit
return inputChainData(ctx, data)
}
func inputAccount(ctx context.Context, data *dataIn) (*dataIn, error) {
var err error
_, data.account, err = core.WalletAndAccountFromInput(ctx)
_, data.account, err = util.WalletAndAccountFromInput(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain acount")
}

View File

@@ -91,9 +91,10 @@ func TestInput(t *testing.T) {
{
name: "KeyGood",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
},
res: &dataIn{
timeout: 5 * time.Second,
@@ -102,9 +103,10 @@ func TestInput(t *testing.T) {
{
name: "AccountUnknown",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"account": "Test wallet/unknown",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"account": "Test wallet/unknown",
},
res: &dataIn{
timeout: 5 * time.Second,
@@ -114,9 +116,10 @@ func TestInput(t *testing.T) {
{
name: "AccountGood",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"account": "Test wallet/Interop 0",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"account": "Test wallet/Interop 0",
},
res: &dataIn{
timeout: 5 * time.Second,
@@ -125,9 +128,10 @@ func TestInput(t *testing.T) {
{
name: "JSONInvalid",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"exit": `invalid`,
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"exit": `invalid`,
},
res: &dataIn{
timeout: 5 * time.Second,
@@ -137,9 +141,10 @@ func TestInput(t *testing.T) {
{
name: "JSONGood",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"exit": `{"message":{"epoch":"123","validator_index":"456"},"signature":"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"}`,
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"exit": `{"exit":{"message":{"epoch":"123","validator_index":"456"},"signature":"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"},"fork_version":"0x00002009"}`,
},
res: &dataIn{
timeout: 5 * time.Second,
@@ -148,19 +153,21 @@ func TestInput(t *testing.T) {
{
name: "ClientBad",
vars: map[string]interface{}{
"connection": "localhost:1",
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
"connection": "localhost:1",
"allow-insecure-connections": true,
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: failed to connect to Ethereum 2 client with any known method",
},
{
name: "EpochProvided",
vars: map[string]interface{}{
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
"epoch": "123",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
"allow-insecure-connections": true,
"timeout": "5s",
"key": "0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866",
"epoch": "123",
},
res: &dataIn{
timeout: 5 * time.Second,

View File

@@ -46,7 +46,7 @@ func output(ctx context.Context, data *dataOut) (string, error) {
func outputJSON(ctx context.Context, data *dataOut) (string, error) {
validatorExitData := &util.ValidatorExitData{
Data: data.signedVoluntaryExit,
Exit: data.signedVoluntaryExit,
ForkVersion: data.forkVersion,
}
bytes, err := json.Marshal(validatorExitData)

View File

@@ -79,7 +79,7 @@ func TestOutput(t *testing.T) {
},
},
},
res: `{"data":{"message":{"epoch":"123","validator_index":"456"},"signature":"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"},"fork_version":"0x01020304"}`,
res: `{"exit":{"message":{"epoch":"123","validator_index":"456"},"signature":"0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"},"fork_version":"0x01020304"}`,
},
}

View File

@@ -20,8 +20,8 @@ import (
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/signing"
"github.com/wealdtech/ethdo/util"
)
// maxFutureEpochs is the farthest in the future for which an exit will be created.
@@ -111,7 +111,7 @@ func fetchValidator(ctx context.Context, data *dataIn) (*api.Validator, error) {
var validator *api.Validator
validatorPubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := core.BestPublicKey(data.account)
pubKey, err := util.BestPublicKey(data.account)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain public key for account")
}

61
cmd/validatorduties.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 cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
validatorduties "github.com/wealdtech/ethdo/cmd/validator/duties"
)
var validatorDutiesCmd = &cobra.Command{
Use: "duties",
Short: "List known duties for a validator",
Long: `List known duties for a validator. For example:
ethdo validator duties --account=Validators/One
Attester duties are known for the current and next epoch. Proposer duties are known for the current epoch.
In quiet mode this will return 0 if the the duties have been obtained, otherwise 1.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := validatorduties.Run(cmd)
if err != nil {
return err
}
if viper.GetBool("quiet") {
return nil
}
fmt.Printf(res)
return nil
},
}
func init() {
validatorCmd.AddCommand(validatorDutiesCmd)
validatorFlags(validatorDutiesCmd)
validatorDutiesCmd.Flags().String("pubkey", "", "validator public key for duties")
validatorDutiesCmd.Flags().String("index", "", "validator index for duties")
}
func validatorDutiesBindings() {
if err := viper.BindPFlag("pubkey", validatorDutiesCmd.Flags().Lookup("pubkey")); err != nil {
panic(err)
}
if err := viper.BindPFlag("index", validatorDutiesCmd.Flags().Lookup("index")); err != nil {
panic(err)
}
}

View File

@@ -31,7 +31,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
string2eth "github.com/wealdtech/go-string2eth"
@@ -48,14 +47,18 @@ In quiet mode this will return 0 if the validator information can be obtained, o
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
eth2Client, err := util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
eth2Client, err := util.ConnectToBeaconNode(ctx,
viper.GetString("connection"),
viper.GetDuration("timeout"),
viper.GetBool("allow-insecure-connections"),
)
errCheck(err, "Failed to connect to Ethereum 2 beacon node")
account, err := validatorInfoAccount()
errCheck(err, "Failed to obtain validator account")
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := core.BestPublicKey(account)
pubKey, err := util.BestPublicKey(account)
errCheck(err, "Failed to obtain validator public key")
copy(pubKeys[0][:], pubKey.Marshal())
validators, err := eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, "head", pubKeys)
@@ -91,6 +94,7 @@ In quiet mode this will return 0 if the validator information can be obtained, o
if verbose {
if validator.Status.HasActivated() {
fmt.Printf("Index: %d\n", validator.Index)
fmt.Printf("Activation epoch: %d\n", validator.Validator.ActivationEpoch)
}
fmt.Printf("Public key: %#x\n", validator.Validator.PublicKey)
}

View File

@@ -1,4 +1,4 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Copyright © 2019 - 2021 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
@@ -24,7 +24,7 @@ import (
// ReleaseVersion is the release version of the codebase.
// Usually overrideen by tag names when building binaries.
var ReleaseVersion = "local build from v1.7.0"
var ReleaseVersion = "local build (latest release 1.7.4)"
// versionCmd represents the version command
var versionCmd = &cobra.Command{

View File

@@ -19,7 +19,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -49,7 +49,7 @@ func input(ctx context.Context) (*dataIn, error) {
data.debug = viper.GetBool("debug")
// Wallet.
wallet, err := core.WalletFromInput(ctx)
wallet, err := util.WalletFromInput(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to access wallet")
}

View File

@@ -19,7 +19,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
@@ -51,7 +50,7 @@ func input(ctx context.Context) (*dataIn, error) {
data.debug = viper.GetBool("debug")
// Wallet.
wallet, err := core.WalletFromInput(ctx)
wallet, err := util.WalletFromInput(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to access wallet")
}

View File

@@ -6,7 +6,7 @@ Converting from mnemonics to keys can be confusing. Below are commands that all
A seed is a 24-word phrase that is used as the start point of a process called hierarchical derivation. It can be used, in combination with a path, to generate any number of keys.
### I want to be able to create keys from the mnemonic
### I want to be able to create accounts from the mnemonic
The first thing you need to do is to create a wallet. To do this run the command below with the following changes:
@@ -18,9 +18,9 @@ The first thing you need to do is to create a wallet. To do this run the comman
$ ethdo wallet create --type=hd --mnemonic='abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art' --wallet=Wallet --wallet-passphrase=secret
```
### I want a specific public key.
### I want an account with a specific public key.
To create a specific public key you need to have both the mnemonic and the derivation path. A derivation path looks something like `m/12381/3600/0/0` and is used by `ethdo` to generate a specific private key (from which the public key is in turn derived).
To create an account with a specific public key you need to have both the mnemonic and the derivation path. A derivation path looks something like `m/12381/3600/0/0` and is used by `ethdo` to generate a specific private key (from which the public key is in turn derived).
You should first create a wallet as per the previous step. To then create an account run the command below with the following changes:
@@ -42,7 +42,7 @@ Path: m/12381/3600/0/0
This process can be repated for any number of paths by changing the `path` and providing a different account name each time.
### I want the private key.
### I want an account's private key.
To obtain the private key of an account follow the steps above, then run:
@@ -81,3 +81,11 @@ $ ethdo validator depositdata --withdrawalaccount=Wallet/Withdrawal_i_ --validat
If you wish to be able to provide this information to the launchpad you can add `--launchpad` to the end of the command.
If you wish to have this data for a particular test network you will need to supply the fork version with `--forkversion`. Details on the fork versions of various testnets can be found in the subdirectories of the [testnet site](https://github.com/goerli/medalla).
### I want keys without creating wallets and accounts
It is possible to derive keys directly from a mnemonic and path without going through the interim steps. Note that this will _not_ create accounts, and cannot be used to then sign data or requests. This may or not be desirable, depending on your requirements.
```
$ ethdo account derive --mnemonic='abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art' --path=m/12381/3600/0/0
```

View File

@@ -54,14 +54,14 @@ $ ethdo wallet delete --wallet="Old wallet"
- `passphrase`: the passphrase with which to encrypt the wallet backup
```sh
$ ethdo wallet export --wallet="Personal wallet" --exportpassphrase="my export secret"
$ ethdo wallet export --wallet="Personal wallet" --passphrase="my export secret"
0x01c7a27ad40d45b4ae5be5f...
```
The encrypted wallet export is written to the console; it can be redirected to store it in a file.
```sh
$ ethdo wallet export --wallet="Personal wallet" --exportpassphrase="my export secret" >export.dat
$ ethdo wallet export --wallet="Personal wallet" --passphrase="my export secret" >export.dat
```
#### `import`
@@ -72,13 +72,13 @@ $ ethdo wallet export --wallet="Personal wallet" --exportpassphrase="my export s
- `verify`: confirm information about the wallet import without importing it
```sh
$ ethdo wallet import --importdata="0x01c7a27ad40d45b4ae5be5f..." --passphrase="my export secret"
$ ethdo wallet import --data="0x01c7a27ad40d45b4ae5be5f..." --passphrase="my export secret"
```
The encrypted wallet export can be read from a file. For example with Unix systems:
```sh
$ ethdo wallet import --importdata=`cat export.dat` --passphrase="my export secret"
$ ethdo wallet import --data=`cat export.dat` --passphrase="my export secret"
```
#### `info`
@@ -121,6 +121,21 @@ For distributed accounts you will also need to supply `--participants` and `--si
```sh
$ ethdo account create --account="Personal wallet/Operations" --wallet-passphrase="my wallet secret" --passphrase="my account secret"
```
#### `derive`
`ethdo account derive` provides the ability to derive an account's keys without creating either the wallet or the account. This allows users to quickly obtain or confirm keys without going through a relatively long process, and has the added security benefit of not writing any information to disk. Options for deriving the account include:
- `mnemonic`: a pre-defined 24-word [BIP-39 seed phrase](https://en.bitcoin.it/wiki/Seed_phrase) to derive the account, along with an additional "seed extension" phrase if required supplied as the 25th word
- `path`: the HD path used to derive the account
- `show-private-key`: show the private of the derived account. **Warning** displaying private keys, especially those derived from seeds held on hardware wallets, can expose your Ether to risk of being stolen. Only use this option if you are sure you understand the risks involved
- `show-withdrawal-credentials`: show the withdrawal credentials of the derived account
```sh
$ ethdo account derive --mnemonic="abandon ... abandon art" --path="m/12381/3600/0/0"
Public key: 0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db
```
#### `import`
`ethdo account import` creates a new account by importing its private key. Options for creating the account include:
@@ -333,18 +348,29 @@ Exit commands focus on information about validator exits generated by the `ethdo
#### `verify`
`ethdo exit verify` verifies the validator exit information in a JSON file generated by the `ethdo validator exit` command. Options include:
- `data`: either a path to the JSON file or the JSON itself
- `exit`: either a path to the JSON file or the JSON itself
- `account`: the account that generated the exit transaction (if available as an account, in format "wallet/account")
- `pubkey`: the public key of the account that generated the exit transaction
```sh
$ ethdo exit verify --data=${HOME}/exit.json --pubkey=0xa951530887ae2494a8cc4f11cf186963b0051ac4f7942375585b9cf98324db1e532a67e521d0fcaab510edad1352394c
$ ethdo exit verify --exit=${HOME}/exit.json --pubkey=0xa951530887ae2494a8cc4f11cf186963b0051ac4f7942375585b9cf98324db1e532a67e521d0fcaab510edad1352394c
```
### `node` commands
Node commands focus on information from an Ethereum 2 node.
#### `events`
`ethdo node events` displays events emitted by an Ethereum 2 node.
```sh
$ ethdo node events --topics=head,chain_reorg
{"topic":"head","data":{"block":"0x3b98ccd8dbd39e0763a5e91ef754f4559f5f9b6b8014ff45c8abf2eaf236324a","current_duty_dependent_root":"0xdedb063fcc2f404c701fe05a5bfbc95881d23292239adc1c4fc49d409beea7be","epoch_transition":false,"previous_duty_dependent_root":"0x626037a43b204b88d1911510d2717669ee2839b3227f5642832c36e5e6fc5e2f","slot":"231380","state":"0x009630f55970fa73b61cc97b0ed83b2faaf9103c8db722705e1b4376f240e415"}}
{"topic":"head","data":{"block":"0x41e4c09da2ddbca777fbdae5b0cdd2823df630fb74e1d3f6837586046737b414","current_duty_dependent_root":"0xdedb063fcc2f404c701fe05a5bfbc95881d23292239adc1c4fc49d409beea7be","epoch_transition":false,"previous_duty_dependent_root":"0x626037a43b204b88d1911510d2717669ee2839b3227f5642832c36e5e6fc5e2f","slot":"231381","state":"0xd2ce52483df1add63df441c15d4aef291be8a41d6d1d3ce7e9d6d619f7c911de"}}
...
```
#### `info`
`ethdo node info` obtains the information about an Ethereum 2 node.
@@ -367,6 +393,20 @@ Current epoch: 5
Genesis timestamp: 1587020563
```
### `slot` commands
Slot commands focus on information about Ethereum 2 slots.
#### `slottime`
`ethdo slot time` provides information about the time of a slot. options include:
- `slot` the slot for which to provide the time
```sh
$ ethdo slot time --slot=5
2020-12-01 12:01:23 +0000 GMT
```
### `validator` commands
Validator commands focus on interaction with Ethereum 2 validators.
@@ -435,6 +475,18 @@ Effective balance: 3.1 Ether
Attester commands focus on Ethereum 2 validators' actions as attesters.
#### `duties`
`ethdo attester duties` provides information on the duties that a given validator has in a given epoch. Options include:
- `epoch` the epoch in which to obtain the duties (defaults to current epoch)
- `account` the account for which to fetch the duties (in format "wallet/account")
- `pubkey` the public key for which to fetch the duties
```sh
$ ethdo attester duties --account=Validators/0 --epoch=5
Validator attesting in slot 186 committee 3
```
#### `inclusion`
`ethdo attester inclusion` finds the block with wihch an attestation is included on the chain. Options include:

62
go.mod
View File

@@ -4,29 +4,31 @@ go 1.13
require (
github.com/OneOfOne/xxhash v1.2.5 // indirect
github.com/attestantio/dirk v0.9.3
github.com/attestantio/go-eth2-client v0.6.10
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321
github.com/attestantio/dirk v1.0.2
github.com/attestantio/go-eth2-client v0.6.21
github.com/aws/aws-sdk-go v1.37.1 // indirect
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/gofrs/uuid v3.3.0+incompatible
github.com/gogo/protobuf v1.3.1
github.com/google/uuid v1.1.2
github.com/goccy/go-yaml v1.8.6 // indirect
github.com/gofrs/uuid v4.0.0+incompatible
github.com/gogo/protobuf v1.3.2
github.com/google/uuid v1.2.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de
github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371
github.com/jackc/puddle v1.1.3 // indirect
github.com/magiconair/properties v1.8.4 // indirect
github.com/minio/highwayhash v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d
github.com/nbutton23/zxcvbn-go v0.0.0-20201221231540-e56b841a3c88
github.com/pelletier/go-toml v1.8.1 // indirect
github.com/pkg/errors v0.9.1
github.com/protolambda/zssz v0.1.5 // indirect
github.com/prysmaticlabs/ethereumapis v0.0.0-20201020182719-7f66dae2bbba
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65
github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae
github.com/prysmaticlabs/ethereumapis v0.0.0-20210201130911-92b2a467c108
github.com/prysmaticlabs/go-bitfield v0.0.0-20210129193852-0db57134419f
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388
github.com/rs/zerolog v1.20.0
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.4.1 // indirect
github.com/spf13/afero v1.5.1 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.1.1
github.com/spf13/jwalterweatherman v1.1.0 // indirect
@@ -39,23 +41,23 @@ require (
github.com/wealdtech/eth2-signer-api v1.6.0
github.com/wealdtech/go-bytesutil v1.1.1
github.com/wealdtech/go-ecodec v1.1.1
github.com/wealdtech/go-eth2-types/v2 v2.5.1
github.com/wealdtech/go-eth2-util v1.6.2
github.com/wealdtech/go-eth2-wallet v1.14.3
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4
github.com/wealdtech/go-eth2-wallet-distributed v1.1.2
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.2
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.2
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.13
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.2
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.1
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.1
github.com/wealdtech/go-eth2-types/v2 v2.5.2
github.com/wealdtech/go-eth2-util v1.6.3
github.com/wealdtech/go-eth2-wallet v1.14.4
github.com/wealdtech/go-eth2-wallet-dirk v1.1.5
github.com/wealdtech/go-eth2-wallet-distributed v1.1.3
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.4
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.3
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.14
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.4
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.2
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2
github.com/wealdtech/go-string2eth v1.1.0
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd // indirect
golang.org/x/text v0.3.4
google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6 // indirect
google.golang.org/grpc v1.33.2
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
golang.org/x/text v0.3.5
google.golang.org/genproto v0.0.0-20210201184850-646a494a81ea // indirect
google.golang.org/grpc v1.35.0
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

142
go.sum
View File

@@ -15,6 +15,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.68.0/go.mod h1:91NO4SCDjUfe1zeC0f4/dpckkUNpuNEyqm4X2KLrzNQ=
cloud.google.com/go v0.70.0/go.mod h1:/UTKYRQTWjVnSe7nGvoSzxEFUELzSI/yAYd0JQT6cRo=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -69,12 +70,24 @@ github.com/attestantio/dirk v0.9.2 h1:yv/Tp/Y/1wATdASROOoY2ZxP1NFjZZCD0b5TasnvYS
github.com/attestantio/dirk v0.9.2/go.mod h1:yIpIiADNeBmhsCxhZ0o3gFVmUnpl9sPqRhVtwNApJoc=
github.com/attestantio/dirk v0.9.3 h1:hJj/X63n7UV+DseKlR8Kjs+zLYtf+2Alqk9A6nI8mUg=
github.com/attestantio/dirk v0.9.3/go.mod h1:EfppeT+VjQXnE9Ti5/vxa6ptZJAN2vMXO6KZojvSOXA=
github.com/attestantio/dirk v1.0.2 h1:CYIRgQIbPqshwvgNJt98vV/ljhZmnAqfhQujoIpvGKg=
github.com/attestantio/dirk v1.0.2/go.mod h1:QHXxAnKD9cpuPC7STamSW2nPXEn7YTypcNFPAKfWTFQ=
github.com/attestantio/go-eth2-client v0.6.8 h1:Lsjx5P0pB8ruZBfJUbqy5hpevD4Zt8Z0Lg4V5m2s53E=
github.com/attestantio/go-eth2-client v0.6.8/go.mod h1:lYEayGHzZma9HMUJgyxFIzDWRck8n2IedP7KTkIwe0g=
github.com/attestantio/go-eth2-client v0.6.9 h1:Hbf4tX9MvxCsLokED8Ic3tQxmEAb/phoBkBmk8sKJm0=
github.com/attestantio/go-eth2-client v0.6.9/go.mod h1:ODAZ4yS1YYYew/EsgGsVb/siNEoa505CrGsvlVFdkfo=
github.com/attestantio/go-eth2-client v0.6.10 h1:PMNBMLk6xfMEUqhaUnsI0/HZRrstZF18Gt6Dm5GelW4=
github.com/attestantio/go-eth2-client v0.6.10/go.mod h1:ODAZ4yS1YYYew/EsgGsVb/siNEoa505CrGsvlVFdkfo=
github.com/attestantio/go-eth2-client v0.6.15 h1:GNkiSF2Dqp6qahMXMW8r8Wy61WEvytnAM+rEyutdfv8=
github.com/attestantio/go-eth2-client v0.6.15/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.16 h1:2Xn5RKqXUXfxLYVHn3D6l0FK7NUCjzl5v4oYIxcxc5k=
github.com/attestantio/go-eth2-client v0.6.16/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.19 h1:I3iax2CJxVy1lixBMbijTGORwXMGrygkkf6eKZPWhz0=
github.com/attestantio/go-eth2-client v0.6.19/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.20 h1:THyBw78EaFuF/u4UNTbeCLXhgdN5Gr/3tGKxVZE+YEw=
github.com/attestantio/go-eth2-client v0.6.20/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/attestantio/go-eth2-client v0.6.21 h1:omtOkQ0iu8dXjlQdHGZdESJYT9zOu9YnYMFMGF1Xjv4=
github.com/attestantio/go-eth2-client v0.6.21/go.mod h1:Hya4fp1ZLWAFI64qMhNbQgfY4StWiHulW4CFwu+vP3s=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.32.6 h1:HoswAabUWgnrUF7X/9dr4WRgrr8DyscxXvTDm7Qw/5c=
@@ -94,6 +107,12 @@ github.com/aws/aws-sdk-go v1.35.14 h1:nucVVXXjAr9UkmYCBWxQWRuYa5KOlaXjuJGg2ulW0K
github.com/aws/aws-sdk-go v1.35.14/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.35.26 h1:MawRvDpAp/Ai859dPC1xo1fdU/BIkijoHj0DwXLXXkI=
github.com/aws/aws-sdk-go v1.35.26/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
github.com/aws/aws-sdk-go v1.36.2 h1:UAeFPct+jHqWM+tgiqDrC9/sfbWj6wkcvpsJ+zdcsvA=
github.com/aws/aws-sdk-go v1.36.2/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.36.12 h1:YJpKFEMbqEoo+incs5qMe61n1JH3o4O1IMkMexLzJG8=
github.com/aws/aws-sdk-go v1.36.12/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go v1.37.1 h1:BTHmuN+gzhxkvU9sac2tZvaY0gV9ihbHw+KxZOecYvY=
github.com/aws/aws-sdk-go v1.37.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
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=
@@ -112,6 +131,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
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/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
@@ -156,6 +177,8 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
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/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
@@ -172,6 +195,12 @@ github.com/ferranbt/fastssz v0.0.0-20200826142241-3a913c5a1313/go.mod h1:DyEu2iu
github.com/ferranbt/fastssz v0.0.0-20201020132831-68dc48984fd3/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321 h1:9Pkbf8HgETu3xKpz12Sj5clUrVFp2O+ymK7pBsTPYRM=
github.com/ferranbt/fastssz v0.0.0-20201030134205-9b9624098321/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20201207112544-98a5de30d648 h1:TBgYVQ5wP1iSjg53BnlXibpYzmAZJLsZhOcGDtu0FlQ=
github.com/ferranbt/fastssz v0.0.0-20201207112544-98a5de30d648/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20201210095258-318e164fe1dd h1:W2w+U6B6jVYrSAtip8HylYbu0G3XoJLLvggm1kuPKq4=
github.com/ferranbt/fastssz v0.0.0-20201210095258-318e164fe1dd/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9 h1:9VDpsWq096+oGMDTT/SgBD/VgZYf4pTF+KTPmZ+OaKM=
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -187,22 +216,32 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
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-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-yaml v1.8.3 h1:VGzw2KWSUyQX0yXai02S0nttBc+Oa4Kvh6RCFoxt8SE=
github.com/goccy/go-yaml v1.8.3/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M=
github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/goccy/go-yaml v1.8.6 h1:xOsXodQ17pkM420Ai0DROYyLbx8FAmX0KhU8MY6ZIg0=
github.com/goccy/go-yaml v1.8.6/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
github.com/gofrs/uuid v1.2.0 h1:coDhrjgyJaglxSjxuJdqQSSdUpG3w6p1OwN2od6frBU=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -247,10 +286,12 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -260,12 +301,15 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201009210932-67992a1a5a35/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
@@ -336,6 +380,8 @@ github.com/herumi/bls-eth-go-binary v0.0.0-20201019012252-4b463a10c225 h1:S7pKW7
github.com/herumi/bls-eth-go-binary v0.0.0-20201019012252-4b463a10c225/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de h1:qLlwYGvpvAx/nDBnPt2KpZTXGli0oHBGddyYxJHTOds=
github.com/herumi/bls-eth-go-binary v0.0.0-20201104034342-d782bdf735de/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371 h1:LEw2KkKciJEr3eKDLzdZ/rjzSR6Y+BS6xKxdA78Bq6s=
github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@@ -347,6 +393,8 @@ github.com/jackc/puddle v1.1.1 h1:PJAw7H/9hoWC4Kf3J8iNmL1SwA6E8vfsLqBiL+F6CtI=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.2 h1:mpQEXihFnWGDy6X98EOTh81JYuxn7txby8ilJ3iIPGM=
github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
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=
@@ -367,6 +415,7 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -419,6 +468,10 @@ github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYG
github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.0 h1:7ks8ZkOP5/ujthUsT07rNv+nkLXCQWKNHuwzOAesEks=
github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
@@ -434,6 +487,8 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/nbutton23/zxcvbn-go v0.0.0-20201221231540-e56b841a3c88 h1:o+O3Cd1HO9CTgxE3/C8p5I5Y4C0yYWbF8d4IkfOLtcQ=
github.com/nbutton23/zxcvbn-go v0.0.0-20201221231540-e56b841a3c88/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@@ -494,6 +549,7 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -515,13 +571,23 @@ github.com/prysmaticlabs/ethereumapis v0.0.0-20201003171600-a72e5f77d233 h1:dGeu
github.com/prysmaticlabs/ethereumapis v0.0.0-20201003171600-a72e5f77d233/go.mod h1:k7b2dxy6RppCG6kmOJkNOXzRpEoTdsPygc2aQhsUsZk=
github.com/prysmaticlabs/ethereumapis v0.0.0-20201020182719-7f66dae2bbba h1:ItW6tq3B45Gws8dO0cIuU1Srlgf4qomZnWkc0sDCln0=
github.com/prysmaticlabs/ethereumapis v0.0.0-20201020182719-7f66dae2bbba/go.mod h1:k7b2dxy6RppCG6kmOJkNOXzRpEoTdsPygc2aQhsUsZk=
github.com/prysmaticlabs/ethereumapis v0.0.0-20201207010723-e69ac7fa952d h1:HdarpPepaIp6xIFfH4hG3IU6doct9WupCYQgT97G+4g=
github.com/prysmaticlabs/ethereumapis v0.0.0-20201207010723-e69ac7fa952d/go.mod h1:k7b2dxy6RppCG6kmOJkNOXzRpEoTdsPygc2aQhsUsZk=
github.com/prysmaticlabs/ethereumapis v0.0.0-20210201130911-92b2a467c108 h1:iiLmzQ0tSh0ShqrzdZm2T2xJdHze7wu8dAMywl/8Ynw=
github.com/prysmaticlabs/ethereumapis v0.0.0-20210201130911-92b2a467c108/go.mod h1:k7b2dxy6RppCG6kmOJkNOXzRpEoTdsPygc2aQhsUsZk=
github.com/prysmaticlabs/go-bitfield v0.0.0-20191017011753-53b773adde52/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200322041314-62c2aee71669/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65 h1:hJfAWrlxx7SKpn4S/h2JGl2HHwA1a2wSS3HAzzZ0F+U=
github.com/prysmaticlabs/go-bitfield v0.0.0-20200618145306-2ae0807bef65/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20201217222627-a48494c940af h1:rnCvwxNuTbKnpdFGVBwWpbHruNcRv0J4MnjRNTick10=
github.com/prysmaticlabs/go-bitfield v0.0.0-20201217222627-a48494c940af/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210129193852-0db57134419f h1:omXTHDyMBMOCpwsppvIWZ8z6eRZouMU+4ndPhUHgBLc=
github.com/prysmaticlabs/go-bitfield v0.0.0-20210129193852-0db57134419f/go.mod h1:hCwmef+4qXWjv0jLDbQdWnL0Ol7cS7/lCSS26WR+u6s=
github.com/prysmaticlabs/go-ssz v0.0.0-20200101200214-e24db4d9e963/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae h1:7qd0Af1ozWKBU3c93YW2RH+/09hJns9+ftqWUZyts9c=
github.com/prysmaticlabs/go-ssz v0.0.0-20200612203617-6d5c9aa213ae/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388 h1:4bD+ujqGfY4zoDUF3q9MhdmpPXzdp03DYUIlXeQ72kk=
github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388/go.mod h1:VecIJZrewdAuhVckySLFt2wAAHRME934bSDurP8ftkc=
github.com/r3labs/sse/v2 v2.3.0 h1:R/UMa0ML6AYKQ8irQNHhY+204lz1LytDIdKhCxSVAd8=
github.com/r3labs/sse/v2 v2.3.0/go.mod h1:hUrYMKfu9WquG9MyI0r6TKiNH+6Sw/QPKm2YbNbU5g8=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -564,6 +630,8 @@ github.com/spf13/afero v1.3.4 h1:8q6vk3hthlpb2SouZcnBVKboxWQWMDNF38bwholZrJc=
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.4.1 h1:asw9sl74539yqavKaglDM5hFpdJVK0Y5Dr/JOgQ89nQ=
github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg=
github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -591,6 +659,7 @@ github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
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.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -636,6 +705,8 @@ github.com/wealdtech/go-eth2-types/v2 v2.5.0 h1:L8sl3yoICAbn3134CBLNUt0o5h2voe0E
github.com/wealdtech/go-eth2-types/v2 v2.5.0/go.mod h1:321w9X26lAnNa/lQJi2A6Lap5IsNORoLwFPoJ1i8QvY=
github.com/wealdtech/go-eth2-types/v2 v2.5.1 h1:59VZuwgqRaTjBu3b3CCaxG05XTmANtuTKA8hy3C6IFQ=
github.com/wealdtech/go-eth2-types/v2 v2.5.1/go.mod h1:UUtEgRum8HkPvImpu5+hFYRanMUjP0k6KWqHlYkOGbk=
github.com/wealdtech/go-eth2-types/v2 v2.5.2 h1:tiA6T88M6XQIbrV5Zz53l1G5HtRERcxQfmET225V4Ls=
github.com/wealdtech/go-eth2-types/v2 v2.5.2/go.mod h1:8lkNUbgklSQ4LZ2oMSuxSdR7WwJW3L9ge1dcoCVyzws=
github.com/wealdtech/go-eth2-util v1.2.2 h1:LALunpMSJFvu89RHS1zl6RjZ52805utRvd12RtquB54=
github.com/wealdtech/go-eth2-util v1.2.2/go.mod h1:R3VlTd69B2Jf58s62ChcyXt11ZK1/36CTplTuyR/6dE=
github.com/wealdtech/go-eth2-util v1.3.0 h1:aX1+PnxB904GIf5JE9GRKYPuGQJsCT+Q7PG9BMeFN40=
@@ -648,6 +719,8 @@ github.com/wealdtech/go-eth2-util v1.6.1 h1:gYW2s6iea/6NoSuSbisMqETpcnQYfqQnpmGL
github.com/wealdtech/go-eth2-util v1.6.1/go.mod h1:0hCjncDU0yi6dzGgrCgWAj6grdvJ6loEKCGpCMfxo9c=
github.com/wealdtech/go-eth2-util v1.6.2 h1:Gk7xVTG/bY1IUw/8wxOf97DuPbLTGGoZ0k5dNayudhk=
github.com/wealdtech/go-eth2-util v1.6.2/go.mod h1:0hCjncDU0yi6dzGgrCgWAj6grdvJ6loEKCGpCMfxo9c=
github.com/wealdtech/go-eth2-util v1.6.3 h1:2INPeOR35x5LdFFpSzyw954WzTD+DFyHe3yKlJnG5As=
github.com/wealdtech/go-eth2-util v1.6.3/go.mod h1:0hFMj/qtio288oZFHmAbCnPQ9OB3c4WFzs5NVPKTY4k=
github.com/wealdtech/go-eth2-wallet v1.10.2 h1:oUgi6Ih5fA9thhIipzXMSaLkiwDQXwT8q3bCOLpCr7s=
github.com/wealdtech/go-eth2-wallet v1.10.2/go.mod h1:8H9pgp5K7X1kU1cJMS/B3DrMZF74ZlwBThownrcRYgk=
github.com/wealdtech/go-eth2-wallet v1.11.0 h1:2KfrWDqF4sWGgk4N5+DaYmh0hOnqiCl0P4vCz5mx17U=
@@ -664,6 +737,8 @@ github.com/wealdtech/go-eth2-wallet v1.14.2 h1:pk6JGQdeEafVmZw5JYg2gk/8IeZjf0mY8
github.com/wealdtech/go-eth2-wallet v1.14.2/go.mod h1:irzlGFMyRCWlvGgdI7IjS+/Oyr3Y+Dkkh5kxo0VCRDg=
github.com/wealdtech/go-eth2-wallet v1.14.3 h1:VskYm62CSMPm9pc/93E2mO3p1GcYUg8HHUSW/rgXPks=
github.com/wealdtech/go-eth2-wallet v1.14.3/go.mod h1:cGFCLvyUua84+WQ9e9ETnXjx9hnlZgjRRYYltn+RfOE=
github.com/wealdtech/go-eth2-wallet v1.14.4 h1:gtc3riPPk7jyA9+6GPLduvAUFcPrIw+GvmHiPdO9K88=
github.com/wealdtech/go-eth2-wallet v1.14.4/go.mod h1:0v3IjRDc/f5ZJtGOUMubuqvh9AkblRi8e+mhvKVYzIY=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.0 h1:1QUcWILF3h4OLCgTPpWklvRSuPu0fqrt15jwSm7CSC4=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.0/go.mod h1:VTzjJ51dedvYPr4huI7g7KXZVTpGR6ZrCDQwBxJpLck=
github.com/wealdtech/go-eth2-wallet-dirk v1.0.1 h1:YUE1QlJPun8b+xbz0JM71/3t1i9zp9KjcZdJvtJQL+E=
@@ -678,6 +753,8 @@ github.com/wealdtech/go-eth2-wallet-dirk v1.1.2 h1:HSF3j/RY5bl46cPgskNNz9k7NEeVR
github.com/wealdtech/go-eth2-wallet-dirk v1.1.2/go.mod h1:WQ0YW8E+A8r+SjMYX8ZwouZNAHEQPvoxy4Q3OtC0KqU=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4 h1:huJwlmQDNGjjBi6B/yEDLYFUcx+xbldhoJfkVGLBJYY=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.4/go.mod h1:CEQyNdk+egD2UbvnVn4qGeSBkvR09dmknCA293WiCVk=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.5 h1:OGnl5PQHuq8R+grgzeLwyG2l2rPZ0eTfMR8LEHqus4o=
github.com/wealdtech/go-eth2-wallet-dirk v1.1.5/go.mod h1:HN3QOG8c+VExZGOiXSMwCRy78jYvv3LkG01ReCUWGgQ=
github.com/wealdtech/go-eth2-wallet-distributed v1.0.1 h1:3BxMII8T6t16g6lWcYWXjfdvaw8rXuwMQx9h0TG5wRg=
github.com/wealdtech/go-eth2-wallet-distributed v1.0.1/go.mod h1:Ha/8S+SCLEuSfXHdvhTLwnKaEF47o6gzQ+FURKwftvU=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.0 h1:OZjjuxcIYo+EhAfph7lYP1z+VeNs9ruOI32kqtYe1Jg=
@@ -686,6 +763,8 @@ github.com/wealdtech/go-eth2-wallet-distributed v1.1.1 h1:KSaNQbtj5XXjttTVHe1oy+
github.com/wealdtech/go-eth2-wallet-distributed v1.1.1/go.mod h1:Ik8JPsQQiMengG+dVUaLbFmGug1z9UOWqBDHkF1tGro=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.2 h1:ABE1tyxGfXAPPphQ32dval7+9aP61BsIdtvuOJr3azY=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.2/go.mod h1:BRl33Vt9urhVuNHGiBfrf0gRs+U+gKSWCV2kmzD5xTw=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.3 h1:K0M4BA4DNgevioL9oGRBpPt7HdvEWcAd8W/myL+ZZxM=
github.com/wealdtech/go-eth2-wallet-distributed v1.1.3/go.mod h1:xocBupP57d3vsZMamWrZRjy4vB05YBtuwWihqiU1vXs=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0 h1:IcpS4VpXhYz+TVupB5n6C6IQzaKwG+Rc8nvgCa/da4c=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.0.0/go.mod h1:X8WRO5hEwbjx8ZOqoRmtS1ngyflKs25GkP7qGv7yOqE=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.0 h1:CWb82xeNaZQt1Z829RyDALUy7UZbc6VOfTS+82jRdEQ=
@@ -694,6 +773,8 @@ github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.1 h1:PYwMOCt92iWEH
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.1/go.mod h1:JelKMM10UzDJNXdIcojMj6SCIsHC8NYn4c1S2FFk7OQ=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.2 h1:JRZGHJWTX9iEYNg1jKSuO5WBrLVwMLExkJg04esRgss=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.2/go.mod h1:q+Ng4rNBsD7nMk6s07BpAa2V6Se1aH1dua2jk5orjc0=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 h1:SxrDVSr+oXuT1x8kZt4uWqNCvv5xXEGV9zd7cuSrZS8=
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3/go.mod h1:qiIimacW5NhVRy8o+YxWo9YrecXqDAKKbL0+sOa0SJ4=
github.com/wealdtech/go-eth2-wallet-encryptor-unencrypted v1.0.1/go.mod h1:49K88T/4LNQpB8ghVcjTKeRRi/bZHeYjN8Ef5S23yps=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.1.3/go.mod h1:STigKib4ZSefVvJjx88V2QpUGaoyUE1TiupcpsHpvKE=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.2.0 h1:L+yrAn8TC9DQUw+S7moOJxQTp2jrHCoAZLpI747Nx2g=
@@ -710,6 +791,8 @@ github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.2 h1:3EYbuUrs4cCId+WxFAtx+H/uQXRR
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.2/go.mod h1:hmDme779S5sqxN+W+zmHpS0K8n13fGekHM3gUUB1Ip0=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3 h1:9Gt/UGrg3wWkZEFuXOdmm5Ih/wOJPP/p8l9v3MIPPzc=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.3/go.mod h1:UzS7JsWmOGjaSky+NTSjriTpdv+Vww1pWemb+3+GRk8=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.4 h1:jXykgCCddYb3FaHekRJC9ZI6payM5+WxBcP53Z2u0uw=
github.com/wealdtech/go-eth2-wallet-hd/v2 v2.5.4/go.mod h1:07W5FVdIm43EIpGvcv+tgktJYpaeb9emo+g2NW5/7+s=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.1.2/go.mod h1:IssxoHII0ewO1VysMfCmdJP1D00tRhRhXIhhaEXIOVE=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0 h1:h4eePfG0ANOJYMonmIYOvxJ9uLmBEX4APb2O8Vhtv6k=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.2.0/go.mod h1:Un2EtseZWSObmTBjgkt7Qz2am54S/0115jrF83lto1U=
@@ -719,6 +802,8 @@ github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.1 h1:inSu0xN3LQN9/nEXTri5IbGLfhsv
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.1/go.mod h1:72HjvN+bANNgv/YCZ4Rjwgn6wesg24aHSQlHzrbPFWo=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.2 h1:NwJV/Ll90WhqxhCcYCdHYWIURGXDt/GRPNFOvu4kzbg=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.2/go.mod h1:WyFAmQHBIUN4hd9hAZQ9Py+N7c+mmlpDSTgiNxvICCM=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.3 h1:j8wt8ax+PmCMX770Enb3sQjvyzcRtTtI9goy6uMY7h8=
github.com/wealdtech/go-eth2-wallet-nd/v2 v2.3.3/go.mod h1:+pkq2t6lFJJQhEoZjB1YHeK051dP+0bGDsPrxr3CtHg=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2 h1:Z4Pw7/Mlp6jJLoJnhgov8M1011HP/Pb3YYqcdYGCy6Q=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.15.2/go.mod h1:GSMbVCewjbxRrw32m6YCd9DOzCRjAXB3qUOQnr58JEs=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.0 h1:sWuSrAKdWSphiQCVcThozaFgTrwemXNXDI5CnFcP02s=
@@ -727,6 +812,8 @@ github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1 h1:l9YV6OBqcxp5fjsc
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.1/go.mod h1:Zxhj/4i8nRpk4LTTqFKbfI2KyvO3uqLMerNXqKZKDK0=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.13 h1:zVV0kL6TZ1fW/Od9BW9e7W5UJB78gNbcbRQK+HeJOL8=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.13/go.mod h1:x6sKafiDSvsUeiYZq7TE/ZWIWeAToXLIqgb7KCehgjU=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.14 h1:6JbX/2VEMOt7gmWyquRJB8TbVPtsczkB8GR4cE+pjxs=
github.com/wealdtech/go-eth2-wallet-store-filesystem v1.16.14/go.mod h1:sEMoRUyXSyd7guotrOPfOTTDPFMjf0iIrn6yA4IASDk=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2 h1:a7GWfFd139CODvvkuTbRIuRwAAjb55sFDGRh177KXGk=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.7.2/go.mod h1:VWvXScZKUWHbhQpadLX8Yj+mc8U/i4zGthQJee+o3xg=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.8.0 h1:+q7p58NvOEfEDw8NgEoNaSG/s1eFHpyg91NEobA6RF0=
@@ -737,6 +824,8 @@ github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.1 h1:YGw5YanOepPGalSyvDKwCEdwv
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.1/go.mod h1:FR+mhCaoZN4d+EEBSV2QT2cO4szdKvDLTHRygMrH6fk=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.2 h1:HFT1w+8icvHj5Yb1qDZUjzIQYnFbau1ahYwB08kwwJM=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.2/go.mod h1:oKDDrc/BMDotY8/zT9TfmnELt+QMaPCiWwTiBmjlwTw=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.4 h1:gCJ1r40pPy2rJ12+sOdiekqRhYijLkHktuxzXo1Pl6M=
github.com/wealdtech/go-eth2-wallet-store-s3 v1.9.4/go.mod h1:lOImPvwr12uomYS8TuvMfSNKC+Duic8WtREilfUFNnQ=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2 h1:GvG3ZuzxbqFjGUaGoa8Tz7XbPlDA33G6nHQbSZInC3g=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.4.2/go.mod h1:+TbqLmJuT98PWi/xW1bp5nwZbKz+SIJYVh/+NUkmnb4=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.5.0/go.mod h1:RMIIV5/N8TgukTVzyumQd7AplpC440ZXDSk8VffeEwQ=
@@ -744,6 +833,8 @@ github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0 h1:41H6hnVsI/csBx20UHpI
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.0/go.mod h1:XtXHbl4OV/XenQsvGmXbh+bVXaGS788oa30DB7kDInA=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.1 h1:vv9lR8K76FUSNbzUU25MN4HNhZIBBI1kJBNfHq2WjRY=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.1/go.mod h1:qnI6/VRpFyKGV+DhzdC1zmx2sA7mRRanCFlk4RYzoYs=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.2 h1:VfEq3gu8yZ6hUll3XEUugm+lBtdWWXrcJaNLp8Je3aU=
github.com/wealdtech/go-eth2-wallet-store-scratch v1.6.2/go.mod h1:qEHxsSqhYd1N7UzN3iFils+z4HDnJl7L772hZiQEm0E=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0 h1:SfoBlW2LYjW05uHhnTZaezX37gbRsp+VYtxWT6SeAME=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.2.0/go.mod h1:XEvrlKFnHLbg1tj4Dep76XKASeS13TBpvdeXmvLiH+k=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.3.0-beta4 h1:VmpgUSr+aUexFmC2AYlQ7zpeAy0w0mcK58ihpDeMCL8=
@@ -760,6 +851,8 @@ github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.0 h1:30sYrHQBchcOv+N2yIB2APnqf
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.0/go.mod h1:X9kYUH/E5YMqFMZ4xL6MJanABUkJGaH/yPZRT2o+yYA=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.1 h1:pcvljXdc/CqXl/JAXXtd6Ey5SqfOq9MvQutvM+5wvHQ=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.1/go.mod h1:PWvCKqRknUmOdkXmMLpyW7wBVaAEP5BWSWRph4iWy98=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2 h1:264/meVYWt1wFw6Mtn+xwkZkXjID42gNra4rycoiDXI=
github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2/go.mod h1:k6kmiKWSWBTd4OxFifTEkPaBLhZspnO2KFD5XJY9nqg=
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-majordomo v1.0.1/go.mod h1:QoT4S1nUQwdQK19+CfepDwV+Yr7cc3dbF+6JFdQnIqY=
@@ -816,6 +909,12 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1V
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620 h1:3wPMTskHO3+O6jqTEXyFcsnuxMQOqYSaHsDxcbUXpqA=
golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -895,16 +994,25 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb h1:mUVeFHoDKis5nxCAzoAi7E8Ghb86EXh/RK6wtvJIqRY=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127 h1:pZPp9+iYUqwYKLjht0SDBbRCRK/9gAXDy7pz5fRDpjo=
golang.org/x/net v0.0.0-20201024042810-be3efd7ff127/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201216054612-986b41b23924 h1:QsnDpLLOKwHBBDa8nDws4DYNc/ryVW2vCpxCs09d4PY=
golang.org/x/net v0.0.0-20201216054612-986b41b23924/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
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=
@@ -913,6 +1021,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -939,6 +1048,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -981,6 +1091,16 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 h1:a/mKvvZr9Jcc8oKfcmgzyp7Ow
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY=
golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742 h1:+CBz4km/0KPU3RGTwARGh/noP3bEwtHcq+0YcBQM2JQ=
golang.org/x/sys v0.0.0-20201218084310-7d0127a74742/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -989,6 +1109,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1039,12 +1161,15 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
@@ -1070,6 +1195,7 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.33.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1134,8 +1260,18 @@ google.golang.org/genproto v0.0.0-20201013134114-7f9ee70cb474/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5 h1:YejJbGvoWsTXHab4OKNrzk27Dr7s4lPLnewbHue1+gM=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6 h1:iRN4+t0lvZX/l9gH14ARF9i58tsVa5a97k6aH95rC3Y=
google.golang.org/genproto v0.0.0-20201111145450-ac7456db90a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201119123407-9b1e624d6bc4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201204160425-06b3db808446 h1:65ppmIPdaZE+BO34gntwqexoTYr30IRNGmS0OGOHu3A=
google.golang.org/genproto v0.0.0-20201204160425-06b3db808446/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d h1:HV9Z9qMhQEsdlvxNFELgQ11RkMzO3CMkjEySjCtuLes=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4 h1:HPkKL4eEh/nemF/FRzYMrFsAh1ZPm5t8NqKBI/Ejlg0=
google.golang.org/genproto v0.0.0-20210201151548-94839c025ad4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210201184850-646a494a81ea h1:B/tOZ5zKaomKBjKJJMjuqwmIc3YNX10q5DcCt8xLYY4=
google.golang.org/genproto v0.0.0-20210201184850-646a494a81ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@@ -1165,6 +1301,10 @@ google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
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=
@@ -1212,6 +1352,8 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -27,6 +27,10 @@ import (
// ConnectToBeaconNode connects to a beacon node at the given address.
func ConnectToBeaconNode(ctx context.Context, address string, timeout time.Duration, allowInsecure bool) (eth2client.Service, error) {
if timeout == 0 {
return nil, errors.New("no timeout specified")
}
if !allowInsecure {
// Ensure the connection is either secure or local.
connectionURL, err := url.Parse(address)

View File

@@ -11,7 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package core
package util
import (
"context"
@@ -23,7 +23,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
dirk "github.com/wealdtech/go-eth2-wallet-dirk"
@@ -44,20 +43,20 @@ func SetupStore() error {
// Set up our wallet store.
switch viper.GetString("store") {
case "s3":
if util.GetBaseDir() != "" {
if GetBaseDir() != "" {
return errors.New("basedir does not apply to the s3 store")
}
store, err = s3.New(s3.WithPassphrase([]byte(util.GetStorePassphrase())))
store, err = s3.New(s3.WithPassphrase([]byte(GetStorePassphrase())))
if err != nil {
return errors.Wrap(err, "failed to access Amazon S3 wallet store")
}
case "filesystem":
opts := make([]filesystem.Option, 0)
if util.GetStorePassphrase() != "" {
opts = append(opts, filesystem.WithPassphrase([]byte(util.GetStorePassphrase())))
if GetStorePassphrase() != "" {
opts = append(opts, filesystem.WithPassphrase([]byte(GetStorePassphrase())))
}
if util.GetBaseDir() != "" {
opts = append(opts, filesystem.WithLocation(viper.GetString("base-dir")))
if GetBaseDir() != "" {
opts = append(opts, filesystem.WithLocation(GetBaseDir()))
}
store = filesystem.New(opts...)
default:
@@ -128,7 +127,7 @@ func WalletAndAccountFromInput(ctx context.Context) (e2wtypes.Wallet, e2wtypes.A
func WalletAndAccountFromPath(ctx context.Context, path string) (e2wtypes.Wallet, e2wtypes.Account, error) {
wallet, err := WalletFromPath(ctx, path)
if err != nil {
return nil, nil, errors.Wrap(err, "faild to open wallet for account")
return nil, nil, errors.Wrap(err, "failed to open wallet for account")
}
_, accountName, err := e2wallet.WalletAndAccountNames(path)
if err != nil {
@@ -139,13 +138,13 @@ func WalletAndAccountFromPath(ctx context.Context, path string) (e2wtypes.Wallet
}
if wallet.Type() == "hierarchical deterministic" && strings.HasPrefix(accountName, "m/") {
if util.GetWalletPassphrase() == "" {
if GetWalletPassphrase() == "" {
return nil, nil, errors.New("walletpassphrase is required for direct path derivations")
}
locker, isLocker := wallet.(e2wtypes.WalletLocker)
if isLocker {
err = locker.Unlock(ctx, []byte(util.GetWalletPassphrase()))
err = locker.Unlock(ctx, []byte(GetWalletPassphrase()))
if err != nil {
return nil, nil, errors.New("failed to unlock wallet")
}
@@ -168,7 +167,7 @@ func WalletAndAccountFromPath(ctx context.Context, path string) (e2wtypes.Wallet
func WalletAndAccountsFromPath(ctx context.Context, path string) (e2wtypes.Wallet, []e2wtypes.Account, error) {
wallet, err := WalletFromPath(ctx, path)
if err != nil {
return nil, nil, errors.Wrap(err, "faild to open wallet for account")
return nil, nil, errors.Wrap(err, "failed to open wallet for account")
}
_, accountSpec, err := e2wallet.WalletAndAccountNames(path)

View File

@@ -11,12 +11,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
package util
import (
"context"
"fmt"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
"github.com/spf13/viper"
@@ -24,66 +24,54 @@ import (
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
// verifyStruct verifies the signature of an arbitrary structure.
func verifyStruct(account e2wtypes.Account, data interface{}, domain []byte, signature e2types.Signature) (bool, error) {
objRoot, err := ssz.HashTreeRoot(data)
outputIf(debug, fmt.Sprintf("Object root is %#x", objRoot))
if err != nil {
return false, err
}
return verifyRoot(account, objRoot, domain, signature)
}
// 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 e2wtypes.Account, root [32]byte, domain []byte) (e2types.Signature, error) {
// SignRoot signs the hash tree root of a data structure
func SignRoot(account e2wtypes.Account, root spec.Root, domain spec.Domain) (e2types.Signature, error) {
if _, isProtectingSigner := account.(e2wtypes.AccountProtectingSigner); isProtectingSigner {
// Signer signs the data to sign itself.
return signGeneric(account, root[:], domain)
// Signer builds the signing data.
return signGeneric(account, root, domain)
}
// Build the signing data manually.
container := &signingContainer{
Root: root[:],
Domain: domain,
container := &spec.SigningData{
ObjectRoot: root,
Domain: domain,
}
outputIf(debug, fmt.Sprintf("Signing container:\n root: %#x\n domain: %#x", container.Root, container.Domain))
signingRoot, err := ssz.HashTreeRoot(container)
// outputIf(debug, fmt.Sprintf("Signing container:\n root: %#x\n domain: %#x", container.ObjectRoot, container.Domain))
signingRoot, err := container.HashTreeRoot()
if err != nil {
return nil, err
}
outputIf(debug, fmt.Sprintf("Signing root: %#x", signingRoot))
// outputIf(debug, fmt.Sprintf("Signing root: %#x", signingRoot))
return sign(account, signingRoot[:])
}
func verifyRoot(account e2wtypes.Account, root [32]byte, domain []byte, signature e2types.Signature) (bool, error) {
// VerifyRoot verifies the hash tree root of a data structure.
func VerifyRoot(account e2wtypes.Account, root spec.Root, domain spec.Domain, signature e2types.Signature) (bool, error) {
// Build the signing data manually.
container := &signingContainer{
Root: root[:],
Domain: domain,
container := &spec.SigningData{
ObjectRoot: root,
Domain: domain,
}
outputIf(debug, fmt.Sprintf("Signing container:\n root: %#x\n domain: %#x", container.Root, container.Domain))
// outputIf(debug, fmt.Sprintf("Signing container:\n root: %#x\n domain: %#x", container.ObjectRoot, container.Domain))
signingRoot, err := ssz.HashTreeRoot(container)
if err != nil {
return false, err
}
outputIf(debug, fmt.Sprintf("Signing root: %#x", signingRoot))
return verify(account, signingRoot[:], signature)
// outputIf(debug, fmt.Sprintf("Signing root: %#x", signingRoot))
pubKey, err := BestPublicKey(account)
if err != nil {
return false, errors.Wrap(err, "failed to obtain account public key")
}
return signature.Verify(signingRoot[:], pubKey), nil
}
func signGeneric(account e2wtypes.Account, data []byte, domain []byte) (e2types.Signature, error) {
// signGeneric signs generic data.
func signGeneric(account e2wtypes.Account, data spec.Root, domain spec.Domain) (e2types.Signature, error) {
alreadyUnlocked, err := unlock(account)
if err != nil {
return nil, err
}
outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data)))
// outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data)))
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
@@ -92,8 +80,8 @@ func signGeneric(account e2wtypes.Account, data []byte, domain []byte) (e2types.
return nil, errors.New("account does not provide generic signing")
}
signature, err := signer.SignGeneric(ctx, data, domain)
errCheck(err, "failed to sign")
signature, err := signer.SignGeneric(ctx, data[:], domain[:])
// errCheck(err, "failed to sign")
if !alreadyUnlocked {
if err := lock(account); err != nil {
return nil, errors.Wrap(err, "failed to lock account")
@@ -108,7 +96,7 @@ func sign(account e2wtypes.Account, data []byte) (e2types.Signature, error) {
if err != nil {
return nil, err
}
outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data)))
// outputIf(debug, fmt.Sprintf("Signing %x (%d)", data, len(data)))
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
@@ -118,7 +106,7 @@ func sign(account e2wtypes.Account, data []byte) (e2types.Signature, error) {
}
signature, err := signer.Sign(ctx, data)
errCheck(err, "failed to sign")
// errCheck(err, "failed to sign")
if !alreadyUnlocked {
if err := lock(account); err != nil {
return nil, errors.Wrap(err, "failed to lock account")
@@ -127,20 +115,11 @@ func sign(account e2wtypes.Account, data []byte) (e2types.Signature, error) {
return signature, err
}
// verify the signature of arbitrary data.
func verify(account e2wtypes.Account, data []byte, signature e2types.Signature) (bool, error) {
pubKey, err := bestPublicKey(account)
if err != nil {
return false, errors.Wrap(err, "failed to obtain account public key")
}
return signature.Verify(data, pubKey), nil
}
// unlock attempts to unlock an account. It returns true if the account was already unlocked.
func unlock(account e2wtypes.Account) (bool, error) {
locker, isAccountLocker := account.(e2wtypes.AccountLocker)
if !isAccountLocker {
outputIf(debug, "Account does not support unlocking")
// outputIf(debug, "Account does not support unlocking")
// This account doesn't support unlocking; return okay.
return true, nil
}
@@ -157,7 +136,7 @@ func unlock(account e2wtypes.Account) (bool, error) {
}
// Not already unlocked; attempt to unlock it.
for _, passphrase := range getPassphrases() {
for _, passphrase := range GetPassphrases() {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
err = locker.Unlock(ctx, []byte(passphrase))
cancel()

View File

@@ -25,19 +25,19 @@ import (
// ValidatorExitData contains data for a validator exit.
type ValidatorExitData struct {
Data *spec.SignedVoluntaryExit
Exit *spec.SignedVoluntaryExit
ForkVersion spec.Version
}
type validatorExitJSON struct {
Data *spec.SignedVoluntaryExit `json:"data"`
Exit *spec.SignedVoluntaryExit `json:"exit"`
ForkVersion string `json:"fork_version"`
}
// MarshalJSON implements custom JSON marshaller.
func (d *ValidatorExitData) MarshalJSON() ([]byte, error) {
validatorExitJSON := &validatorExitJSON{
Data: d.Data,
Exit: d.Exit,
ForkVersion: fmt.Sprintf("%#x", d.ForkVersion),
}
return json.Marshal(validatorExitJSON)
@@ -51,10 +51,10 @@ func (d *ValidatorExitData) UnmarshalJSON(data []byte) error {
return errors.Wrap(err, "failed to unmarshal JSON")
}
if validatorExitJSON.Data == nil {
return errors.New("data missing")
if validatorExitJSON.Exit == nil {
return errors.New("exit missing")
}
d.Data = validatorExitJSON.Data
d.Exit = validatorExitJSON.Exit
if validatorExitJSON.ForkVersion == "" {
return errors.New("fork version missing")

View File

@@ -38,28 +38,28 @@ func TestUnmarshal(t *testing.T) {
err: "invalid character 'i' looking for beginning of value",
},
{
name: "DataMissing",
name: "ExitMissing",
in: []byte(`{"fork_version":"0x00000001"}`),
err: "data missing",
err: "exit missing",
},
{
name: "DataInvalid",
in: []byte(`{"data":{},"fork_version":"0x00000001"}`),
name: "ExitInvalid",
in: []byte(`{"exit":{},"fork_version":"0x00000001"}`),
err: "failed to unmarshal JSON: message missing",
},
{
name: "ForkVersionMissing",
in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"}}`),
in: []byte(`{"exit":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"}}`),
err: "fork version missing",
},
{
name: "ForkVersionInvalid",
in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"invalid"}`),
in: []byte(`{"exit":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"invalid"}`),
err: "fork version invalid: encoding/hex: invalid byte: U+0069 'i'",
},
{
name: "Good",
in: []byte(`{"data":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"0x00000001"}`),
in: []byte(`{"exit":{"message":{"epoch":"0","validator_index":"0"},"signature":"0xb74eade64ebf1e02cc57e5d29517032c6ca99132fb8e7fb7e6d58c68713e581ef0ef88e2a6c599a007d997782abdd50b0f9763500a93a971c89cb2275583fe755d7c0e64f459ff22fcef5cab3f80848f0356e67c142b9cf3ee65613f56283d6e"},"fork_version":"0x00000001"}`),
},
}