Compare commits

...

16 Commits

Author SHA1 Message Date
Jim McDonald
cc59ab618d Tidy up tests. 2021-02-02 20:57:01 +00:00
Jim McDonald
9794949e8a Tidy up separation of input and process. 2021-02-02 20:50:45 +00:00
Jim McDonald
5c741d2b27 Update dependencies. 2021-02-01 19:13:18 +00:00
Jim McDonald
52c76deb5e Add attester duties and slot time commands. 2021-01-24 13:46:35 +00:00
Jim McDonald
c986118f16 Fix typo 2021-01-24 12:25:47 +00:00
Jim McDonald
df6694e3b7 Update tests. 2021-01-02 15:21:56 +00:00
Jim McDonald
a55ad238e6 Add 'node events' command. 2021-01-02 15:20:42 +00:00
Jim McDonald
be21db030e Update chain info fork version type 2021-01-02 10:15:07 +00:00
Jim McDonald
16488c8a40 Add activation epoch to validator info. 2021-01-02 10:13:29 +00:00
Jim McDonald
a7489aa675 Reformat changelog 2020-12-10 07:14:04 +00:00
Jim McDonald
b1647d2f3d Update version. 2020-12-10 00:10:46 +00:00
Jim McDonald
c7f3275dfa Add validtor duties; update validator exit 2020-12-09 20:38:21 +00:00
Jim McDonald
7aeba43338 Add validtor duties; update validator exit 2020-12-09 20:33:30 +00:00
Jim McDonald
688db9ef8c Update dependencies. 2020-12-07 15:21:37 +00:00
Jim McDonald
173883da3e Move core functions to util 2020-12-07 15:18:23 +00:00
Jim McDonald
6077e04619 Move core functions to util 2020-12-07 14:52:08 +00:00
68 changed files with 2768 additions and 247 deletions

View File

@@ -1,8 +1,21 @@
1.7.5:
- 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
@@ -13,12 +26,15 @@
- renamed "--exportpassphrase" and "--importpassphrase" flags to "--passphrase"
- reworked internal structure of account-related commands
- reject weak passphrases by default
1.6.1:
- "attester inclusion" defaults to previous epoch
- output array for launchpad deposit data JSON in all situations
1.6.0:
- update BLS HKDF function to match spec 04
- add --launchpad option to "validator depositdata" to output data in launchpad format
1.5.9:
- fix issue where wallet mnemonics were not normalised to NFKD
- "block info" supports fetching the gensis block (--slot=0)

View File

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

View File

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

View File

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

View File

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

32
cmd/attestation.go Normal file
View File

@@ -0,0 +1,32 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/spf13/cobra"
)
// attestationCmd represents the attestation command
var attestationCmd = &cobra.Command{
Use: "attestation",
Short: "Obtain information about an Ethereum 2 attestation",
Long: "Obtain information about an Ethereum 2 attestation",
}
func init() {
RootCmd.AddCommand(attestationCmd)
}
func attestationFlags(cmd *cobra.Command) {
}

View File

@@ -0,0 +1,87 @@
// 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"
"time"
eth2client "github.com/attestantio/go-eth2-client"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"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
json bool
// Chain information.
slotsPerEpoch uint64
// Operation.
account string
pubKey string
eth2Client eth2client.Service
epoch spec.Epoch
}
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 or pubkey.
if viper.GetString("account") == "" && viper.GetString("pubkey") == "" {
return nil, errors.New("account or pubkey is required")
}
data.account = viper.GetString("account")
data.pubKey = viper.GetString("pubkey")
// 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")
}
// 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)
return data, nil
}

View File

@@ -0,0 +1,96 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package 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: "account or pubkey is required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

View File

@@ -0,0 +1,55 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package attesterduties
import (
"context"
"encoding/json"
"fmt"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
json bool
duty *api.AttesterDuty
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
if data.duty == nil {
return "No duties found", nil
}
if data.json {
bytes, err := json.Marshal(data.duty)
if err != nil {
return "", errors.Wrap(err, "failed to marshalJSON")
}
return string(bytes), nil
}
return fmt.Sprintf("Validator attesting in slot %d committee %d", data.duty.Slot, data.duty.CommitteeIndex), nil
}

View File

@@ -0,0 +1,85 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package attesterduties
import (
"context"
"testing"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
)
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
res string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Empty",
dataOut: &dataOut{},
res: "No duties found",
},
{
name: "Present",
dataOut: &dataOut{
duty: &api.AttesterDuty{
PubKey: testutil.HexToPubKey("0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"),
Slot: 1,
ValidatorIndex: 2,
CommitteeIndex: 3,
CommitteeLength: 4,
CommitteesAtSlot: 5,
ValidatorCommitteeIndex: 6,
},
},
res: "Validator attesting in slot 1 committee 3",
},
{
name: "JSON",
dataOut: &dataOut{
json: true,
duty: &api.AttesterDuty{
PubKey: testutil.HexToPubKey("0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95"),
Slot: 1,
ValidatorIndex: 2,
CommitteeIndex: 3,
CommitteeLength: 4,
CommitteesAtSlot: 5,
ValidatorCommitteeIndex: 6,
},
},
res: `{"pubkey":"0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95","slot":"1","validator_index":"2","committee_index":"3","committee_length":"4","committees_at_slot":"5","validator_committee_index":"6"}`,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res, res)
}
})
}
}

View File

@@ -0,0 +1,99 @@
// 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"
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")
}
var account e2wtypes.Account
var err error
if data.account != "" {
ctx, cancel := context.WithTimeout(ctx, data.timeout)
defer cancel()
_, account, err = util.WalletAndAccountFromPath(ctx, data.account)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
} else {
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(data.pubKey, "0x"))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", data.pubKey))
}
account, err = util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", data.pubKey))
}
}
// Fetch validator
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := util.BestPublicKey(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")
}
validator := validators[0]
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
duty, err := duty(ctx, data.eth2Client, validator, data.epoch, data.slotsPerEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain duty for validator")
}
results.duty = duty
return results, nil
}
func duty(ctx context.Context, eth2Client eth2client.Service, validator *api.Validator, epoch spec.Epoch, slotsPerEpoch uint64) (*api.AttesterDuty, error) {
// Find the attesting slot for the given epoch.
duties, err := eth2Client.(eth2client.AttesterDutiesProvider).AttesterDuties(ctx, epoch, []spec.ValidatorIndex{validator.Index})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain attester duties")
}
if len(duties) == 0 {
return nil, errors.New("validator does not have duty for that epoch")
}
return duties[0], nil
}

View File

@@ -0,0 +1,66 @@
// 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/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,
pubKey: "0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95",
epoch: 100,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@@ -0,0 +1,50 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package attesterduties
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

View File

@@ -15,19 +15,13 @@ package attesterinclusion
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/core"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
type dataIn struct {
@@ -39,10 +33,10 @@ type dataIn struct {
// Chain information.
slotsPerEpoch uint64
// Operation.
validator *api.Validator
eth2Client eth2client.Service
epoch spec.Epoch
account e2wtypes.Account
account string
pubKey string
}
func input(ctx context.Context) (*dataIn, error) {
@@ -56,27 +50,29 @@ func input(ctx context.Context) (*dataIn, error) {
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
// Account.
var err error
data.account, err = attesterInclusionAccount()
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
// Account or pubkey.
if viper.GetString("account") == "" && viper.GetString("pubkey") == "" {
return nil, errors.New("account or pubkey is required")
}
data.account = viper.GetString("account")
data.pubKey = viper.GetString("pubkey")
// 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")
}
// 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,42 +85,5 @@ func input(ctx context.Context) (*dataIn, error) {
}
data.epoch = spec.Epoch(epoch)
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := core.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")
}
data.validator = validators[0]
return data, nil
}
// attesterInclusionAccount obtains the account for the attester inclusion command.
func attesterInclusionAccount() (e2wtypes.Account, error) {
var account e2wtypes.Account
var err error
if viper.GetString("account") != "" {
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout"))
defer cancel()
_, account, err = core.WalletAndAccountFromPath(ctx, viper.GetString("account"))
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
} else {
pubKey := viper.GetString("pubkey")
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(pubKey, "0x"))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", pubKey))
}
account, err = util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", pubKey))
}
}
return account, nil
}

View File

@@ -65,7 +65,7 @@ func TestInput(t *testing.T) {
vars: map[string]interface{}{
"timeout": "5s",
},
err: "failed to obtain account: invalid public key : public key must be 48 bytes",
err: "account or pubkey is required",
},
{
name: "ConnectionMissing",

View File

@@ -15,12 +15,16 @@ package attesterinclusion
import (
"context"
"encoding/hex"
"fmt"
"strings"
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) {
@@ -28,13 +32,49 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) {
return nil, errors.New("no data")
}
var account e2wtypes.Account
var err error
if data.account != "" {
ctx, cancel := context.WithTimeout(ctx, data.timeout)
defer cancel()
_, account, err = util.WalletAndAccountFromPath(ctx, data.account)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain account")
}
} else {
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(data.pubKey, "0x"))
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", data.pubKey))
}
account, err = util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", data.pubKey))
}
}
// Fetch validator
pubKeys := make([]spec.BLSPubKey, 1)
pubKey, err := util.BestPublicKey(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")
}
validator := validators[0]
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
duty, err := duty(ctx, data.eth2Client, data.validator, data.epoch, data.slotsPerEpoch)
duty, err := duty(ctx, data.eth2Client, validator, data.epoch, data.slotsPerEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain duty for validator")
}
@@ -67,7 +107,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) {

View File

@@ -18,7 +18,6 @@ import (
"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"
@@ -48,10 +47,8 @@ func TestProcess(t *testing.T) {
dataIn: &dataIn{
eth2Client: eth2Client,
slotsPerEpoch: 32,
validator: &api.Validator{
Index: 0,
},
epoch: 100,
pubKey: "0x933ad9491b62059dd065b560d256d8957a8c402cc6e8d8ee7290ae11e8f7329267a8811c397529dac52ae1342ba58c95",
epoch: 100,
},
},
}

65
cmd/attesterduties.go Normal file
View File

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

View File

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

View File

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

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

@@ -0,0 +1,59 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeevents
import (
"context"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Operation.
topics []string
eth2Client eth2client.Service
jsonOutput bool
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
data.jsonOutput = viper.GetBool("json")
data.topics = viper.GetStringSlice("topics")
var err error
data.eth2Client, err = util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
return data, nil
}

View File

@@ -0,0 +1,109 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeevents
import (
"context"
"os"
"testing"
"time"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{},
err: "timeout is required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
{
name: "ConnectionBad",
vars: map[string]interface{}{
"timeout": "5s",
"connection": "localhost:1",
"topics": []string{"one", "two"},
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: failed to connect to Ethereum 2 client with any known method",
},
{
name: "TopicsNil",
vars: map[string]interface{}{
"timeout": "5s",
"connection": os.Getenv("ETHDO_TEST_CONNECTION"),
},
res: &dataIn{
timeout: 5 * time.Second,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
require.Equal(t, test.res.topics, res.topics)
}
})
}
}

View File

@@ -0,0 +1,52 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeevents
import (
"context"
"encoding/json"
"fmt"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
var jsonOutput bool
func process(ctx context.Context, data *dataIn) error {
if data == nil {
return errors.New("no data")
}
err := data.eth2Client.(eth2client.EventsProvider).Events(ctx, data.topics, eventHandler)
if err != nil {
return errors.Wrap(err, "failed to connect for events")
}
<-ctx.Done()
return nil
}
func eventHandler(event *api.Event) {
if event.Data == nil {
return
}
data, err := json.Marshal(event)
if err == nil {
fmt.Println(string(data))
}
}

View File

@@ -0,0 +1,74 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeevents
import (
"context"
"os"
"testing"
"github.com/attestantio/go-eth2-client/auto"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
os.Setenv("ETHDO_ALLOW_INSECURE_CONNECTIONS", "true")
eth2Client, err := auto.New(context.Background(),
auto.WithLogLevel(zerolog.Disabled),
auto.WithAddress(os.Getenv("ETHDO_TEST_CONNECTION")),
)
require.NoError(t, err)
tests := []struct {
name string
dataIn *dataIn
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "TopicsNil",
dataIn: &dataIn{
eth2Client: eth2Client,
},
err: "failed to connect for events: no topics supplied",
},
{
name: "TopicsUnknown",
dataIn: &dataIn{
eth2Client: eth2Client,
topics: []string{"foo"},
},
err: "failed to connect for events: unsupported event topic foo",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

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

@@ -0,0 +1,41 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nodeevents
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
if err := process(ctx, dataIn); err != nil {
return "", errors.Wrap(err, "failed to process")
}
// Process generates all output.
return "", nil
}

52
cmd/nodeevents.go Normal file
View File

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

32
cmd/proposer.go Normal file
View File

@@ -0,0 +1,32 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/spf13/cobra"
)
// proposerCmd represents the proposer command
var proposerCmd = &cobra.Command{
Use: "proposer",
Short: "Obtain information about Ethereum 2 proposers",
Long: "Obtain information about Ethereum 2 proposers",
}
func init() {
RootCmd.AddCommand(proposerCmd)
}
func proposerFlags(cmd *cobra.Command) {
}

View File

@@ -25,7 +25,6 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/core"
"github.com/wealdtech/ethdo/util"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
@@ -69,14 +68,22 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
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":
@@ -94,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
}
@@ -105,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)
}
}
@@ -300,7 +306,7 @@ func walletAndAccountFromInput(ctx context.Context) (e2wtypes.Wallet, e2wtypes.A
func walletAndAccountFromPath(ctx context.Context, path string) (e2wtypes.Wallet, e2wtypes.Account, error) {
wallet, err := walletFromPath(ctx, path)
if err != nil {
return nil, nil, errors.Wrap(err, "faild to open wallet for account")
return nil, nil, errors.Wrap(err, "failed to open wallet for account")
}
_, accountName, err := e2wallet.WalletAndAccountNames(path)
if err != nil {

View File

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

View File

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

32
cmd/slot.go Normal file
View File

@@ -0,0 +1,32 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"github.com/spf13/cobra"
)
// slotCmd represents the slot command
var slotCmd = &cobra.Command{
Use: "slot",
Short: "Obtain information about an Ethereum 2 slot",
Long: "Obtain information about an Ethereum 2 slot",
}
func init() {
RootCmd.AddCommand(slotCmd)
}
func slotFlags(cmd *cobra.Command) {
}

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

@@ -0,0 +1,61 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/wealdtech/ethdo/util"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Operation.
slot string
eth2Client eth2client.Service
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
if viper.GetString("slot") == "" {
return nil, errors.New("slot is required")
}
data.slot = viper.GetString("slot")
// Ethereum 2 client.
var err error
data.eth2Client, err = util.ConnectToBeaconNode(ctx, viper.GetString("connection"), viper.GetDuration("timeout"), viper.GetBool("allow-insecure-connections"))
if err != nil {
return nil, errors.Wrap(err, "failed to connect to Ethereum 2 beacon node")
}
return data, nil
}

View File

@@ -0,0 +1,96 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"os"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{},
err: "timeout is required",
},
{
name: "SlotMissing",
vars: map[string]interface{}{
"timeout": "5s",
},
err: "slot is required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"slot": "1",
},
err: "failed to connect to Ethereum 2 beacon node: failed to connect to beacon node: problem with parameters: no address specified",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

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

@@ -0,0 +1,44 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"fmt"
"time"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
startTime time.Time
endTime time.Time
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
if data.verbose {
return fmt.Sprintf("%s - %s", data.startTime, data.endTime), nil
}
return fmt.Sprintf("%s", data.startTime), nil
}

View File

@@ -0,0 +1,64 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestOutput(t *testing.T) {
tests := []struct {
name string
dataOut *dataOut
res string
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Normal",
dataOut: &dataOut{
startTime: time.Unix(1606824023, 0),
},
res: "2020-12-01 12:00:23 +0000 GMT",
},
{
name: "Verbose",
dataOut: &dataOut{
startTime: time.Unix(1606824023, 0),
endTime: time.Unix(1606824035, 0),
verbose: true,
},
res: "2020-12-01 12:00:23 +0000 GMT - 2020-12-01 12:00:35 +0000 GMT",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := output(context.Background(), test.dataOut)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res, res)
}
})
}
}

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

@@ -0,0 +1,60 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"strconv"
"time"
eth2client "github.com/attestantio/go-eth2-client"
"github.com/pkg/errors"
)
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
slot, err := strconv.ParseInt(data.slot, 10, 64)
if err != nil {
return nil, errors.Wrap(err, "invalid slot specified")
}
if slot < 0 {
return nil, errors.New("slot must be a positive integer")
}
genesis, err := data.eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain genesis information")
}
config, err := data.eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain chain specifications")
}
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
results.startTime = genesis.GenesisTime.Add(time.Duration((time.Duration(slot*int64(slotDuration.Seconds())) * time.Second)))
results.endTime = results.startTime.Add(slotDuration)
return results, nil
}

View File

@@ -0,0 +1,76 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"os"
"testing"
"time"
"github.com/attestantio/go-eth2-client/auto"
"github.com/rs/zerolog"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
eth2Client, err := auto.New(context.Background(),
auto.WithLogLevel(zerolog.Disabled),
auto.WithAddress(os.Getenv("ETHDO_TEST_CONNECTION")),
)
require.NoError(t, err)
tests := []struct {
name string
dataIn *dataIn
expected time.Time
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Slot0",
dataIn: &dataIn{
eth2Client: eth2Client,
slot: "0",
},
expected: time.Unix(1606824023, 0),
},
{
name: "Slot1",
dataIn: &dataIn{
eth2Client: eth2Client,
slot: "1",
},
expected: time.Unix(1606824035, 0),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
res, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.expected, res.startTime)
}
})
}
}

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

@@ -0,0 +1,50 @@
// Copyright © 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package slottime
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

57
cmd/slottime.go Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,71 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/spf13/viper"
)
type dataIn struct {
// System.
timeout time.Duration
quiet bool
verbose bool
debug bool
// Ethereum 2 connection.
eth2Client string
allowInsecure bool
// Operation.
account string
pubKey string
index string
}
func input(ctx context.Context) (*dataIn, error) {
data := &dataIn{}
if viper.GetDuration("timeout") == 0 {
return nil, errors.New("timeout is required")
}
data.timeout = viper.GetDuration("timeout")
data.quiet = viper.GetBool("quiet")
data.verbose = viper.GetBool("verbose")
data.debug = viper.GetBool("debug")
// Ethereum 2 connection.
data.eth2Client = viper.GetString("connection")
if data.eth2Client == "" {
return nil, errors.New("connection is required")
}
data.allowInsecure = viper.GetBool("allow-insecure-connections")
// Account.
data.account = viper.GetString("account")
// PubKey.
data.pubKey = viper.GetString("pubkey")
// ID.
data.index = viper.GetString("index")
if data.account == "" && data.pubKey == "" && data.index == "" {
return nil, errors.New("account, pubkey or index required")
}
return data, nil
}

View File

@@ -0,0 +1,100 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"os"
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"github.com/wealdtech/ethdo/testutil"
e2types "github.com/wealdtech/go-eth2-types/v2"
e2wallet "github.com/wealdtech/go-eth2-wallet"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
nd "github.com/wealdtech/go-eth2-wallet-nd/v2"
scratch "github.com/wealdtech/go-eth2-wallet-store-scratch"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func TestInput(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
require.NoError(t, e2types.InitBLS())
store := scratch.New()
require.NoError(t, e2wallet.UseStore(store))
testWallet, err := nd.CreateWallet(context.Background(), "Test wallet", store, keystorev4.New())
require.NoError(t, err)
require.NoError(t, testWallet.(e2wtypes.WalletLocker).Unlock(context.Background(), nil))
viper.Set("passphrase", "pass")
_, err = testWallet.(e2wtypes.WalletAccountImporter).ImportAccount(context.Background(),
"Interop 0",
testutil.HexToBytes("0x25295f0d1d592a90b333e26e85149708208e9f8e8bc18f6c77bd62f8ad7a6866"),
[]byte("pass"),
)
require.NoError(t, err)
tests := []struct {
name string
vars map[string]interface{}
res *dataIn
err string
}{
{
name: "TimeoutMissing",
vars: map[string]interface{}{
"connection": "http://locahost:4000",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "timeout is required",
},
{
name: "AccountMissing",
vars: map[string]interface{}{
"timeout": "5s",
"connection": "http://locahost:4000",
},
err: "account, pubkey or index required",
},
{
name: "ConnectionMissing",
vars: map[string]interface{}{
"timeout": "5s",
"pubkey": "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c",
},
err: "connection is required",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
viper.Reset()
for k, v := range test.vars {
viper.Set(k, v)
}
res, err := input(context.Background())
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
require.Equal(t, test.res.timeout, res.timeout)
}
})
}
}

View File

@@ -0,0 +1,112 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"fmt"
"strings"
"time"
api "github.com/attestantio/go-eth2-client/api/v1"
"github.com/pkg/errors"
)
type dataOut struct {
debug bool
quiet bool
verbose bool
genesisTime time.Time
slotDuration time.Duration
slotsPerEpoch uint64
thisEpochAttesterDuty *api.AttesterDuty
thisEpochProposerDuties []*api.ProposerDuty
nextEpochAttesterDuty *api.AttesterDuty
}
func output(ctx context.Context, data *dataOut) (string, error) {
if data == nil {
return "", errors.New("no data")
}
if data.quiet {
return "", nil
}
builder := strings.Builder{}
now := time.Now()
builder.WriteString("Current time: ")
builder.WriteString(now.Format("15:04:05\n"))
if data.thisEpochAttesterDuty != nil {
thisEpochAttesterSlot := data.thisEpochAttesterDuty.Slot
thisSlotStart := data.genesisTime.Add(time.Duration(thisEpochAttesterSlot) * data.slotDuration)
thisSlotEnd := thisSlotStart.Add(data.slotDuration)
if thisSlotEnd.After(now) {
builder.WriteString("Upcoming attestation slot this epoch: ")
builder.WriteString(thisSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(thisSlotEnd.Format("15:04:05 ("))
until := thisSlotStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
}
for _, proposerDuty := range data.thisEpochProposerDuties {
proposerSlot := proposerDuty.Slot
proposerSlotStart := data.genesisTime.Add(time.Duration(proposerSlot) * data.slotDuration)
proposerSlotEnd := proposerSlotStart.Add(data.slotDuration)
builder.WriteString("Upcoming proposer slot this epoch: ")
builder.WriteString(proposerSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(proposerSlotEnd.Format("15:04:05 ("))
until := proposerSlotStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
if data.nextEpochAttesterDuty != nil {
nextEpochAttesterSlot := data.nextEpochAttesterDuty.Slot
nextSlotStart := data.genesisTime.Add(time.Duration(nextEpochAttesterSlot) * data.slotDuration)
nextSlotEnd := nextSlotStart.Add(data.slotDuration)
builder.WriteString("Upcoming attestation slot next epoch: ")
builder.WriteString(nextSlotStart.Format("15:04:05"))
builder.WriteString(" - ")
builder.WriteString(nextSlotEnd.Format("15:04:05 ("))
until := nextSlotStart.Sub(now)
builder.WriteString(fmt.Sprintf("%ds until start of slot)\n", int(until.Seconds())))
nextEpoch := uint64(data.nextEpochAttesterDuty.Slot) / data.slotsPerEpoch
nextEpochStart := data.genesisTime.Add(time.Duration(nextEpoch*data.slotsPerEpoch) * data.slotDuration)
builder.WriteString("Next epoch starts ")
builder.WriteString(nextEpochStart.Format("15:04:05 ("))
until = nextEpochStart.Sub(now)
if until > 0 {
builder.WriteString(fmt.Sprintf("%ds until start of epoch)\n", int(until.Seconds())))
} else {
builder.WriteString("\n")
}
}
return builder.String(), nil
}

View File

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

View File

@@ -0,0 +1,182 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
eth2client "github.com/attestantio/go-eth2-client"
api "github.com/attestantio/go-eth2-client/api/v1"
spec "github.com/attestantio/go-eth2-client/spec/phase0"
"github.com/pkg/errors"
"github.com/wealdtech/ethdo/util"
e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2"
)
func process(ctx context.Context, data *dataIn) (*dataOut, error) {
if data == nil {
return nil, errors.New("no data")
}
// Ethereum 2 client.
eth2Client, err := util.ConnectToBeaconNode(ctx, data.eth2Client, data.timeout, data.allowInsecure)
if err != nil {
return nil, err
}
results := &dataOut{
debug: data.debug,
quiet: data.quiet,
verbose: data.verbose,
}
validatorIndex, err := validatorIndex(ctx, eth2Client, data)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain validator index")
}
// Fetch duties for this and next epoch.
thisEpoch, err := currentEpoch(ctx, eth2Client)
if err != nil {
return nil, errors.Wrap(err, "failed to calculate current epoch")
}
thisEpochAttesterDuty, err := attesterDuty(ctx, eth2Client, validatorIndex, thisEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain this epoch duty for validator")
}
results.thisEpochAttesterDuty = thisEpochAttesterDuty
thisEpochProposerDuties, err := proposerDuties(ctx, eth2Client, validatorIndex, thisEpoch)
results.thisEpochProposerDuties = thisEpochProposerDuties
nextEpoch := thisEpoch + 1
nextEpochAttesterDuty, err := attesterDuty(ctx, eth2Client, validatorIndex, nextEpoch)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain next epoch duty for validator")
}
results.nextEpochAttesterDuty = nextEpochAttesterDuty
genesis, err := eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain genesis data")
}
results.genesisTime = genesis.GenesisTime
config, err := eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
results.slotsPerEpoch = config["SLOTS_PER_EPOCH"].(uint64)
results.slotDuration = config["SECONDS_PER_SLOT"].(time.Duration)
return results, nil
}
func attesterDuty(ctx context.Context, eth2Client eth2client.Service, validatorIndex spec.ValidatorIndex, epoch spec.Epoch) (*api.AttesterDuty, error) {
// Find the attesting slot for the given epoch.
duties, err := eth2Client.(eth2client.AttesterDutiesProvider).AttesterDuties(ctx, epoch, []spec.ValidatorIndex{validatorIndex})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain attester duties")
}
if len(duties) == 0 {
return nil, errors.New("validator does not have duty for that epoch")
}
return duties[0], nil
}
func proposerDuties(ctx context.Context, eth2Client eth2client.Service, validatorIndex spec.ValidatorIndex, epoch spec.Epoch) ([]*api.ProposerDuty, error) {
// Fetch the proposer duties for this epoch.
proposerDuties, err := eth2Client.(eth2client.ProposerDutiesProvider).ProposerDuties(ctx, epoch, []spec.ValidatorIndex{validatorIndex})
if err != nil {
return nil, errors.Wrap(err, "failed to obtain proposer duties")
}
return proposerDuties, nil
}
func currentEpoch(ctx context.Context, eth2Client eth2client.Service) (spec.Epoch, error) {
config, err := eth2Client.(eth2client.SpecProvider).Spec(ctx)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain beacon chain configuration")
}
slotsPerEpoch := config["SLOTS_PER_EPOCH"].(uint64)
slotDuration := config["SECONDS_PER_SLOT"].(time.Duration)
genesis, err := eth2Client.(eth2client.GenesisProvider).Genesis(ctx)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain genesis data")
}
if genesis.GenesisTime.After(time.Now()) {
return spec.Epoch(0), nil
}
return spec.Epoch(uint64(time.Since(genesis.GenesisTime).Seconds()) / (uint64(slotDuration.Seconds()) * slotsPerEpoch)), nil
}
// validatorIndex obtains the index of a validator
func validatorIndex(ctx context.Context, eth2Client eth2client.Service, data *dataIn) (spec.ValidatorIndex, error) {
switch {
case data.account != "":
ctx, cancel := context.WithTimeout(context.Background(), data.timeout)
defer cancel()
_, account, err := util.WalletAndAccountFromPath(ctx, data.account)
if err != nil {
return 0, errors.Wrap(err, "failed to obtain account")
}
return accountToIndex(ctx, account, eth2Client)
case data.pubKey != "":
pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(data.pubKey, "0x"))
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", data.pubKey))
}
account, err := util.NewScratchAccount(nil, pubKeyBytes)
if err != nil {
return 0, errors.Wrap(err, fmt.Sprintf("invalid public key %s", data.pubKey))
}
return accountToIndex(ctx, account, eth2Client)
case data.index != "":
val, err := strconv.ParseUint(data.index, 10, 64)
if err != nil {
return 0, err
}
return spec.ValidatorIndex(val), nil
default:
return 0, errors.New("no validator")
}
}
func accountToIndex(ctx context.Context, account e2wtypes.Account, eth2Client eth2client.Service) (spec.ValidatorIndex, error) {
pubKey, err := util.BestPublicKey(account)
if err != nil {
return 0, err
}
pubKeys := make([]spec.BLSPubKey, 1)
copy(pubKeys[0][:], pubKey.Marshal())
validators, err := eth2Client.(eth2client.ValidatorsProvider).ValidatorsByPubKey(ctx, "head", pubKeys)
if err != nil {
return 0, err
}
for index := range validators {
return index, nil
}
return 0, errors.New("validator not found")
}

View File

@@ -0,0 +1,60 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestProcess(t *testing.T) {
if os.Getenv("ETHDO_TEST_CONNECTION") == "" {
t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests")
}
tests := []struct {
name string
dataIn *dataIn
err string
}{
{
name: "Nil",
err: "no data",
},
{
name: "Client",
dataIn: &dataIn{
timeout: 5 * time.Second,
eth2Client: os.Getenv("ETHDO_TEST_CONNECTION"),
allowInsecure: true,
index: "1",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := process(context.Background(), test.dataIn)
if test.err != "" {
require.EqualError(t, err, test.err)
} else {
require.NoError(t, err)
}
})
}
}

View File

@@ -0,0 +1,50 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package validatorduties
import (
"context"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// Run runs the wallet create data command.
func Run(cmd *cobra.Command) (string, error) {
ctx := context.Background()
dataIn, err := input(ctx)
if err != nil {
return "", errors.Wrap(err, "failed to obtain input")
}
// Further errors do not need a usage report.
cmd.SilenceUsage = true
dataOut, err := process(ctx, dataIn)
if err != nil {
return "", errors.Wrap(err, "failed to process")
}
if viper.GetBool("quiet") {
return "", nil
}
results, err := output(ctx, dataOut)
if err != nil {
return "", errors.Wrap(err, "failed to obtain output")
}
return results, nil
}

View File

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

View File

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

View File

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

View File

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

View File

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

61
cmd/validatorduties.go Normal file
View File

@@ -0,0 +1,61 @@
// Copyright © 2020 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
validatorduties "github.com/wealdtech/ethdo/cmd/validator/duties"
)
var validatorDutiesCmd = &cobra.Command{
Use: "duties",
Short: "List known duties for a validator",
Long: `List known duties for a validator. For example:
ethdo validator duties --account=Validators/One
Attester duties are known for the current and next epoch. Proposer duties are known for the current epoch.
In quiet mode this will return 0 if the the duties have been obtained, otherwise 1.`,
RunE: func(cmd *cobra.Command, args []string) error {
res, err := validatorduties.Run(cmd)
if err != nil {
return err
}
if viper.GetBool("quiet") {
return nil
}
fmt.Printf(res)
return nil
},
}
func init() {
validatorCmd.AddCommand(validatorDutiesCmd)
validatorFlags(validatorDutiesCmd)
validatorDutiesCmd.Flags().String("pubkey", "", "validator public key for duties")
validatorDutiesCmd.Flags().String("index", "", "validator index for duties")
}
func validatorDutiesBindings() {
if err := viper.BindPFlag("pubkey", validatorDutiesCmd.Flags().Lookup("pubkey")); err != nil {
panic(err)
}
if err := viper.BindPFlag("index", validatorDutiesCmd.Flags().Lookup("index")); err != nil {
panic(err)
}
}

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright © 2019, 2020 Weald Technology Trading
// Copyright © 2019 - 2021 Weald Technology Trading
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -24,7 +24,7 @@ import (
// ReleaseVersion is the release version of the codebase.
// Usually overrideen by tag names when building binaries.
var ReleaseVersion = "local build (latest release 1.7.2)"
var ReleaseVersion = "local build (latest release 1.7.5)"
// versionCmd represents the version command
var versionCmd = &cobra.Command{

View File

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

View File

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

View File

@@ -348,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.
@@ -382,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.
@@ -450,6 +475,18 @@ Effective balance: 3.1 Ether
Attester commands focus on Ethereum 2 validators' actions as attesters.
#### `duties`
`ethdo attester duties` provides information on the duties that a given validator has in a given epoch. Options include:
- `epoch` the epoch in which to obtain the duties (defaults to current epoch)
- `account` the account for which to fetch the duties (in format "wallet/account")
- `pubkey` the public key for which to fetch the duties
```sh
$ ethdo attester duties --account=Validators/0 --epoch=5
Validator attesting in slot 186 committee 3
```
#### `inclusion`
`ethdo attester inclusion` finds the block with wihch an attestation is included on the chain. Options include:

62
go.mod
View File

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

142
go.sum
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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