mirror of
https://github.com/wealdtech/ethdo.git
synced 2026-01-10 14:37:57 -05:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c741d2b27 | ||
|
|
52c76deb5e | ||
|
|
c986118f16 | ||
|
|
df6694e3b7 | ||
|
|
a55ad238e6 | ||
|
|
be21db030e | ||
|
|
16488c8a40 | ||
|
|
a7489aa675 | ||
|
|
b1647d2f3d | ||
|
|
c7f3275dfa | ||
|
|
7aeba43338 | ||
|
|
688db9ef8c | ||
|
|
173883da3e | ||
|
|
6077e04619 | ||
|
|
95c57363a2 | ||
|
|
9b96b4e34f | ||
|
|
40ba1987cd | ||
|
|
9c08c0a1a4 | ||
|
|
b2360fa2f6 | ||
|
|
e7cc6ce18b | ||
|
|
a83e206c89 | ||
|
|
947dbdaef6 | ||
|
|
ac87f51047 |
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@@ -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
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
58
cmd/account/derive/input.go
Normal file
58
cmd/account/derive/input.go
Normal 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
|
||||
}
|
||||
78
cmd/account/derive/input_internal_test.go
Normal file
78
cmd/account/derive/input_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
53
cmd/account/derive/output.go
Normal file
53
cmd/account/derive/output.go
Normal 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
|
||||
}
|
||||
98
cmd/account/derive/output_internal_test.go
Normal file
98
cmd/account/derive/output_internal_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
72
cmd/account/derive/process.go
Normal file
72
cmd/account/derive/process.go
Normal 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
|
||||
}
|
||||
97
cmd/account/derive/process_internal_test.go
Normal file
97
cmd/account/derive/process_internal_test.go
Normal 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
49
cmd/account/derive/run.go
Normal 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
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
69
cmd/accountderive.go
Normal 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
32
cmd/attestation.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2020 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
}
|
||||
131
cmd/attester/duties/input.go
Normal file
131
cmd/attester/duties/input.go
Normal 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
|
||||
}
|
||||
96
cmd/attester/duties/input_internal_test.go
Normal file
96
cmd/attester/duties/input_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
55
cmd/attester/duties/output.go
Normal file
55
cmd/attester/duties/output.go
Normal 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
|
||||
}
|
||||
85
cmd/attester/duties/output_internal_test.go
Normal file
85
cmd/attester/duties/output_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
58
cmd/attester/duties/process.go
Normal file
58
cmd/attester/duties/process.go
Normal 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
|
||||
}
|
||||
69
cmd/attester/duties/process_internal_test.go
Normal file
69
cmd/attester/duties/process_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
50
cmd/attester/duties/run.go
Normal file
50
cmd/attester/duties/run.go
Normal 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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
65
cmd/attesterduties.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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 := ðpb.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")
|
||||
}
|
||||
|
||||
@@ -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
59
cmd/node/events/input.go
Normal 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
|
||||
}
|
||||
109
cmd/node/events/input_internal_test.go
Normal file
109
cmd/node/events/input_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
52
cmd/node/events/process.go
Normal file
52
cmd/node/events/process.go
Normal 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))
|
||||
}
|
||||
}
|
||||
74
cmd/node/events/process_internal_test.go
Normal file
74
cmd/node/events/process_internal_test.go
Normal 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
41
cmd/node/events/run.go
Normal 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
52
cmd/nodeevents.go
Normal 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
32
cmd/proposer.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2020 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
}
|
||||
16
cmd/root.go
16
cmd/root.go
@@ -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 {
|
||||
|
||||
@@ -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()))
|
||||
|
||||
@@ -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
32
cmd/slot.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright © 2020 Weald Technology Trading
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// 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
61
cmd/slot/time/input.go
Normal 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
|
||||
}
|
||||
96
cmd/slot/time/input_internal_test.go
Normal file
96
cmd/slot/time/input_internal_test.go
Normal 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
44
cmd/slot/time/output.go
Normal 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
|
||||
}
|
||||
64
cmd/slot/time/output_internal_test.go
Normal file
64
cmd/slot/time/output_internal_test.go
Normal 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
60
cmd/slot/time/process.go
Normal 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
|
||||
}
|
||||
76
cmd/slot/time/process_internal_test.go
Normal file
76
cmd/slot/time/process_internal_test.go
Normal 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
50
cmd/slot/time/run.go
Normal 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
57
cmd/slottime.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"}]`,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
71
cmd/validator/duties/input.go
Normal file
71
cmd/validator/duties/input.go
Normal 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
|
||||
}
|
||||
100
cmd/validator/duties/input_internal_test.go
Normal file
100
cmd/validator/duties/input_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
112
cmd/validator/duties/output.go
Normal file
112
cmd/validator/duties/output.go
Normal 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
|
||||
}
|
||||
83
cmd/validator/duties/output_internal_test.go
Normal file
83
cmd/validator/duties/output_internal_test.go
Normal 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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
182
cmd/validator/duties/process.go
Normal file
182
cmd/validator/duties/process.go
Normal 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")
|
||||
}
|
||||
60
cmd/validator/duties/process_internal_test.go
Normal file
60
cmd/validator/duties/process_internal_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
50
cmd/validator/duties/run.go
Normal file
50
cmd/validator/duties/run.go
Normal 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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"}`,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -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
61
cmd/validatorduties.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
62
go.mod
@@ -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
142
go.sum
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
@@ -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")
|
||||
|
||||
@@ -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"}`),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user