From 1ec6ddc914971d86bacdc69689afaf804a840976 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 15:14:23 +0000 Subject: [PATCH 1/8] Set withdrawal credentials. --- cmd/account/create/process_internal_test.go | 315 --------------- cmd/account/derive/process.go | 45 +-- cmd/account/derive/process_internal_test.go | 8 +- cmd/accountcreate.go | 4 - cmd/accountderive.go | 8 - cmd/block/info/output.go | 6 +- cmd/chaininfo.go | 14 +- cmd/root.go | 22 +- cmd/slot/time/output_internal_test.go | 4 +- cmd/validator/credentials/get/command.go | 27 +- cmd/validator/credentials/get/output.go | 29 +- cmd/validator/credentials/get/process.go | 12 +- cmd/validator/credentials/set/command.go | 116 ++++++ .../credentials/set/command_internal_test.go | 83 ++++ cmd/validator/credentials/set/output.go | 37 ++ cmd/validator/credentials/set/process.go | 349 ++++++++++++++++ cmd/validator/credentials/set/run.go | 50 +++ cmd/validatorcredentialsget.go | 14 +- cmd/validatorcredentialsset.go | 87 ++++ cmd/validatorinfo.go | 82 +--- cmd/validatorkeycheck.go | 4 - cmd/walletcreate.go | 4 - docs/changingwithdrawalcredentials.md | 267 +++++++++++++ docs/usage.md | 10 +- go.mod | 38 +- go.sum | 378 +++++++++++++++--- services/chaintime/standard/service.go | 34 ++ signing/container_encoding.go | 25 +- util/account.go | 141 +++++++ util/account_test.go | 103 +++++ util/scratchaccount.go | 8 + 31 files changed, 1737 insertions(+), 587 deletions(-) delete mode 100644 cmd/account/create/process_internal_test.go create mode 100644 cmd/validator/credentials/set/command.go create mode 100644 cmd/validator/credentials/set/command_internal_test.go create mode 100644 cmd/validator/credentials/set/output.go create mode 100644 cmd/validator/credentials/set/process.go create mode 100644 cmd/validator/credentials/set/run.go create mode 100644 cmd/validatorcredentialsset.go create mode 100644 docs/changingwithdrawalcredentials.md create mode 100644 util/account_test.go diff --git a/cmd/account/create/process_internal_test.go b/cmd/account/create/process_internal_test.go deleted file mode 100644 index 82fd820..0000000 --- a/cmd/account/create/process_internal_test.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright © 2019, 2020 Weald Technology Trading -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package accountcreate - -import ( - "context" - "crypto/tls" - "crypto/x509" - "fmt" - "math/rand" - "os" - "testing" - "time" - - "github.com/attestantio/dirk/testing/daemon" - "github.com/attestantio/dirk/testing/resources" - "github.com/pkg/errors" - "github.com/stretchr/testify/require" - e2types "github.com/wealdtech/go-eth2-types/v2" - dirk "github.com/wealdtech/go-eth2-wallet-dirk" - keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" - hd "github.com/wealdtech/go-eth2-wallet-hd/v2" - nd "github.com/wealdtech/go-eth2-wallet-nd/v2" - scratch "github.com/wealdtech/go-eth2-wallet-store-scratch" - "google.golang.org/grpc/credentials" -) - -func TestProcess(t *testing.T) { - require.NoError(t, e2types.InitBLS()) - - testNDWallet, err := nd.CreateWallet(context.Background(), - "Test", - scratch.New(), - keystorev4.New(), - ) - require.NoError(t, err) - testHDWallet, err := hd.CreateWallet(context.Background(), - "Test", - []byte("pass"), - scratch.New(), - keystorev4.New(), - []byte{ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }, - ) - require.NoError(t, err) - - // #nosec G404 - port1 := uint32(12000 + rand.Intn(4000)) - // #nosec G404 - port2 := uint32(12000 + rand.Intn(4000)) - // #nosec G404 - port3 := uint32(12000 + rand.Intn(4000)) - peers := map[uint64]string{ - 1: fmt.Sprintf("signer-test01:%d", port1), - 2: fmt.Sprintf("signer-test02:%d", port2), - 3: fmt.Sprintf("signer-test03:%d", port3), - } - _, path, err := daemon.New(context.Background(), "", 1, port1, peers) - require.NoError(t, err) - defer os.RemoveAll(path) - _, path, err = daemon.New(context.Background(), "", 2, port2, peers) - require.NoError(t, err) - defer os.RemoveAll(path) - _, path, err = daemon.New(context.Background(), "", 3, port3, peers) - require.NoError(t, err) - defer os.RemoveAll(path) - endpoints := []*dirk.Endpoint{ - dirk.NewEndpoint("signer-test01", port1), - dirk.NewEndpoint("signer-test02", port2), - dirk.NewEndpoint("signer-test03", port3), - } - credentials, err := credentialsFromCerts(context.Background(), resources.ClientTest01Crt, resources.ClientTest01Key, resources.CACrt) - require.NoError(t, err) - testDistributedWallet, err := dirk.OpenWallet(context.Background(), "Wallet 3", credentials, endpoints) - require.NoError(t, err) - - tests := []struct { - name string - dataIn *dataIn - err string - }{ - { - name: "Nil", - err: "no data", - }, - { - name: "WalletPassphraseIncorrect", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Good", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "bad", - participants: 1, - signingThreshold: 1, - }, - err: "failed to unlock wallet: incorrect passphrase", - }, - { - name: "PassphraseMissing", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Good", - passphrase: "", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - }, - err: "passphrase is required", - }, - { - name: "PassphraseWeak", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Good", - passphrase: "poor", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - }, - err: "supplied passphrase is weak; use a stronger one or run with the --allow-weak-passphrases flag", - }, - { - name: "Good", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Good", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - }, - }, - { - name: "PathMalformed", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Pathed", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - path: "n/12381/3600/1/2/3", - }, - err: "path does not match expected format m/…", - }, - { - name: "PathPassphraseMissing", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Pathed", - passphrase: "", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - path: "m/12381/3600/1/2/3", - }, - err: "passphrase is required", - }, - { - name: "PathNotSupported", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testNDWallet, - accountName: "Pathed", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - path: "m/12381/3600/1/2/3", - }, - err: "wallet does not support account creation with an explicit path", - }, - { - name: "GoodWithPath", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testHDWallet, - accountName: "Pathed", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 1, - signingThreshold: 1, - path: "m/12381/3600/1/2/3", - }, - }, - { - name: "DistributedSigningThresholdZero", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testDistributedWallet, - accountName: "Remote", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 3, - signingThreshold: 0, - }, - err: "signing threshold required", - }, - { - name: "DistributedSigningThresholdNotHalf", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testDistributedWallet, - accountName: "Remote", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 3, - signingThreshold: 1, - }, - err: "signing threshold must be more than half the number of participants", - }, - { - name: "DistributedSigningThresholdTooHigh", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testDistributedWallet, - accountName: "Remote", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 3, - signingThreshold: 4, - }, - err: "signing threshold cannot be higher than the number of participants", - }, - { - name: "DistributedNotSupported", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testNDWallet, - accountName: "Remote", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 3, - signingThreshold: 2, - }, - err: "wallet does not support distributed account creation", - }, - { - name: "DistributedGood", - dataIn: &dataIn{ - timeout: 5 * time.Second, - wallet: testDistributedWallet, - accountName: "Remote", - passphrase: "ce%NohGhah4ye5ra", - walletPassphrase: "pass", - participants: 3, - signingThreshold: 2, - }, - }, - } - - 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.dataIn.accountName, res.account.Name()) - } - }) - } -} - -func TestNilData(t *testing.T) { - _, err := processStandard(context.Background(), nil) - require.EqualError(t, err, "no data") - _, err = processPathed(context.Background(), nil) - require.EqualError(t, err, "no data") - _, err = processDistributed(context.Background(), nil) - require.EqualError(t, err, "no data") -} - -func credentialsFromCerts(ctx context.Context, clientCert []byte, clientKey []byte, caCert []byte) (credentials.TransportCredentials, error) { - clientPair, err := tls.X509KeyPair(clientCert, clientKey) - if err != nil { - return nil, errors.Wrap(err, "failed to load client keypair") - } - - tlsCfg := &tls.Config{ - Certificates: []tls.Certificate{clientPair}, - MinVersion: tls.VersionTLS13, - } - - if caCert != nil { - cp := x509.NewCertPool() - if !cp.AppendCertsFromPEM(caCert) { - return nil, errors.New("failed to add CA certificate") - } - tlsCfg.RootCAs = cp - } - - return credentials.NewTLS(tlsCfg), nil -} diff --git a/cmd/account/derive/process.go b/cmd/account/derive/process.go index 89ee75c..3ef744d 100644 --- a/cmd/account/derive/process.go +++ b/cmd/account/derive/process.go @@ -16,12 +16,11 @@ package accountderive import ( "context" "regexp" - "strings" "github.com/pkg/errors" - "github.com/tyler-smith/go-bip39" - util "github.com/wealdtech/go-eth2-util" - "golang.org/x/text/unicode/norm" + "github.com/wealdtech/ethdo/util" + e2types "github.com/wealdtech/go-eth2-types/v2" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) // pathRegex is the regular expression that matches an HD path. @@ -32,40 +31,20 @@ func process(ctx context.Context, data *dataIn) (*dataOut, error) { return nil, errors.New("no data") } - // If there are more than 24 words we treat the additional characters as the passphrase. - mnemonicParts := strings.Split(data.mnemonic, " ") - mnemonicPassphrase := "" - if len(mnemonicParts) > 24 { - data.mnemonic = strings.Join(mnemonicParts[:24], " ") - mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ") - } - // Normalise the input. - data.mnemonic = string(norm.NFKD.Bytes([]byte(data.mnemonic))) - mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase))) - - if !bip39.IsMnemonicValid(data.mnemonic) { - return nil, errors.New("mnemonic is invalid") - } - - // Create seed from mnemonic and passphrase. - seed := bip39.NewSeed(data.mnemonic, mnemonicPassphrase) - - // Ensure the path is valid. - match := pathRegex.Match([]byte(data.path)) - if !match { - return nil, errors.New("path does not match expected format m/…") - } - - // Derive private key from seed and path. - key, err := util.PrivateKeyFromSeedAndPath(seed, data.path) + account, err := util.ParseAccount(ctx, data.mnemonic, []string{data.path}, true) if err != nil { - return nil, errors.Wrap(err, "failed to generate key") + return nil, errors.Wrap(err, "failed to derive account") + } + + key, err := account.(e2wtypes.AccountPrivateKeyProvider).PrivateKey(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to obtain account private key") } results := &dataOut{ - showPrivateKey: data.showPrivateKey, + showPrivateKey: data.showPrivateKey, showWithdrawalCredentials: data.showWithdrawalCredentials, - key: key, + key: key.(*e2types.BLSPrivateKey), } return results, nil diff --git a/cmd/account/derive/process_internal_test.go b/cmd/account/derive/process_internal_test.go index 1acd145..9bbd4f0 100644 --- a/cmd/account/derive/process_internal_test.go +++ b/cmd/account/derive/process_internal_test.go @@ -40,7 +40,7 @@ func TestProcess(t *testing.T) { dataIn: &dataIn{ path: "m/12381/3600/0/0", }, - err: "mnemonic is invalid", + err: "failed to derive account: no account specified", }, { name: "MnemonicInvalid", @@ -48,14 +48,14 @@ func TestProcess(t *testing.T) { mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", path: "m/12381/3600/0/0", }, - err: "mnemonic is invalid", + err: "failed to derive account: mnemonic is invalid", }, { name: "PathMissing", dataIn: &dataIn{ mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", }, - err: "path does not match expected format m/…", + err: "failed to derive account: path does not match expected format m/…", }, { name: "PathInvalid", @@ -63,7 +63,7 @@ func TestProcess(t *testing.T) { mnemonic: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", path: "n/12381/3600/0/0", }, - err: "path does not match expected format m/…", + err: "failed to derive account: path does not match expected format m/…", }, { name: "Good", diff --git a/cmd/accountcreate.go b/cmd/accountcreate.go index a05900a..b9009fb 100644 --- a/cmd/accountcreate.go +++ b/cmd/accountcreate.go @@ -49,7 +49,6 @@ func init() { accountFlags(accountCreateCmd) accountCreateCmd.Flags().Uint32("participants", 1, "Number of participants (1 for non-distributed accounts, >1 for distributed accounts)") accountCreateCmd.Flags().Uint32("signing-threshold", 1, "Signing threshold (1 for non-distributed accounts)") - accountCreateCmd.Flags().String("path", "", "path of account (for hierarchical deterministic accounts)") } func accountCreateBindings() { @@ -59,7 +58,4 @@ func accountCreateBindings() { if err := viper.BindPFlag("signing-threshold", accountCreateCmd.Flags().Lookup("signing-threshold")); err != nil { panic(err) } - if err := viper.BindPFlag("path", accountCreateCmd.Flags().Lookup("path")); err != nil { - panic(err) - } } diff --git a/cmd/accountderive.go b/cmd/accountderive.go index 245141d..270d654 100644 --- a/cmd/accountderive.go +++ b/cmd/accountderive.go @@ -47,19 +47,11 @@ In quiet mode this will return 0 if the inputs can derive an account account, ot func init() { accountCmd.AddCommand(accountDeriveCmd) accountFlags(accountDeriveCmd) - accountDeriveCmd.Flags().String("mnemonic", "", "mnemonic from which to derive the HD seed") - accountDeriveCmd.Flags().String("path", "", "path from which to derive the account") accountDeriveCmd.Flags().Bool("show-private-key", false, "show private key for derived account") accountDeriveCmd.Flags().Bool("show-withdrawal-credentials", false, "show withdrawal credentials for derived account") } func accountDeriveBindings() { - if err := viper.BindPFlag("mnemonic", accountDeriveCmd.Flags().Lookup("mnemonic")); err != nil { - panic(err) - } - if err := viper.BindPFlag("path", accountDeriveCmd.Flags().Lookup("path")); err != nil { - panic(err) - } if err := viper.BindPFlag("show-private-key", accountDeriveCmd.Flags().Lookup("show-private-key")); err != nil { panic(err) } diff --git a/cmd/block/info/output.go b/cmd/block/info/output.go index f550862..0c69ddd 100644 --- a/cmd/block/info/output.go +++ b/cmd/block/info/output.go @@ -296,7 +296,7 @@ func outputBellatrixBlockText(ctx context.Context, data *dataOut, signedBlock *b bodyRoot, signedBlock.Message.ParentRoot, signedBlock.Message.StateRoot, - signedBlock.Message.Body.Graffiti, + signedBlock.Message.Body.Graffiti[:], data.genesisTime, data.slotDuration, data.slotsPerEpoch) @@ -386,7 +386,7 @@ func outputAltairBlockText(ctx context.Context, data *dataOut, signedBlock *alta bodyRoot, signedBlock.Message.ParentRoot, signedBlock.Message.StateRoot, - signedBlock.Message.Body.Graffiti, + signedBlock.Message.Body.Graffiti[:], data.genesisTime, data.slotDuration, data.slotsPerEpoch) @@ -469,7 +469,7 @@ func outputPhase0BlockText(ctx context.Context, data *dataOut, signedBlock *phas bodyRoot, signedBlock.Message.ParentRoot, signedBlock.Message.StateRoot, - signedBlock.Message.Body.Graffiti, + signedBlock.Message.Body.Graffiti[:], data.genesisTime, data.slotDuration, data.slotsPerEpoch) diff --git a/cmd/chaininfo.go b/cmd/chaininfo.go index e2dbabd..b93d540 100644 --- a/cmd/chaininfo.go +++ b/cmd/chaininfo.go @@ -1,4 +1,4 @@ -// Copyright © 2020 Weald Technology Trading +// Copyright © 2020, 2022 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 @@ -53,6 +53,11 @@ In quiet mode this will return 0 if the chain information can be obtained, other os.Exit(_exitSuccess) } + if viper.GetBool("prepare-offline") { + fmt.Printf("Add the following to your command to run it offline:\n --offline --genesis-validators=root=%#x --fork-version=%#x\n", genesis.GenesisValidatorsRoot, fork.CurrentVersion) + os.Exit(_exitSuccess) + } + if genesis.GenesisTime.Unix() == 0 { fmt.Println("Genesis time: undefined") } else { @@ -84,4 +89,11 @@ In quiet mode this will return 0 if the chain information can be obtained, other func init() { chainCmd.AddCommand(chainInfoCmd) chainFlags(chainInfoCmd) + chainInfoCmd.Flags().Bool("prepare-offline", false, "Provide information useful for offline commands") +} + +func chainInfoBindings() { + if err := viper.BindPFlag("prepare-offline", chainInfoCmd.Flags().Lookup("prepare-offline")); err != nil { + panic(err) + } } diff --git a/cmd/root.go b/cmd/root.go index bb5b8a6..0efffbc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -96,6 +96,8 @@ func includeCommandBindings(cmd *cobra.Command) { blockInfoBindings() case "chain/eth1votes": chainEth1VotesBindings() + case "chain/info": + chainInfoBindings() case "chain/queues": chainQueuesBindings() case "chain/time": @@ -118,6 +120,8 @@ func includeCommandBindings(cmd *cobra.Command) { synccommitteeMembersBindings() case "validator/credentials/get": validatorCredentialsGetBindings() + case "validator/credentials/set": + validatorCredentialsSetBindings() case "validator/depositdata": validatorDepositdataBindings() case "validator/duties": @@ -169,10 +173,26 @@ func init() { if err := viper.BindPFlag("store", RootCmd.PersistentFlags().Lookup("store")); err != nil { panic(err) } - RootCmd.PersistentFlags().String("account", "", "Account name (in format \"wallet/account\")") + RootCmd.PersistentFlags().String("account", "", `Account name (in format "/")`) if err := viper.BindPFlag("account", RootCmd.PersistentFlags().Lookup("account")); err != nil { panic(err) } + RootCmd.PersistentFlags().String("mnemonic", "", "Mnemonic to provide access to an account") + if err := viper.BindPFlag("mnemonic", RootCmd.PersistentFlags().Lookup("mnemonic")); err != nil { + panic(err) + } + RootCmd.PersistentFlags().String("path", "", "Hierarchical derivation path used with mnemonic to provide access to an account") + if err := viper.BindPFlag("path", RootCmd.PersistentFlags().Lookup("path")); err != nil { + panic(err) + } + RootCmd.PersistentFlags().String("private-key", "", "Private key to provide access to an account") + if err := viper.BindPFlag("private-key", RootCmd.PersistentFlags().Lookup("private-key")); err != nil { + panic(err) + } + RootCmd.PersistentFlags().String("public-key", "", "public key to provide access to an account") + if err := viper.BindPFlag("public-key", RootCmd.PersistentFlags().Lookup("public-key")); err != nil { + panic(err) + } RootCmd.PersistentFlags().String("basedir", "", "Base directory for filesystem wallets") if err := viper.BindPFlag("basedir", RootCmd.PersistentFlags().Lookup("basedir")); err != nil { panic(err) diff --git a/cmd/slot/time/output_internal_test.go b/cmd/slot/time/output_internal_test.go index 52a0d7f..a8ddb04 100644 --- a/cmd/slot/time/output_internal_test.go +++ b/cmd/slot/time/output_internal_test.go @@ -37,7 +37,7 @@ func TestOutput(t *testing.T) { dataOut: &dataOut{ startTime: time.Unix(1606824023, 0), }, - res: "2020-12-01 12:00:23 +0000 GMT", + res: "2020-12-01 12:00:23 +0000 UTC", }, { name: "Verbose", @@ -46,7 +46,7 @@ func TestOutput(t *testing.T) { endTime: time.Unix(1606824035, 0), verbose: true, }, - res: "2020-12-01 12:00:23 +0000 GMT - 2020-12-01 12:00:35 +0000 GMT", + res: "2020-12-01 12:00:23 +0000 UTC - 2020-12-01 12:00:35 +0000 UTC", }, } diff --git a/cmd/validator/credentials/get/command.go b/cmd/validator/credentials/get/command.go index 2c6784d..5ba50df 100644 --- a/cmd/validator/credentials/get/command.go +++ b/cmd/validator/credentials/get/command.go @@ -29,9 +29,7 @@ type command struct { debug bool // Input. - account string - index string - pubKey string + validator string // Beacon node connection. timeout time.Duration @@ -43,7 +41,7 @@ type command struct { validatorsProvider eth2client.ValidatorsProvider // Output. - validator *apiv1.Validator + validatorInfo *apiv1.Validator } func newCommand(ctx context.Context) (*command, error) { @@ -62,25 +60,10 @@ func newCommand(ctx context.Context) (*command, error) { c.connection = viper.GetString("connection") c.allowInsecureConnections = viper.GetBool("allow-insecure-connections") - c.account = viper.GetString("account") - c.index = viper.GetString("index") - c.pubKey = viper.GetString("pubkey") - nonNil := 0 - if c.account != "" { - nonNil++ - } - if c.index != "" { - nonNil++ - } - if c.pubKey != "" { - nonNil++ - } - if nonNil == 0 { - return nil, errors.New("one of account, index or pubkey required") - } - if nonNil > 1 { - return nil, errors.New("only one of account, index and pubkey allowed") + if viper.GetString("validator") == "" { + return nil, errors.New("validator is required") } + c.validator = viper.GetString("validator") return c, nil } diff --git a/cmd/validator/credentials/get/output.go b/cmd/validator/credentials/get/output.go index 9a69ea5..d1ac4bd 100644 --- a/cmd/validator/credentials/get/output.go +++ b/cmd/validator/credentials/get/output.go @@ -17,6 +17,8 @@ import ( "context" "fmt" "strings" + + ethutil "github.com/wealdtech/go-eth2-util" ) func (c *command) output(ctx context.Context) (string, error) { @@ -26,19 +28,38 @@ func (c *command) output(ctx context.Context) (string, error) { builder := strings.Builder{} - switch c.validator.Validator.WithdrawalCredentials[0] { + switch c.validatorInfo.Validator.WithdrawalCredentials[0] { case 0: builder.WriteString("BLS credentials: ") - builder.WriteString(fmt.Sprintf("%#x", c.validator.Validator.WithdrawalCredentials)) + builder.WriteString(fmt.Sprintf("%#x", c.validatorInfo.Validator.WithdrawalCredentials)) case 1: builder.WriteString("Ethereum execution address: ") - builder.WriteString(fmt.Sprintf("%#x", c.validator.Validator.WithdrawalCredentials[12:])) + builder.WriteString(addressBytesToEIP55(c.validatorInfo.Validator.WithdrawalCredentials[12:])) if c.verbose { builder.WriteString("\n") builder.WriteString("Withdrawal credentials: ") - builder.WriteString(fmt.Sprintf("%#x", c.validator.Validator.WithdrawalCredentials)) + builder.WriteString(fmt.Sprintf("%#x", c.validatorInfo.Validator.WithdrawalCredentials)) } } return builder.String(), nil } + +// addressBytesToEIP55 converts a byte array in to an EIP-55 string format. +func addressBytesToEIP55(address []byte) string { + bytes := []byte(fmt.Sprintf("%x", address)) + hash := ethutil.Keccak256(bytes) + for i := 0; i < len(bytes); i++ { + hashByte := hash[i/2] + if i%2 == 0 { + hashByte >>= 4 + } else { + hashByte &= 0xf + } + if bytes[i] > '9' && hashByte > 7 { + bytes[i] -= 32 + } + } + + return fmt.Sprintf("0x%s", string(bytes)) +} diff --git a/cmd/validator/credentials/get/process.go b/cmd/validator/credentials/get/process.go index 1c38527..4706484 100644 --- a/cmd/validator/credentials/get/process.go +++ b/cmd/validator/credentials/get/process.go @@ -65,17 +65,7 @@ func (c *command) setup(ctx context.Context) error { func (c *command) fetchValidator(ctx context.Context) error { var err error - switch { - case c.account != "": - c.validator, err = util.ParseValidator(ctx, c.validatorsProvider, c.account, "head") - case c.index != "": - c.validator, err = util.ParseValidator(ctx, c.validatorsProvider, c.index, "head") - case c.pubKey != "": - c.validator, err = util.ParseValidator(ctx, c.validatorsProvider, c.pubKey, "head") - default: - return errors.New("account, index or public key must be supplied") - } - + c.validatorInfo, err = util.ParseValidator(ctx, c.validatorsProvider, c.validator, "head") if err != nil { return errors.Wrap(err, "failed to obtain validator information") } diff --git a/cmd/validator/credentials/set/command.go b/cmd/validator/credentials/set/command.go new file mode 100644 index 0000000..7be9b37 --- /dev/null +++ b/cmd/validator/credentials/set/command.go @@ -0,0 +1,116 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "context" + "time" + + consensusclient "github.com/attestantio/go-eth2-client" + apiv1 "github.com/attestantio/go-eth2-client/api/v1" + capella "github.com/attestantio/go-eth2-client/spec/capella" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/pkg/errors" + "github.com/spf13/viper" + "github.com/wealdtech/ethdo/services/chaintime" + "github.com/wealdtech/ethdo/util" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" +) + +type command struct { + quiet bool + verbose bool + debug bool + offline bool + json bool + + // Input. + account string + passphrases []string + mnemonic string + path string + privateKey string + validator string + withdrawalAddress string + signedOperation string + forkVersion string + genesisValidatorsRoot string + + // Beacon node connection. + timeout time.Duration + connection string + allowInsecureConnections bool + + // Processing. + consensusClient consensusclient.Service + chainTime chaintime.Service + withdrawalAccount e2wtypes.Account + validatorInfo *apiv1.Validator + domain phase0.Domain + op *capella.BLSToExecutionChange + + // Output. + signedOp *capella.SignedBLSToExecutionChange +} + +func newCommand(ctx context.Context) (*command, error) { + c := &command{ + quiet: viper.GetBool("quiet"), + verbose: viper.GetBool("verbose"), + debug: viper.GetBool("debug"), + offline: viper.GetBool("offline"), + json: viper.GetBool("json"), + } + + // Timeout. + if viper.GetDuration("timeout") == 0 { + return nil, errors.New("timeout is required") + } + c.timeout = viper.GetDuration("timeout") + + c.connection = viper.GetString("connection") + c.allowInsecureConnections = viper.GetBool("allow-insecure-connections") + + c.account = viper.GetString("account") + c.passphrases = util.GetPassphrases() + c.mnemonic = viper.GetString("mnemonic") + c.path = viper.GetString("path") + c.privateKey = viper.GetString("private-key") + + if c.account == "" && c.mnemonic == "" && c.privateKey == "" { + return nil, errors.New("one of account, mnemonic or private key required") + } + + if c.account != "" && len(c.passphrases) == 0 { + return nil, errors.New("passphrase required with account") + } + + if c.mnemonic != "" && c.path == "" { + return nil, errors.New("path required with mnemonic") + } + + if viper.GetString("validator") == "" { + return nil, errors.New("validator is required") + } + c.validator = viper.GetString("validator") + + c.withdrawalAddress = viper.GetString("withdrawal-address") + + c.signedOperation = viper.GetString("signed-operation") + + c.forkVersion = viper.GetString("fork-version") + c.genesisValidatorsRoot = viper.GetString("genesis-validators-root") + + return c, nil +} diff --git a/cmd/validator/credentials/set/command_internal_test.go b/cmd/validator/credentials/set/command_internal_test.go new file mode 100644 index 0000000..0beba2a --- /dev/null +++ b/cmd/validator/credentials/set/command_internal_test.go @@ -0,0 +1,83 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "context" + "os" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/require" +) + +func TestInput(t *testing.T) { + if os.Getenv("ETHDO_TEST_CONNECTION") == "" { + t.Skip("ETHDO_TEST_CONNECTION not configured; cannot run tests") + } + + tests := []struct { + name string + vars map[string]interface{} + err string + }{ + { + name: "TimeoutMissing", + vars: map[string]interface{}{}, + err: "timeout is required", + }, + { + name: "NoValidatorInfo", + vars: map[string]interface{}{ + "timeout": "5s", + "connection": os.Getenv("ETHDO_TEST_CONNECTION"), + }, + err: "one of account, index or pubkey required", + }, + { + name: "MultipleValidatorInfo", + vars: map[string]interface{}{ + "timeout": "5s", + "connection": os.Getenv("ETHDO_TEST_CONNECTION"), + "index": "1", + "pubkey": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + }, + err: "only one of account, index and pubkey allowed", + }, + { + name: "Good", + vars: map[string]interface{}{ + "timeout": "5s", + "connection": os.Getenv("ETHDO_TEST_CONNECTION"), + "index": "1", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + viper.Reset() + + for k, v := range test.vars { + viper.Set(k, v) + } + _, err := newCommand(context.Background()) + if test.err != "" { + require.EqualError(t, err, test.err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/cmd/validator/credentials/set/output.go b/cmd/validator/credentials/set/output.go new file mode 100644 index 0000000..4a367f5 --- /dev/null +++ b/cmd/validator/credentials/set/output.go @@ -0,0 +1,37 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "context" + "encoding/json" + + "github.com/pkg/errors" +) + +func (c *command) output(ctx context.Context) (string, error) { + if c.quiet { + return "", nil + } + + if c.json || c.offline { + data, err := json.Marshal(c.signedOp) + if err != nil { + return "", errors.Wrap(err, "failed to marshal signed operation") + } + return string(data), nil + } + + return "", nil +} diff --git a/cmd/validator/credentials/set/process.go b/cmd/validator/credentials/set/process.go new file mode 100644 index 0000000..a16ef5f --- /dev/null +++ b/cmd/validator/credentials/set/process.go @@ -0,0 +1,349 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "strconv" + "strings" + + consensusclient "github.com/attestantio/go-eth2-client" + "github.com/attestantio/go-eth2-client/spec/bellatrix" + capella "github.com/attestantio/go-eth2-client/spec/capella" + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/pkg/errors" + standardchaintime "github.com/wealdtech/ethdo/services/chaintime/standard" + "github.com/wealdtech/ethdo/signing" + "github.com/wealdtech/ethdo/util" + ethutil "github.com/wealdtech/go-eth2-util" +) + +func (c *command) process(ctx context.Context) error { + if err := c.setup(ctx); err != nil { + return err + } + + if err := c.obtainOp(ctx); err != nil { + return err + } + + if c.json || c.offline { + // Want JSON output, or cannot broadcast. + return nil + } + + if validated, reason := c.validateOp(ctx); !validated { + return fmt.Errorf("operation failed validation: %s", reason) + } + + return c.broadcastOp(ctx) +} + +func (c *command) obtainOp(ctx context.Context) error { + // See if we have been given an op. + if c.signedOperation != "" { + // Input could be JSON or a path to JSON. + switch { + case strings.HasPrefix(c.signedOperation, "{"): + // Looks like JSON, nothing to do. + default: + // Assume it's a path to JSON + data, err := os.ReadFile(c.signedOperation) + if err != nil { + return errors.Wrap(err, "failed to read signed operation file") + } + c.signedOperation = string(data) + } + // Unmarshal it to confirm it is valid. + signedOp := &capella.SignedBLSToExecutionChange{} + if err := json.Unmarshal([]byte(c.signedOperation), signedOp); err != nil { + return err + } + return nil + } + + // Need to create a new op. + if err := c.fetchAccount(ctx); err != nil { + return err + } + pubkey, err := util.BestPublicKey(c.withdrawalAccount) + if err != nil { + return err + } + blsPubkey := phase0.BLSPubKey{} + copy(blsPubkey[:], pubkey.Marshal()) + + withdrawalAddressBytes, err := hex.DecodeString(strings.TrimPrefix(c.withdrawalAddress, "0x")) + if err != nil { + return errors.Wrap(err, "failed to obtain execution address") + } + if len(withdrawalAddressBytes) != bellatrix.ExecutionAddressLength { + return errors.New("withdrawal address must be exactly 20 bytes in length") + } + // Ensure the address is properly checksummed. + checksummedAddress := addressBytesToEIP55(withdrawalAddressBytes) + if checksummedAddress != c.withdrawalAddress { + return fmt.Errorf("withdrawal address checksum does not match (expected %s)", checksummedAddress) + } + withdrawalAddress := bellatrix.ExecutionAddress{} + copy(withdrawalAddress[:], withdrawalAddressBytes) + + if c.offline { + err = c.obtainOpOffline(ctx, blsPubkey, withdrawalAddress) + } else { + err = c.obtainOpOnline(ctx, blsPubkey, withdrawalAddress) + } + if err != nil { + return errors.Wrap(err, "failed to obtain operation") + } + + root, err := c.op.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "failed to generate root for credentials change operation") + } + + // Sign the operation. + signature, err := signing.SignRoot(ctx, c.withdrawalAccount, nil, root, c.domain) + if err != nil { + return errors.Wrap(err, "failed to sign credentials change operation") + } + + c.signedOp = &capella.SignedBLSToExecutionChange{ + Message: c.op, + Signature: signature, + } + + return nil +} + +func (c *command) obtainOpOffline(ctx context.Context, + pubkey phase0.BLSPubKey, + withdrawalAddress bellatrix.ExecutionAddress, +) error { + if c.validator == "" { + return errors.New("validator index must be supplied when offline") + } + validatorIndex, err := strconv.ParseUint(c.validator, 10, 64) + if err != nil { + return errors.Wrap(err, "validator must be an index when offline") + } + + if c.forkVersion == "" { + return errors.New("fork version must be supplied when offline") + } + forkVersionBytes, err := hex.DecodeString(strings.TrimPrefix(c.forkVersion, "0x")) + if err != nil { + return errors.Wrap(err, "fork version invalid") + } + if len(forkVersionBytes) != phase0.ForkVersionLength { + return errors.New("fork version incorrect length") + } + forkVersion := phase0.Version{} + copy(forkVersion[:], forkVersionBytes) + + if c.genesisValidatorsRoot == "" { + return errors.New("genesis validators root must be supplied when offline") + } + genesisValidatorsRootBytes, err := hex.DecodeString(strings.TrimPrefix(c.genesisValidatorsRoot, "0x")) + if err != nil { + return errors.Wrap(err, "genesis validators root invalid") + } + if len(genesisValidatorsRootBytes) != phase0.RootLength { + return errors.New("genesis validators root incorrect length") + } + genesisValidatorsRoot := phase0.Root{} + copy(genesisValidatorsRoot[:], genesisValidatorsRootBytes) + + // Generate the domain. + forkData := &phase0.ForkData{ + CurrentVersion: forkVersion, + GenesisValidatorsRoot: genesisValidatorsRoot, + } + root, err := forkData.HashTreeRoot() + if err != nil { + return errors.Wrap(err, "failed to calculate signature domain") + } + c.domain = phase0.Domain{} + copy(c.domain[:], []byte{0x0a, 0x00, 0x00, 0x00}) // DOMAIN_BLS_TO_EXECUTION_CHANGE. + copy(c.domain[4:], root[:]) + + // Generate the change operation. + c.op = &capella.BLSToExecutionChange{ + ValidatorIndex: phase0.ValidatorIndex(validatorIndex), + FromBLSPubkey: pubkey, + ToExecutionAddress: withdrawalAddress, + } + + return nil +} + +func (c *command) obtainOpOnline(ctx context.Context, + pubkey phase0.BLSPubKey, + withdrawalAddress bellatrix.ExecutionAddress, +) error { + // Ensure the validator is correct and suitable. + if err := c.fetchChainInfo(ctx); err != nil { + return err + } + // TODO Move to broadcast. + if c.validatorInfo.Validator.WithdrawalCredentials[0] != 0x00 { + return errors.New("validator withdrawal credentials are not using BLS; cannot change") + } + { + // TODO remove. + x, _ := json.Marshal(c.validatorInfo) + fmt.Printf("%s\n", string(x)) + } + + // Generate the change operation. + c.op = &capella.BLSToExecutionChange{ + ValidatorIndex: c.validatorInfo.Index, + FromBLSPubkey: pubkey, + ToExecutionAddress: withdrawalAddress, + } + + return nil +} + +func (c *command) validateOp(ctx context.Context, +) ( + bool, + string, +) { + // Confirm that the public key hashes to the existing withdrawal credentials (if available). + if c.validatorInfo != nil { + pubkey, err := util.BestPublicKey(c.withdrawalAccount) + if err != nil { + return false, "failed to obtain a public key for the withdrawal account" + } + blsHash := ethutil.Keccak256(pubkey.Marshal()) + // TODO remove. + fmt.Printf("BLS pub key is %#x, hash is %#x\n", pubkey, blsHash) + if !bytes.Equal(blsHash[1:], c.validatorInfo.Validator.WithdrawalCredentials[:]) { + return false, "validator withdrawal credentials do not match current withdrawal credentials" + } + } + + return true, "" +} + +func (c *command) broadcastOp(ctx context.Context) error { + // Broadcast the operation. + return c.consensusClient.(consensusclient.BLSToExecutionChangeSubmitter).SubmitBLSToExecutionChange(ctx, c.signedOp) +} + +func (c *command) setup(ctx context.Context) error { + if c.offline { + return nil + } + + var err error + + // Connect to the consensus node. + c.consensusClient, err = util.ConnectToBeaconNode(ctx, c.connection, c.timeout, c.allowInsecureConnections) + if err != nil { + return errors.Wrap(err, "failed to connect to consensus node") + } + + // Set up chaintime. + c.chainTime, err = standardchaintime.New(ctx, + standardchaintime.WithGenesisTimeProvider(c.consensusClient.(consensusclient.GenesisTimeProvider)), + standardchaintime.WithForkScheduleProvider(c.consensusClient.(consensusclient.ForkScheduleProvider)), + standardchaintime.WithSpecProvider(c.consensusClient.(consensusclient.SpecProvider)), + ) + if err != nil { + return errors.Wrap(err, "failed to create chaintime service") + } + + return nil +} + +func (c *command) fetchChainInfo(ctx context.Context) error { + var err error + + // Obtain the validators provider. + validatorsProvider, isProvider := c.consensusClient.(consensusclient.ValidatorsProvider) + if !isProvider { + return errors.New("consensus node does not provide validator information") + } + + c.validatorInfo, err = util.ParseValidator(ctx, validatorsProvider, c.validator, "head") + if err != nil { + return errors.Wrap(err, "failed to obtain validator") + } + + epoch := c.chainTime.CurrentEpoch() + + // Obtain the domain type. + spec, err := c.consensusClient.(consensusclient.SpecProvider).Spec(ctx) + if err != nil { + return errors.Wrap(err, "failed to obtain spec") + } + domainType, exists := spec["DOMAIN_BLS_TO_EXECUTION_CHANGE"].(phase0.DomainType) + if !exists { + return errors.New("failed to obtain DOMAIN_BLS_TO_EXECUTION_CHANGE") + } + + domainProvider, isProvider := c.consensusClient.(consensusclient.DomainProvider) + if !isProvider { + return errors.New("consensus node does not provide domain information") + } + c.domain, err = domainProvider.Domain(ctx, domainType, epoch) + if err != nil { + return errors.Wrap(err, "failed to obtain domain") + } + + return nil +} + +func (c *command) fetchAccount(ctx context.Context) error { + var err error + + switch { + case c.account != "": + c.withdrawalAccount, err = util.ParseAccount(ctx, c.account, c.passphrases, true) + case c.mnemonic != "": + c.withdrawalAccount, err = util.ParseAccount(ctx, c.mnemonic, []string{c.path}, true) + case c.privateKey != "": + c.withdrawalAccount, err = util.ParseAccount(ctx, c.privateKey, nil, true) + default: + err = errors.New("account, mnemonic or private key must be supplied") + } + + return err +} + +// addressBytesToEIP55 converts a byte array in to an EIP-55 string format. +func addressBytesToEIP55(address []byte) string { + bytes := []byte(fmt.Sprintf("%x", address)) + hash := ethutil.Keccak256(bytes) + for i := 0; i < len(bytes); i++ { + hashByte := hash[i/2] + if i%2 == 0 { + hashByte >>= 4 + } else { + hashByte &= 0xf + } + if bytes[i] > '9' && hashByte > 7 { + bytes[i] -= 32 + } + } + + return fmt.Sprintf("0x%s", string(bytes)) +} diff --git a/cmd/validator/credentials/set/run.go b/cmd/validator/credentials/set/run.go new file mode 100644 index 0000000..33417d2 --- /dev/null +++ b/cmd/validator/credentials/set/run.go @@ -0,0 +1,50 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "context" + + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// Run runs the command. +func Run(cmd *cobra.Command) (string, error) { + ctx := context.Background() + + c, err := newCommand(ctx) + if err != nil { + return "", errors.Wrap(err, "failed to set up command") + } + + // Further errors do not need a usage report. + cmd.SilenceUsage = true + + if err := c.process(ctx); err != nil { + return "", errors.Wrap(err, "failed to process") + } + + if viper.GetBool("quiet") { + return "", nil + } + + results, err := c.output(ctx) + if err != nil { + return "", errors.Wrap(err, "failed to obtain output") + } + + return results, nil +} diff --git a/cmd/validatorcredentialsget.go b/cmd/validatorcredentialsget.go index 9556d2b..7cd0344 100644 --- a/cmd/validatorcredentialsget.go +++ b/cmd/validatorcredentialsget.go @@ -26,7 +26,7 @@ var validatorCredentialsGetCmd = &cobra.Command{ Short: "Obtain withdrawal credentials for an Ethereum consensus validator", Long: `Obtain withdrawal credentials for an Ethereum consensus validator. For example: - ethdo validator credentials get --account=primary/validator + ethdo validator credentials get --validator=primary/validator In quiet mode this will return 0 if the validator exists, otherwise 1.`, RunE: func(cmd *cobra.Command, args []string) error { @@ -47,19 +47,11 @@ In quiet mode this will return 0 if the validator exists, otherwise 1.`, func init() { validatorCredentialsCmd.AddCommand(validatorCredentialsGetCmd) validatorCredentialsFlags(validatorCredentialsGetCmd) - validatorCredentialsGetCmd.Flags().String("account", "", "Account for which to fetch validator credentials") - validatorCredentialsGetCmd.Flags().String("index", "", "Validator index for which to fetch validator credentials") - validatorCredentialsGetCmd.Flags().String("pubkey", "", "Validator public key for which to fetch validator credentials") + validatorCredentialsGetCmd.Flags().String("validator", "", "Validator for which to get validator credentials") } func validatorCredentialsGetBindings() { - if err := viper.BindPFlag("account", validatorCredentialsGetCmd.Flags().Lookup("account")); err != nil { - panic(err) - } - if err := viper.BindPFlag("index", validatorCredentialsGetCmd.Flags().Lookup("index")); err != nil { - panic(err) - } - if err := viper.BindPFlag("pubkey", validatorCredentialsGetCmd.Flags().Lookup("pubkey")); err != nil { + if err := viper.BindPFlag("validator", validatorCredentialsGetCmd.Flags().Lookup("validator")); err != nil { panic(err) } } diff --git a/cmd/validatorcredentialsset.go b/cmd/validatorcredentialsset.go new file mode 100644 index 0000000..e72beb4 --- /dev/null +++ b/cmd/validatorcredentialsset.go @@ -0,0 +1,87 @@ +// Copyright © 2022 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" + validatorcredentialsset "github.com/wealdtech/ethdo/cmd/validator/credentials/set" +) + +var validatorCredentialsSetCmd = &cobra.Command{ + Use: "set", + Short: "Set withdrawal credentials for an Ethereum consensus validator", + Long: `Set withdrawal credentials for an Ethereum consensus validator. For example: + + ethdo validator credentials set --validator=primary/validator --execution-address=0x00...13 --private-key=0x00...1f + +The existing account can be specified in one of three ways: + + - private key using --private-key + - account and passphrase using --account and --passphrase + - mnemonic and path using --mnemonic and --path + +In quiet mode this will return 0 if the credentials operation has been generated (and successfully broadcast if online), otherwise 1.`, + RunE: func(cmd *cobra.Command, args []string) error { + res, err := validatorcredentialsset.Run(cmd) + if err != nil { + return err + } + if viper.GetBool("quiet") { + return nil + } + if res != "" { + fmt.Println(res) + } + return nil + }, +} + +func init() { + validatorCredentialsCmd.AddCommand(validatorCredentialsSetCmd) + validatorCredentialsFlags(validatorCredentialsSetCmd) + validatorCredentialsSetCmd.Flags().String("validator", "", "Validator for which to set validator credentials") + validatorCredentialsSetCmd.Flags().String("withdrawal-address", "", "Execution address to which to direct withdrawals") + validatorCredentialsSetCmd.Flags().String("signed-operation", "", "Use pre-defined JSON signed operation as created by --json to transmit the credentials change operation") + validatorCredentialsSetCmd.Flags().Bool("json", false, "Generate JSON data containing a signed operation rather than broadcast it to the network (implied when offline)") + validatorCredentialsSetCmd.Flags().Bool("offline", false, "Do not attempt to connect to a beacon node to obtain information for the operation") + validatorCredentialsSetCmd.Flags().String("fork-version", "", "Fork version to use for signing (offline only)") + validatorCredentialsSetCmd.Flags().String("genesis-validators-root", "", "Genesis validators root to use for signing (offline only)") +} + +func validatorCredentialsSetBindings() { + if err := viper.BindPFlag("validator", validatorCredentialsSetCmd.Flags().Lookup("validator")); err != nil { + panic(err) + } + if err := viper.BindPFlag("signed-operation", validatorCredentialsSetCmd.Flags().Lookup("signed-operation")); err != nil { + panic(err) + } + if err := viper.BindPFlag("withdrawal-address", validatorCredentialsSetCmd.Flags().Lookup("withdrawal-address")); err != nil { + panic(err) + } + if err := viper.BindPFlag("json", validatorCredentialsSetCmd.Flags().Lookup("json")); err != nil { + panic(err) + } + if err := viper.BindPFlag("offline", validatorCredentialsSetCmd.Flags().Lookup("offline")); err != nil { + panic(err) + } + if err := viper.BindPFlag("fork-version", validatorCredentialsSetCmd.Flags().Lookup("fork-version")); err != nil { + panic(err) + } + if err := viper.BindPFlag("genesis-validators-root", validatorCredentialsSetCmd.Flags().Lookup("genesis-validators-root")); err != nil { + panic(err) + } +} diff --git a/cmd/validatorinfo.go b/cmd/validatorinfo.go index d89b8ad..97970bf 100644 --- a/cmd/validatorinfo.go +++ b/cmd/validatorinfo.go @@ -1,4 +1,4 @@ -// Copyright © 2020, 2021 Weald Technology Trading +// Copyright © 2020 - 2022 Weald Technology Trading // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -16,7 +16,6 @@ package cmd import ( "bytes" "context" - "encoding/hex" "encoding/json" "fmt" "io/ioutil" @@ -41,7 +40,7 @@ var validatorInfoCmd = &cobra.Command{ Short: "Obtain information about a validator", Long: `Obtain information about validator. For example: - ethdo validator info --account=primary/validator + ethdo validator info --validator=primary/validator In quiet mode this will return 0 if the validator information can be obtained, otherwise 1.`, Run: func(cmd *cobra.Command, args []string) { @@ -54,32 +53,20 @@ In quiet mode this will return 0 if the validator information can be obtained, o ) errCheck(err, "Failed to connect to Ethereum 2 beacon node") - account, err := validatorInfoAccount(ctx, eth2Client) - errCheck(err, "Failed to obtain validator account") - - pubKeys := make([]spec.BLSPubKey, 1) - 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) - errCheck(err, "Failed to obtain validator information") - if len(validators) == 0 { - fmt.Println("Validator not known by beacon node") - os.Exit(_exitSuccess) + if viper.GetString("validator") == "" { + fmt.Println("validator is required") + os.Exit(_exitFailure) } - var validator *api.Validator - for _, v := range validators { - validator = v - } + validator, err := util.ParseValidator(ctx, eth2Client.(eth2client.ValidatorsProvider), viper.GetString("validator"), "head") if verbose { network, err := util.Network(ctx, eth2Client) errCheck(err, "Failed to obtain network") outputIf(debug, fmt.Sprintf("Network is %s", network)) - pubKey, err := util.BestPublicKey(account) + pubKey, err := validator.PubKey(ctx) if err == nil { - deposits, totalDeposited, err := graphData(network, pubKey.Marshal()) + deposits, totalDeposited, err := graphData(network, pubKey[:]) if err == nil && deposits > 0 { fmt.Printf("Number of deposits: %d\n", deposits) fmt.Printf("Total deposited: %s\n", string2eth.GWeiToString(uint64(totalDeposited), true)) @@ -124,50 +111,7 @@ In quiet mode this will return 0 if the validator information can be obtained, o // validatorInfoAccount obtains the account for the validator info command. func validatorInfoAccount(ctx context.Context, eth2Client eth2client.Service) (e2wtypes.Account, error) { - var account e2wtypes.Account - var err error - switch { - case viper.GetString("account") != "": - ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("timeout")) - defer cancel() - _, account, err = walletAndAccountFromPath(ctx, viper.GetString("account")) - if err != nil { - return nil, errors.Wrap(err, "failed to obtain account") - } - case viper.GetString("pubkey") != "": - pubKeyBytes, err := hex.DecodeString(strings.TrimPrefix(viper.GetString("pubkey"), "0x")) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to decode public key %s", viper.GetString("pubkey"))) - } - account, err = util.NewScratchAccount(nil, pubKeyBytes) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", viper.GetString("pubkey"))) - } - case viper.GetInt64("index") != -1: - validatorsProvider, isValidatorsProvider := eth2Client.(eth2client.ValidatorsProvider) - if !isValidatorsProvider { - return nil, errors.New("client does not provide validator information") - } - index := spec.ValidatorIndex(viper.GetInt64("index")) - validators, err := validatorsProvider.Validators(ctx, "head", []spec.ValidatorIndex{ - index, - }) - if err != nil { - return nil, errors.Wrap(err, "failed to obtain validator information") - } - if len(validators) == 0 { - return nil, errors.New("unknown validator index") - } - pubKeyBytes := make([]byte, 48) - copy(pubKeyBytes, validators[index].Validator.PublicKey[:]) - account, err = util.NewScratchAccount(nil, pubKeyBytes) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("invalid public key %s", viper.GetString("pubkey"))) - } - default: - return nil, errors.New("neither account nor public key supplied") - } - return account, nil + return util.ParseAccount(ctx, viper.GetString("validator"), nil, false) } // graphData returns data from the graph about number and amount of deposits @@ -224,16 +168,12 @@ func graphData(network string, validatorPubKey []byte) (uint64, spec.Gwei, error func init() { validatorCmd.AddCommand(validatorInfoCmd) - validatorInfoCmd.Flags().String("pubkey", "", "Public key for which to obtain status") - validatorInfoCmd.Flags().Int64("index", -1, "Index for which to obtain status") + validatorInfoCmd.Flags().String("validator", "", "Public key for which to obtain status") validatorFlags(validatorInfoCmd) } func validatorInfoBindings() { - if err := viper.BindPFlag("pubkey", validatorInfoCmd.Flags().Lookup("pubkey")); err != nil { - panic(err) - } - if err := viper.BindPFlag("index", validatorInfoCmd.Flags().Lookup("index")); err != nil { + if err := viper.BindPFlag("validator", validatorInfoCmd.Flags().Lookup("validator")); err != nil { panic(err) } } diff --git a/cmd/validatorkeycheck.go b/cmd/validatorkeycheck.go index fccd4a2..928998f 100644 --- a/cmd/validatorkeycheck.go +++ b/cmd/validatorkeycheck.go @@ -50,7 +50,6 @@ func init() { validatorCmd.AddCommand(validatorKeycheckCmd) validatorFlags(validatorKeycheckCmd) validatorKeycheckCmd.Flags().String("withdrawal-credentials", "", "Withdrawal credentials to check (can run offline)") - validatorKeycheckCmd.Flags().String("mnemonic", "", "Mnemonic from which to generate withdrawal credentials") validatorKeycheckCmd.Flags().String("privkey", "", "Private key from which to generate withdrawal credentials") } @@ -58,9 +57,6 @@ func validatorKeycheckBindings() { if err := viper.BindPFlag("withdrawal-credentials", validatorKeycheckCmd.Flags().Lookup("withdrawal-credentials")); err != nil { panic(err) } - if err := viper.BindPFlag("mnemonic", validatorKeycheckCmd.Flags().Lookup("mnemonic")); err != nil { - panic(err) - } if err := viper.BindPFlag("privkey", validatorKeycheckCmd.Flags().Lookup("privkey")); err != nil { panic(err) } diff --git a/cmd/walletcreate.go b/cmd/walletcreate.go index cd1082e..8ed0835 100644 --- a/cmd/walletcreate.go +++ b/cmd/walletcreate.go @@ -45,14 +45,10 @@ func init() { walletCmd.AddCommand(walletCreateCmd) walletFlags(walletCreateCmd) walletCreateCmd.Flags().String("type", "non-deterministic", "Type of wallet to create (non-deterministic or hierarchical deterministic)") - walletCreateCmd.Flags().String("mnemonic", "", "The 24-word mnemonic for a hierarchical deterministic wallet") } func walletCreateBindings() { if err := viper.BindPFlag("type", walletCreateCmd.Flags().Lookup("type")); err != nil { panic(err) } - if err := viper.BindPFlag("mnemonic", walletCreateCmd.Flags().Lookup("mnemonic")); err != nil { - panic(err) - } } diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md new file mode 100644 index 0000000..0711978 --- /dev/null +++ b/docs/changingwithdrawalcredentials.md @@ -0,0 +1,267 @@ +# Changing withdrawal credentials. +When creating a validator it is possible to set is withdrawal credentials to those based upon a BLS private key (known as BLS withdrawal credentials, or "type 0" withdrawal credentials) or based upon an Ethereum execution address (known as execution withdrawal credentials, or "type 1" withdrawal credentials). With the advent of the Capella hard fork, it is possible for rewards accrued on the consensus chain (also known as the beacon chain) to be sent to the execution chain. However, for this to occur the validator's withdrawal credentials must be type 1. Capella also brings a mechanism to change existing type 0 withdrawal credentials to type 1 withdrawal credentials, and this document outlines the process to change withdrawal credentials from type 0 to type 1 so that such rewards can be accessed. + +**Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure you end up with the ability to access the rewards that will be sent to the execution address within the credentials.** + +## Preparing for the process +A number of steps need to be taken to prepare for creating and broadcasting the credentials change operation. + +### Accessing the beacon node +`ethdo` requires access to the beacon node at various points during the operation. `ethdo` will attempt to find a local beacon node automatically, but if not then an explicit connection value will be required. To find out if `ethdo` has access to the beacon node run: + +``` +ethdo node info --verbose +``` + +The result should be something similar to the following: + +``` +Version: teku/v22.9.1/linux-x86_64/-privatebuild-openjdk64bitservervm-java-14 +Syncing: false +``` + +It is important to confirm that the "Syncing" value is "false". If this is "true" it means that the node is currently syncing, and you will need to wait for the process to finish before proceeding. + +If this command instead returns an error you will need to add an explicit connection string. For example, if your beacon node is serving its REST API on port 12345 then you should add `--connection=http://localhost:12345` to all `ethdo` commands in this process, for example: + +```sh +ethdo --connection=http://localhost:12345 node info --verbose +``` + +Note that some beacon nodes may require configuration to serve their REST API. Please refer to the documentation of your specific beacon node to enable this. + +### Validator reference +There are three options to reference a validator: + +- the `ethdo` account of the validator (in format wallet/account) +- the validator's public key (in format 0x...) +- the validator's index (in format 123...) + +Any of these can be passed to the following commands with the `--validator` parameter. You need to ensure that you have this information before starting the process. + +**In the following examples we will use the validator with index 123. Please replace this with the reference to your validator in all commands.** + +### Execution address +The execution address will be the address to which all Ether held by the validator from the consensus chain will be sent. It is important to understand that at time of writing this value cannot be changed, so it is critical that one of the following criteria are met: + +- the private keys for the Ethereum address are known +- the Ethereum address is secured by a hardware wallet +- the Ethereum address is that of a smart contract with the ability to withdraw funds + +The execution address must be supplied in [EIP-55](https://eips.ethereum.org/EIPS/eip-55) format, _i.e._ using mixed case for checksum. An example of a mixed-case Ethereum address is `0x8f0844Fd51E31ff6Bf5baBe21DCcf7328E19Fd9F` + +### Online or offline +It is possible to generate the withdrawal credentials change operation either online or offline. + +In _online_ mode the credentials will be generated on a server that has both access to the internet and access to the private keys of the existing withdrawal credentials. This is the easiest process, however due to it involving private keys on a computer connected to the internet some consider this insecure. + +In _offline_ mode there are two servers: one with access to the internet, and one with access to the private keys. This is the most secure process, however requires additional steps to accomplish. + +It is a personal choice as to if an online or offline method is chosen to generate the credentials change operation. Instructions for both methods are present. + +## The process +### Check your current validator credentials +The first step will be to confirm that the validator can be found on-chain. To do so, run the following command: + +```sh +ethdo validator credentials get --validator=123 +``` + +This should return information similar to the following: + +``` +BLS credentials: 0x00ebf119d469a31ff2a534d176e6d594046a2367f7a36848009f70f3cb9a9dd1 +``` + +This result should start with the phrase "BLS credentials", which means that these credentials must be upgraded to an Ethereum execution address to receive withdrawals. If instead the result starts with the phrase "Ethereum execution address" it means that the credentials are already set to an Ethereum execution address and no further action is necessary (or possible). + + +The next step depends on if you have access to your keys + +### Generate and publish the credentials change operation (online) +The steps for generating and publishing the credentials change operation online depend on the method by which you access your current withdrawal key. + +#### Using a mnemonic +Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. + +- m/12381/3600/_i_/0 is the path to the _i_th withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ +- m/12381/3600/_i_/0/0 is the path to the _i_th validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ + +The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: + +``` +ethdo account derive --mnemonic='abandon ... art' --path='m/12381/3600/0/0/0' +``` + +replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: + +``` +Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726dbfc3c7463884c68a531515aab94c87 +``` + +The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. + +Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: + +``` +ethdo account derive --mnemonic='abandon ... art' --path='m/12381/0/0' --show-withdrawal-credentials +``` + +again replacing the first '0' in the path with the validator number. This will provide an output similar to: + +``` +Public key: 0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db +Withdrawal credentials: 0x008ba1cc4b091b91c1202bba3f508075d6ff565c77e559f0803c0792e0302bf1 +``` + +The displayed withdrawal credentials should match the current withdrawal credentials of your validator (note that these were obtained in an earlier step so you can use the output there to confirm that they match). If not, then do not proceed further and obtain help to understand why there is a mismatch. + +Once you are comfortable that the mnemonic and path provide the correct result you can generate and broadcast the credentials change operation with the following command: + +``` +ethdo validator credentials set --validator=123 --execution-address=0x00...13 --mnemonic='abandon ... art' --path='m/12381/0/0' +``` + +again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. + +#### Using a private key +If you have the private key from which the current withdrawal credentials were derived this can be used to generate and broadcast the credentials change operation with the following command: + +``` +ethdo validator credentials set --validator=123 --execution-address=0x00...13 --private-key=0x3b...9c +``` + +using your own execution address as explained earlier in the guide, and your own private key. + +#### Using an account +If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate and broadcast the credentials change operation with the following command: + +``` +ethdo validator credentials set --validator=123 --execution-address=0x00...13 --account=Wallet/Account --passphrase=secret +``` + +setting the execution address, account and passphrase to your own values. + +### Generate the credentials change operation (offline) +Generating the credentials change operation offline requires information from the online component, so is somewhat more involved than the online process, however does not expose mnemonics, private keys, or passphrases to servers that are connected to the internet. The process is below. + +#### Obtain data required for offline generation. +Generating the credentials change operation requires information that comes from an online beacon node. As such, on your _online_ server you need to run the following command: + +``` +ethdo chain info --prepare-offline +``` + +This will return something similar to the following response: + +``` +Add the following to your command to run it offline: + --offline --genesis-validators=root=0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb --fork-version=0x03001020 +``` + +This information needs to be copied to your offline server to continue. + +#### Generate signed operation +Generating the signed operation offline + +#### Using a mnemonic +Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. + +- m/12381/3600/_i_/0 is the path to the _i_th withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ +- m/12381/3600/_i_/0/0 is the path to the _i_th validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ + +The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: + +``` +ethdo account derive --mnemonic='abandon ... art' --path='m/12381/3600/0/0/0' +``` + +replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: + +``` +Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726dbfc3c7463884c68a531515aab94c87 +``` + +The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. + +Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: + +``` +ethdo account derive --mnemonic='abandon ... art' --path='m/12381/0/0' --show-withdrawal-credentials +``` + +again replacing the first '0' in the path with the validator number. This will provide an output similar to: + +``` +Public key: 0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db +Withdrawal credentials: 0x008ba1cc4b091b91c1202bba3f508075d6ff565c77e559f0803c0792e0302bf1 +``` + +The displayed withdrawal credentials should match the current withdrawal credentials of your validator (note that these were obtained in an earlier step so you can use the output there to confirm that they match). If not, then do not proceed further and obtain help to understand why there is a mismatch. + +Once you are comfortable that the mnemonic and path provide the correct result you can generate the credentials change operation with the following command: + +``` +ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --mnemonic='abandon ... art' --path='m/12381/0/0' +``` + +again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. This will produce output similar to the following: + +``` +{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} + +``` + +#### Using a private key +If you have the private key from which the current withdrawal credentials were derived this can be used to generate the credentials change operation with the following command: + +``` +ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --private-key=0x3bdb...6a9c +``` + +using your own execution address as explained earlier in the guide, and your own private key. This will produce output similar to the following: + +``` +{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} +``` + +#### Using an account +If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate the credentials change operation with the following command: + +``` +ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --account=Wallet/Account --passphrase=secret +``` + +setting the execution address, account and passphrase to your own values. This will produce output similar to the following: + +``` +{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} +``` + +### Broadcasting a previously-generated credentials change operation +An online server can broadcast the result of the previous step. Note that the data does not expose any sensitive information such as private keys, and as such is safe to be accessed by the online server. Broadcasting the operation is a simple case of supplying it to `ethdo`: + +``` +ethdo validator credentials set --signed-operation='{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"}' +``` + +Alternatively, if the operation is stored on a filesystem, for example on a USB device from where it was copied from the offline server, it can be used with: + +``` +ethdo validator credentials set --signed-operation=/path/to/signed/operation +``` + +## Confirming the process has succeeded +The final step is confirming the operation has taken place. To do so, run the following command on an online server: + +```sh +ethdo validator credentials get --validator=123 +``` + +The result should start with the phrase "Ethereum execution address" and display the execution address you chose at the beginning of the process, for example: + +``` +Ethereum execution address: 0x8f0844Fd51E31ff6Bf5baBe21DCcf7328E19Fd9F +``` + +If the result starts with the phrase "BLS credentials" then it may be that the operation has yet to be incorporated on the chain, please wait a few minutes and check again. If this continues to be the case please obtain help to understand why the change operation failed to work. diff --git a/docs/usage.md b/docs/usage.md index b6317fc..200662c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -581,12 +581,10 @@ Validator commands focus on interaction with Ethereum 2 validators. #### `credentials get` `ethdo validator credentials get` provides information about the withdrawal credentials for the provided validator. Options include: - - `account` the account for which to obtain the withdrawal credentials (in format "wallet/account") - - `pubkey` the public key of the validator for which to obtain the withdrawal credentials - - `index` the index of the validator for which to obtain the withdrawal credentials + - `validator` the account, public key or index for which to obtain the withdrawal credentials ```sh -$ ethdo validator credentials get --account=Validators/1 +$ ethdo validator credentials get --validator=Validators/1 ``` #### `depositdata` @@ -622,7 +620,7 @@ $ ethdo validator exit --key=0x01e748d098d3bcb477d636f19d510399ae18205fadf9814ee `ethdo validator info` provides information for a given validator. ```sh -$ ethdo validator info --account=Validators/1 +$ ethdo validator info --validator=Validators/1 Status: Active Balance: 3.203823585 Ether Effective balance: 3.1 Ether @@ -641,7 +639,7 @@ Effective balance: 3.1 Ether Withdrawal credentials: 0x0033ef3cb10b36d0771ffe8a02bc5bfc7e64ea2f398ce77e25bb78989edbee36 ``` -If the validator is not an account it can be queried directly with `--pubkey`. +If the validator is not an account then `--validator` option can be supplied with a validator index or public key. ```sh $ ethdo validator info --pubkey=0x842dd66cfeaeff4397fc7c94f7350d2131ca0c4ad14ff727963be9a1edb4526604970df6010c3da6474a9820fa81642b diff --git a/go.mod b/go.mod index 4bebb8d..4d18003 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,18 @@ module github.com/wealdtech/ethdo go 1.16 require ( - github.com/OneOfOne/xxhash v1.2.5 // indirect - github.com/attestantio/dirk v1.1.0 - github.com/attestantio/go-eth2-client v0.11.0 - github.com/aws/aws-sdk-go v1.42.44 // indirect - github.com/ferranbt/fastssz v0.0.0-20220103083642-bc5fefefa28b + github.com/attestantio/go-eth2-client v0.14.0 + github.com/aws/aws-sdk-go v1.44.111 // indirect + github.com/ferranbt/fastssz v0.1.2 github.com/gofrs/uuid v4.2.0+incompatible + github.com/google/go-cmp v0.5.9 // indirect github.com/google/uuid v1.3.0 github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b - github.com/herumi/bls-eth-go-binary v0.0.0-20220103074059-01b0ca9e9ef7 - github.com/jackc/puddle v1.2.1 // indirect + github.com/herumi/bls-eth-go-binary v1.28.1 + github.com/jackc/puddle v1.3.0 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/klauspost/cpuid/v2 v2.1.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 @@ -20,22 +22,22 @@ require ( github.com/protolambda/zssz v0.1.5 // indirect github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 github.com/prysmaticlabs/go-ssz v0.0.0-20210121151755-f6208871c388 - github.com/rs/zerolog v1.26.1 + github.com/rs/zerolog v1.28.0 github.com/shopspring/decimal v1.3.1 - github.com/spf13/afero v1.8.0 // indirect + github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cobra v1.3.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.10.1 - github.com/stretchr/testify v1.7.0 + github.com/spf13/viper v1.13.0 + github.com/stretchr/testify v1.8.0 github.com/tyler-smith/go-bip39 v1.1.0 github.com/wealdtech/go-bytesutil v1.1.1 github.com/wealdtech/go-ecodec v1.1.2 - github.com/wealdtech/go-eth2-types/v2 v2.6.0 + github.com/wealdtech/go-eth2-types/v2 v2.7.0 github.com/wealdtech/go-eth2-util v1.7.0 github.com/wealdtech/go-eth2-wallet v1.15.0 github.com/wealdtech/go-eth2-wallet-dirk v1.2.0 github.com/wealdtech/go-eth2-wallet-distributed v1.1.4 - github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.2.0 + github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.3.0 github.com/wealdtech/go-eth2-wallet-hd/v2 v2.6.0 github.com/wealdtech/go-eth2-wallet-nd/v2 v2.4.0 github.com/wealdtech/go-eth2-wallet-store-filesystem v1.17.0 @@ -43,9 +45,11 @@ require ( github.com/wealdtech/go-eth2-wallet-store-scratch v1.7.0 github.com/wealdtech/go-eth2-wallet-types/v2 v2.9.0 github.com/wealdtech/go-string2eth v1.2.0 - golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed // indirect + golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b // indirect + golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect golang.org/x/text v0.3.7 - google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect - google.golang.org/grpc v1.44.0 - gopkg.in/ini.v1 v1.66.3 // indirect + golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect + google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 // indirect ) diff --git a/go.sum b/go.sum index f93344d..5734d4e 100644 --- a/go.sum +++ b/go.sum @@ -29,35 +29,156 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= +cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= +cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= +cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= +cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= +cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= +cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= +cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= +cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= +cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= +cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= +cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= +cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= +cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= +cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= +cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= 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= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= +cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= +cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= +cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= +cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= +cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= +cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= +cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= +cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= +cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= +cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= +cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= +cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= +cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= +cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= +cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= +cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= +cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= +cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= +cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= +cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= +cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= +cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= +cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= +cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= +cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= +cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= +cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= +cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= +cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= +cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= +cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= +cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= +cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= +cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= +cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= +cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= +cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= +cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= +cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= +cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= +cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= +cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= +cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= +cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= +cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= +cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= +cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= +cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= +cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= +cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= +cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= +cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= +cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= +cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= +cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= +cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= +cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= +cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= +cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= +cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= +cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= +cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= +cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= +cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= +cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= +cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= +cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= +cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= +cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= +cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= +cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= +cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= cloud.google.com/go/secretmanager v1.0.0/go.mod h1:+Qkm5qxIJ5mk74xxIXA+87fseaY1JLYBcFPQoc/GQxg= +cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= +cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= +cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= +cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= +cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= +cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= +cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= +cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= +cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= +cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= +cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= +cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= +cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= +cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= +cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= +cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= +cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= +cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= +cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= +cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= +cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= +cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/HdrHistogram/hdrhistogram-go v1.1.1/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI= -github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -75,16 +196,15 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/attestantio/dirk v1.1.0 h1:hwMTYZkwj/Y0um3OD0LQxg2xSl4/5xqVWV2MRePE4ec= github.com/attestantio/dirk v1.1.0/go.mod h1:2jkOw/XHjvIDdhDcmj+Z3kuVPpxMcQ6zxzzjSSv71PY= github.com/attestantio/go-eth2-client v0.8.1/go.mod h1:kEK9iAAOBoADO5wEkd84FEOzjT1zXgVWveQsqn+uBGg= -github.com/attestantio/go-eth2-client v0.11.0 h1:8/Jn5AAfd+4tOggLi+FvOv9/ORaObECv42ab7vK2FJc= -github.com/attestantio/go-eth2-client v0.11.0/go.mod h1:zXL/BxC0cBBhxj+tP7QG7t9Ufoa8GwQLdlbvZRd9+dM= +github.com/attestantio/go-eth2-client v0.14.0 h1:usWgI0KIfGWQ8G7XUsMM2bTe+yuJEh4d3HEO1vPD5Go= +github.com/attestantio/go-eth2-client v0.14.0/go.mod h1:bcg5gfjVcm+MtcaZfzv/uSWNHU4i8hGamVG+9JCZnC0= github.com/aws/aws-sdk-go v1.33.17/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.40.41/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aws/aws-sdk-go v1.41.19/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.42.44 h1:vPlF4cUsdN5ETfvb7ewZFbFZyB6Rsfndt3kS2XqLXKo= -github.com/aws/aws-sdk-go v1.42.44/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.44.111 h1:AcWfOgeedSQ4gQVwcIe6aLxpQNJMloZQyqnr7Dzki+s= +github.com/aws/aws-sdk-go v1.44.111/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -116,6 +236,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -143,6 +264,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.0/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -154,12 +276,16 @@ github.com/ferranbt/fastssz v0.0.0-20200728110133-0b6e349af87a/go.mod h1:DyEu2iu github.com/ferranbt/fastssz v0.0.0-20210526181520-7df50c8568f8/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM= github.com/ferranbt/fastssz v0.0.0-20210905181407-59cf6761a7d5/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4= github.com/ferranbt/fastssz v0.0.0-20211031100431-9823ca9021f1/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4= -github.com/ferranbt/fastssz v0.0.0-20220103083642-bc5fefefa28b h1:Jea4sHxe4sTegJgpfhWvxSjFF2nyq4/R/qWm6AziPiI= -github.com/ferranbt/fastssz v0.0.0-20220103083642-bc5fefefa28b/go.mod h1:S8yiDeAXy8f88W4Ul+0dBMPx49S05byYbmZD6Uv94K4= +github.com/ferranbt/fastssz v0.1.1/go.mod h1:U2ZsxlYyvGeQGmadhz8PlEqwkBzDIhHwd3xuKrg2JIs= +github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk= +github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -188,7 +314,6 @@ github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZg github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 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/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -241,8 +366,11 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/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/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.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= @@ -269,13 +397,21 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= 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/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.13.0/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= @@ -290,6 +426,7 @@ github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -313,20 +450,21 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/herumi/bls-eth-go-binary v0.0.0-20210520070601-31246bfa8ac4/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/herumi/bls-eth-go-binary v0.0.0-20210902234237-7763804ee078/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/herumi/bls-eth-go-binary v0.0.0-20211117070716-2bdbdadbf8bb/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= -github.com/herumi/bls-eth-go-binary v0.0.0-20220103074059-01b0ca9e9ef7 h1:gMN4oOdFLVR7ye4SCacHD4SIB64NPUNE+V9w8o7bR6A= -github.com/herumi/bls-eth-go-binary v0.0.0-20220103074059-01b0ca9e9ef7/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= +github.com/herumi/bls-eth-go-binary v1.28.1 h1:fcIZ48y5EE9973k05XjE8+P3YiQgjZz4JI/YabAm8KA= +github.com/herumi/bls-eth-go-binary v1.28.1/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jackc/puddle v1.1.4/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= @@ -347,20 +485,23 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL 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/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A= -github.com/klauspost/cpuid/v2 v2.0.11/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= +github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 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 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -369,24 +510,26 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -405,8 +548,9 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/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= @@ -424,8 +568,11 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -441,25 +588,22 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/protolambda/zssz v0.1.5 h1:7fjJjissZIIaa2QcvmhS/pZISMX21zVITt49sW1ouek= github.com/protolambda/zssz v0.1.5/go.mod h1:a4iwOX5FE7/JkKA+J/PH0Mjo9oXftN6P8NZyL28gpag= @@ -470,24 +614,30 @@ github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 h1:0tVE4 github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7/go.mod h1:wmuf/mdK4VMD+jA9ThwcUKjg3a2XWM9cVfFYjDyY4j4= 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/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48 h1:cSo6/vk8YpvkLbk9v3FO97cakNmUoxwi2KMP8hd5WIw= +github.com/prysmaticlabs/gohashtree v0.0.1-alpha.0.20220714111606-acbb2962fb48/go.mod h1:4pWaT30XoEx1j8KNJf3TV+E3mQkaufn7mf+jRNb/Fuk= github.com/r3labs/sse/v2 v2.3.0/go.mod h1:hUrYMKfu9WquG9MyI0r6TKiNH+6Sw/QPKm2YbNbU5g8= github.com/r3labs/sse/v2 v2.7.4 h1:pvCMswPDlXd/ZUFx1dry0LbXJNHXwWPulLcUGYwClc0= github.com/r3labs/sse/v2 v2.7.4/go.mod h1:hUrYMKfu9WquG9MyI0r6TKiNH+6Sw/QPKm2YbNbU5g8= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo= -github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc= github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc= +github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= +github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= +github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y= @@ -495,19 +645,19 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.8.0 h1:5MmtuhAgYeU6qpa7w7bP0dv6MBYuup0vekhSpSkoq60= -github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= @@ -520,21 +670,26 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= -github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= +github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= 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/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 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= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= @@ -551,8 +706,9 @@ github.com/wealdtech/go-ecodec v1.1.2 h1:CcNBnFV6b8IoDtu8wj6cfrmuBRBw00VYqsvpT4+ github.com/wealdtech/go-ecodec v1.1.2/go.mod h1:0Rgn8mEr0GX4fDyuU3aUL+xp4n17Wviscasp6rWCh10= github.com/wealdtech/go-eth2-types/v2 v2.5.5/go.mod h1:QY9t7nwxc26C9/iZHh1wzc+hZbGGn7ipgjMYPhKnN/0= github.com/wealdtech/go-eth2-types/v2 v2.5.6/go.mod h1:SX7+QxnhXGxeW8tESzJ/BSIXvoflBHUi21chqRsZ9wE= -github.com/wealdtech/go-eth2-types/v2 v2.6.0 h1:djgMv1A40bstgkg6L1ZA7eowR/Gbmj1ZWnBdrK39lhY= github.com/wealdtech/go-eth2-types/v2 v2.6.0/go.mod h1:psOez/ZRBzZSDl5hiNDwRf5ZqQujNE6h5FxAz09Koxg= +github.com/wealdtech/go-eth2-types/v2 v2.7.0 h1:TV2jrNkane2nxTiVhyG3npVtg825WvRdCZZ4j+jTENA= +github.com/wealdtech/go-eth2-types/v2 v2.7.0/go.mod h1:aQ5dk+KNPE/A2r3lLhKpW+f5B24aJO68tRz6wO4Zo/g= github.com/wealdtech/go-eth2-util v1.7.0 h1:bgCnZ4H5K5VE+CiAwFTKhrICItq5rI+5VYaODFWC6is= github.com/wealdtech/go-eth2-util v1.7.0/go.mod h1:L0q3G7S1Dm1WJPye5m2wjuNweXC98o1CmLTKPmBTlpg= github.com/wealdtech/go-eth2-wallet v1.15.0 h1:yff2rWCvHyr5bOU41wwilsNemFRYOFinZoIPjhzG10M= @@ -562,8 +718,9 @@ github.com/wealdtech/go-eth2-wallet-dirk v1.2.0/go.mod h1:1lnHDSdcRxj9CFJh+jPtdg github.com/wealdtech/go-eth2-wallet-distributed v1.1.4 h1:EBk/FofiQWtbRYmwdCp0qM9TPDvlh1LN2yjlLr4W3ao= github.com/wealdtech/go-eth2-wallet-distributed v1.1.4/go.mod h1:Y31pDxcdyADwfQl65t8V6KhcmCes31EXkXZPDcT2SIk= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.6/go.mod h1:hIeHsLJWVxFUUqQqaBm9nmUW3Y/eHneQclYyNayUeQg= -github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.2.0 h1:HgIK30YsXxgR6Ra6pvxW1KFUPbx7BpIIK1VGhOlmCm4= github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.2.0/go.mod h1:qqIU42c9sXcNYsiEjUQoOOWYZfZDL1zmyLtz3t+wN2s= +github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.3.0 h1:3Kx2QvKU/4PP0d7+e3+q9G+QiXQprNQPeAXsWOcfKRI= +github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.3.0/go.mod h1:qqIU42c9sXcNYsiEjUQoOOWYZfZDL1zmyLtz3t+wN2s= github.com/wealdtech/go-eth2-wallet-encryptor-unencrypted v1.0.1 h1:x6bq8cVgRgfhwtSQSYo/9AqJ8qEeaS6af28cW0cVj5U= 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.6.0 h1:Oy5TsD6HqZzb3MwGOe+5WVCj4pCKKUYYc2OKyN42QCM= @@ -596,10 +753,14 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= +go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= +go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -631,8 +792,9 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed h1:YoWVYYAfvQ4ddHv3OKmIvX7NCAhFGTj62VP2l2kfBbA= -golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b h1:huxqepDufQpLLIRXiVkTvnxrzJlpwmIWAObmcCcUFr0= +golang.org/x/crypto v0.0.0-20221005025214-4161e89ecf1b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -725,9 +887,18 @@ golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211105192438-b53810dc28af/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211116231205-47ca1ff31462/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 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= @@ -745,6 +916,13 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= +golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= 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= @@ -755,8 +933,11 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ 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/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/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= @@ -841,8 +1022,23 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= +golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -921,8 +1117,12 @@ golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= @@ -961,6 +1161,22 @@ google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnn google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= +google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= +google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= +google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1013,6 +1229,7 @@ google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= @@ -1043,8 +1260,46 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= +google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= +google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= +google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= +google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= +google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= +google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91 h1:Ezh2cpcnP5Rq60sLensUsFnxh7P6513NLvNtCm9iyJ4= +google.golang.org/genproto v0.0.0-20220930163606-c98284e70a91/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1074,9 +1329,14 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= +google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -1090,8 +1350,10 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= @@ -1103,8 +1365,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.3 h1:jRskFVxYaMGAMUbN0UZ7niA9gzL9B49DOqE78vg0k3w= -gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1116,8 +1378,9 @@ 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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1131,3 +1394,4 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/services/chaintime/standard/service.go b/services/chaintime/standard/service.go index 40d4a62..2ab73a0 100644 --- a/services/chaintime/standard/service.go +++ b/services/chaintime/standard/service.go @@ -33,6 +33,7 @@ type Service struct { epochsPerSyncCommitteePeriod uint64 altairForkEpoch phase0.Epoch bellatrixForkEpoch phase0.Epoch + capellaForkEpoch phase0.Epoch } // module-wide log. @@ -100,6 +101,13 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) { } log.Trace().Uint64("epoch", uint64(bellatrixForkEpoch)).Msg("Obtained Bellatrix fork epoch") + capellaForkEpoch, err := fetchCapellaForkEpoch(ctx, parameters.forkScheduleProvider) + if err != nil { + // Set to far future epoch. + capellaForkEpoch = 0xffffffffffffffff + } + log.Trace().Uint64("epoch", uint64(capellaForkEpoch)).Msg("Obtained Capella fork epoch") + s := &Service{ genesisTime: genesisTime, slotDuration: slotDuration, @@ -107,6 +115,7 @@ func New(ctx context.Context, params ...Parameter) (*Service, error) { epochsPerSyncCommitteePeriod: epochsPerSyncCommitteePeriod, altairForkEpoch: altairForkEpoch, bellatrixForkEpoch: bellatrixForkEpoch, + capellaForkEpoch: capellaForkEpoch, } return s, nil @@ -247,3 +256,28 @@ func fetchBellatrixForkEpoch(ctx context.Context, provider eth2client.ForkSchedu } return 0, errors.New("no bellatrix fork obtained") } + +// CapellaInitialEpoch provides the epoch at which the Capella hard fork takes place. +func (s *Service) CapellaInitialEpoch() phase0.Epoch { + return s.capellaForkEpoch +} + +func fetchCapellaForkEpoch(ctx context.Context, provider eth2client.ForkScheduleProvider) (phase0.Epoch, error) { + forkSchedule, err := provider.ForkSchedule(ctx) + if err != nil { + return 0, err + } + count := 0 + for i := range forkSchedule { + count++ + if bytes.Equal(forkSchedule[i].CurrentVersion[:], forkSchedule[i].PreviousVersion[:]) { + // This is the genesis fork; ignore it. + continue + } + if count == 2 { + return forkSchedule[i].Epoch, nil + } + count++ + } + return 0, errors.New("no capella fork obtained") +} diff --git a/signing/container_encoding.go b/signing/container_encoding.go index 426b98f..a77f7cb 100644 --- a/signing/container_encoding.go +++ b/signing/container_encoding.go @@ -1,4 +1,6 @@ // Code generated by fastssz. DO NOT EDIT. +// Hash: c953c4b72fdc3f250f4227b181e286fe53fd663c5aa4f5cc3de6cc9998c7fdb7 +// Version: 0.1.2 package signing import ( @@ -15,15 +17,15 @@ func (c *Container) MarshalSSZTo(buf []byte) (dst []byte, err error) { dst = buf // Field (0) 'Root' - if len(c.Root) != 32 { - err = ssz.ErrBytesLength + if size := len(c.Root); size != 32 { + err = ssz.ErrBytesLengthFn("Container.Root", size, 32) return } dst = append(dst, c.Root...) // Field (1) 'Domain' - if len(c.Domain) != 32 { - err = ssz.ErrBytesLength + if size := len(c.Domain); size != 32 { + err = ssz.ErrBytesLengthFn("Container.Domain", size, 32) return } dst = append(dst, c.Domain...) @@ -66,19 +68,19 @@ func (c *Container) HashTreeRoot() ([32]byte, error) { } // HashTreeRootWith ssz hashes the Container object with a hasher -func (c *Container) HashTreeRootWith(hh *ssz.Hasher) (err error) { +func (c *Container) HashTreeRootWith(hh ssz.HashWalker) (err error) { indx := hh.Index() // Field (0) 'Root' - if len(c.Root) != 32 { - err = ssz.ErrBytesLength + if size := len(c.Root); size != 32 { + err = ssz.ErrBytesLengthFn("Container.Root", size, 32) return } hh.PutBytes(c.Root) // Field (1) 'Domain' - if len(c.Domain) != 32 { - err = ssz.ErrBytesLength + if size := len(c.Domain); size != 32 { + err = ssz.ErrBytesLengthFn("Container.Domain", size, 32) return } hh.PutBytes(c.Domain) @@ -86,3 +88,8 @@ func (c *Container) HashTreeRootWith(hh *ssz.Hasher) (err error) { hh.Merkleize(indx) return } + +// GetTree ssz hashes the Container object +func (c *Container) GetTree() (*ssz.Node, error) { + return ssz.ProofTree(c) +} diff --git a/util/account.go b/util/account.go index 40432e1..78304c3 100644 --- a/util/account.go +++ b/util/account.go @@ -15,11 +15,145 @@ package util import ( "context" + "encoding/hex" + "fmt" + "regexp" + "strings" "github.com/pkg/errors" + "github.com/tyler-smith/go-bip39" + util "github.com/wealdtech/go-eth2-util" e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" + "golang.org/x/text/unicode/norm" ) +// ParseAccount parses input to obtain an account. +func ParseAccount(ctx context.Context, + accountStr string, + supplementary []string, + unlock bool, +) ( + e2wtypes.Account, + error, +) { + if accountStr == "" { + return nil, errors.New("no account specified") + } + + var account e2wtypes.Account + var err error + + switch { + case strings.HasPrefix(accountStr, "0x"): + // A key. Could be public or private. + data, err := hex.DecodeString(strings.TrimPrefix(accountStr, "0x")) + if err != nil { + return nil, errors.Wrap(err, "failed to parse account key") + } + switch len(data) { + case 48: + // Public key. + account, err = newScratchAccountFromPubKey(data) + if err != nil { + return nil, errors.Wrap(err, "failed to create account from public key") + } + if unlock { + return nil, errors.New("cannot unlock an account specified by its public key") + } + case 32: + // Private key. + account, err = newScratchAccountFromPrivKey(data) + if err != nil { + return nil, errors.Wrap(err, "failed to create account from public key") + } + if unlock { + _, err = UnlockAccount(ctx, account, nil) + if err != nil { + return nil, errors.Wrap(err, "failed to unlock account") + } + } + default: + return nil, fmt.Errorf("key of length %d neither public nor private key", len(data)) + } + case strings.Contains(accountStr, "/"): + // An account. + _, account, err = WalletAndAccountFromPath(ctx, accountStr) + if err != nil { + return nil, errors.Wrap(err, "unable to obtain account") + } + if unlock { + // Supplementary will be the unlock passphrase(s). + _, err = UnlockAccount(ctx, account, supplementary) + if err != nil { + return nil, errors.Wrap(err, "failed to unlock account") + } + } + case strings.Contains(accountStr, " "): + // A mnemonic. + // Supplementary will be the path. + if len(supplementary) == 0 { + return nil, errors.New("missing derivation path") + } + account, err = accountFromMnemonicAndPath(accountStr, supplementary[0]) + if err != nil { + return nil, err + } + if unlock { + err = account.(e2wtypes.AccountLocker).Unlock(ctx, nil) + if err != nil { + return nil, errors.Wrap(err, "failed to unlock account") + } + } + default: + return nil, fmt.Errorf("unknown account specifier %s", accountStr) + } + + return account, nil +} + +// hdPathRegex is the regular expression that matches an HD path. +var hdPathRegex = regexp.MustCompile("^m/[0-9]+/[0-9]+(/[0-9+])+") + +func accountFromMnemonicAndPath(mnemonic string, path string) (e2wtypes.Account, error) { + // If there are more than 24 words we treat the additional characters as the passphrase. + mnemonicParts := strings.Split(mnemonic, " ") + mnemonicPassphrase := "" + if len(mnemonicParts) > 24 { + mnemonic = strings.Join(mnemonicParts[:24], " ") + mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ") + } + // Normalise the input. + mnemonic = string(norm.NFKD.Bytes([]byte(mnemonic))) + mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase))) + + if !bip39.IsMnemonicValid(mnemonic) { + return nil, errors.New("mnemonic is invalid") + } + + // Create seed from mnemonic and passphrase. + seed := bip39.NewSeed(mnemonic, mnemonicPassphrase) + + // Ensure the path is valid. + match := hdPathRegex.Match([]byte(path)) + if !match { + return nil, errors.New("path does not match expected format m/…") + } + + // Derive private key from seed and path. + key, err := util.PrivateKeyFromSeedAndPath(seed, path) + if err != nil { + return nil, errors.Wrap(err, "failed to generate key") + } + + // Create a scratch account given the private key. + account, err := newScratchAccountFromPrivKey(key.Marshal()) + if err != nil { + return nil, errors.Wrap(err, "failed to generate scratch account") + } + + return account, nil +} + // UnlockAccount attempts to unlock an account. It returns true if the account was already unlocked. func UnlockAccount(ctx context.Context, account e2wtypes.Account, passphrases []string) (bool, error) { locker, isAccountLocker := account.(e2wtypes.AccountLocker) @@ -46,6 +180,13 @@ func UnlockAccount(ctx context.Context, account e2wtypes.Account, passphrases [] } } + // Also attempt to unlock without any passphrase. + err = locker.Unlock(ctx, nil) + if err == nil { + // Unlocked. + return false, nil + } + // Failed to unlock it. return false, errors.New("failed to unlock account") } diff --git a/util/account_test.go b/util/account_test.go new file mode 100644 index 0000000..bb3c721 --- /dev/null +++ b/util/account_test.go @@ -0,0 +1,103 @@ +// Copyright © 2020 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util_test + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/wealdtech/ethdo/util" + e2types "github.com/wealdtech/go-eth2-types/v2" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" +) + +func TestParseAccount(t *testing.T) { + ctx := context.Background() + require.NoError(t, e2types.InitBLS()) + + tests := []struct { + name string + accountStr string + supplementary []string + unlock bool + err string + expectedPubkey string + expectedUnlocked bool + }{ + { + name: "Zero", + err: "no account specified", + }, + { + name: "Bad", + accountStr: "bad", + err: "unknown account specifier bad", + }, + { + name: "PublicKey", + accountStr: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + expectedPubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + }, + { + name: "PublicKeyUnlocked", + accountStr: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + unlock: true, + err: "cannot unlock an account specified by its public key", + }, + { + name: "PrivateKey", + accountStr: "0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55", + expectedPubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + }, + { + name: "PrivateKeyUnlocked", + accountStr: "0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55", + expectedPubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + unlock: true, + expectedUnlocked: true, + }, + { + name: "Mnemonic", + accountStr: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + supplementary: []string{"m/12381/3600/0/0"}, + expectedPubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + }, + { + name: "MnemonicUnlocked", + accountStr: "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon art", + supplementary: []string{"m/12381/3600/0/0"}, + expectedPubkey: "0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db", + unlock: true, + expectedUnlocked: true, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + account, err := util.ParseAccount(ctx, test.accountStr, test.supplementary, test.unlock) + if test.err == "" { + require.NoError(t, err) + require.NotNil(t, account) + unlocked, err := account.(e2wtypes.AccountLocker).IsUnlocked(ctx) + require.NoError(t, err) + require.Equal(t, test.expectedPubkey, fmt.Sprintf("%#x", account.PublicKey().Marshal())) + require.Equal(t, test.expectedUnlocked, unlocked) + } else { + require.EqualError(t, err, test.err) + } + }) + } +} diff --git a/util/scratchaccount.go b/util/scratchaccount.go index 224f3f6..e7e0158 100644 --- a/util/scratchaccount.go +++ b/util/scratchaccount.go @@ -75,6 +75,14 @@ func (a *ScratchAccount) PublicKey() e2types.PublicKey { return a.pubKey } +// PrivateKey returns the account private key. +func (a *ScratchAccount) PrivateKey(ctx context.Context) (e2types.PrivateKey, error) { + if a.privKey == nil { + return nil, errors.New("no private key available") + } + return a.privKey, nil +} + // Path returns the account path. func (a *ScratchAccount) Path() string { return "" From c9a30a6e4b672527a140b8f9d7d54f75c3867276 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 15:20:08 +0000 Subject: [PATCH 2/8] Update documentation. --- docs/changingwithdrawalcredentials.md | 32 ++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index 0711978..e95cfef 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -1,5 +1,5 @@ # Changing withdrawal credentials. -When creating a validator it is possible to set is withdrawal credentials to those based upon a BLS private key (known as BLS withdrawal credentials, or "type 0" withdrawal credentials) or based upon an Ethereum execution address (known as execution withdrawal credentials, or "type 1" withdrawal credentials). With the advent of the Capella hard fork, it is possible for rewards accrued on the consensus chain (also known as the beacon chain) to be sent to the execution chain. However, for this to occur the validator's withdrawal credentials must be type 1. Capella also brings a mechanism to change existing type 0 withdrawal credentials to type 1 withdrawal credentials, and this document outlines the process to change withdrawal credentials from type 0 to type 1 so that such rewards can be accessed. +When creating a validator it is possible to set its withdrawal credentials to those based upon a BLS private key (known as BLS withdrawal credentials, or "type 0" withdrawal credentials) or based upon an Ethereum execution address (known as execution withdrawal credentials, or "type 1" withdrawal credentials). With the advent of the Capella hard fork, it is possible for rewards accrued on the consensus chain (also known as the beacon chain) to be sent to the execution chain. However, for this to occur the validator's withdrawal credentials must be type 1. Capella also brings a mechanism to change existing type 0 withdrawal credentials to type 1 withdrawal credentials, and this document outlines the process to change withdrawal credentials from type 0 to type 1 so that consensus rewards can be accessed. **Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure you end up with the ability to access the rewards that will be sent to the execution address within the credentials.** @@ -34,8 +34,8 @@ Note that some beacon nodes may require configuration to serve their REST API. There are three options to reference a validator: - the `ethdo` account of the validator (in format wallet/account) -- the validator's public key (in format 0x...) -- the validator's index (in format 123...) +- the validator's public key (in format 0x…) +- the validator's index (in format 123…) Any of these can be passed to the following commands with the `--validator` parameter. You need to ensure that you have this information before starting the process. @@ -50,6 +50,8 @@ The execution address will be the address to which all Ether held by the validat The execution address must be supplied in [EIP-55](https://eips.ethereum.org/EIPS/eip-55) format, _i.e._ using mixed case for checksum. An example of a mixed-case Ethereum address is `0x8f0844Fd51E31ff6Bf5baBe21DCcf7328E19Fd9F` +**In the following examples we will use an execution address of 0x8f…9F. Please replace this with the your execution address in all commands.** + ### Online or offline It is possible to generate the withdrawal credentials change operation either online or offline. @@ -84,13 +86,13 @@ The steps for generating and publishing the credentials change operation online #### Using a mnemonic Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. -- m/12381/3600/_i_/0 is the path to the _i_th withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ -- m/12381/3600/_i_/0/0 is the path to the _i_th validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ +- m/12381/3600/_i_/0 is the path to a withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ +- m/12381/3600/_i_/0/0 is the path to a validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: ``` -ethdo account derive --mnemonic='abandon ... art' --path='m/12381/3600/0/0/0' +ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0/0' ``` replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: @@ -104,7 +106,7 @@ The displayed public key should match the public key of the validator of which y Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: ``` -ethdo account derive --mnemonic='abandon ... art' --path='m/12381/0/0' --show-withdrawal-credentials +ethdo account derive --mnemonic='abandon … art' --path='m/12381/0/0' --show-withdrawal-credentials ``` again replacing the first '0' in the path with the validator number. This will provide an output similar to: @@ -119,7 +121,7 @@ The displayed withdrawal credentials should match the current withdrawal credent Once you are comfortable that the mnemonic and path provide the correct result you can generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x00...13 --mnemonic='abandon ... art' --path='m/12381/0/0' +ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/0/0' ``` again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. @@ -128,7 +130,7 @@ again replacing the first '0' in the path with the validator number, and using y If you have the private key from which the current withdrawal credentials were derived this can be used to generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x00...13 --private-key=0x3b...9c +ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --private-key=0x3b…9c ``` using your own execution address as explained earlier in the guide, and your own private key. @@ -137,7 +139,7 @@ using your own execution address as explained earlier in the guide, and your own If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x00...13 --account=Wallet/Account --passphrase=secret +ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --account=Wallet/Account --passphrase=secret ``` setting the execution address, account and passphrase to your own values. @@ -173,7 +175,7 @@ Many stakers will have generated their validators from a mnemonic. A mnemonic i The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: ``` -ethdo account derive --mnemonic='abandon ... art' --path='m/12381/3600/0/0/0' +ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0/0' ``` replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: @@ -187,7 +189,7 @@ The displayed public key should match the public key of the validator of which y Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: ``` -ethdo account derive --mnemonic='abandon ... art' --path='m/12381/0/0' --show-withdrawal-credentials +ethdo account derive --mnemonic='abandon … art' --path='m/12381/0/0' --show-withdrawal-credentials ``` again replacing the first '0' in the path with the validator number. This will provide an output similar to: @@ -202,7 +204,7 @@ The displayed withdrawal credentials should match the current withdrawal credent Once you are comfortable that the mnemonic and path provide the correct result you can generate the credentials change operation with the following command: ``` -ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --mnemonic='abandon ... art' --path='m/12381/0/0' +ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/0/0' ``` again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. This will produce output similar to the following: @@ -216,7 +218,7 @@ again replacing the first '0' in the path with the validator number, and using y If you have the private key from which the current withdrawal credentials were derived this can be used to generate the credentials change operation with the following command: ``` -ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --private-key=0x3bdb...6a9c +ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --private-key=0x3b…9c ``` using your own execution address as explained earlier in the guide, and your own private key. This will produce output similar to the following: @@ -229,7 +231,7 @@ using your own execution address as explained earlier in the guide, and your own If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate the credentials change operation with the following command: ``` -ethdo validator credentials set --offline --genesis-validators=root=0x04...fb --fork-version=0x03...20 --validator=123 --execution-address=0x00...13 --account=Wallet/Account --passphrase=secret +ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --account=Wallet/Account --passphrase=secret ``` setting the execution address, account and passphrase to your own values. This will produce output similar to the following: From 9fc184f6a1c59f6a40bdef9a176f32b7b4331f5b Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 15:24:15 +0000 Subject: [PATCH 3/8] Update documentation. --- docs/changingwithdrawalcredentials.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index e95cfef..bff85c8 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -4,7 +4,7 @@ When creating a validator it is possible to set its withdrawal credentials to th **Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure you end up with the ability to access the rewards that will be sent to the execution address within the credentials.** ## Preparing for the process -A number of steps need to be taken to prepare for creating and broadcasting the credentials change operation. +A number of steps need to be taken to prepare for generating and broadcasting the credentials change operation. ### Accessing the beacon node `ethdo` requires access to the beacon node at various points during the operation. `ethdo` will attempt to find a local beacon node automatically, but if not then an explicit connection value will be required. To find out if `ethdo` has access to the beacon node run: @@ -78,13 +78,13 @@ BLS credentials: 0x00ebf119d469a31ff2a534d176e6d594046a2367f7a36848009f70f3cb9a9 This result should start with the phrase "BLS credentials", which means that these credentials must be upgraded to an Ethereum execution address to receive withdrawals. If instead the result starts with the phrase "Ethereum execution address" it means that the credentials are already set to an Ethereum execution address and no further action is necessary (or possible). -The next step depends on if you have access to your keys +Once you have the correct information to refer to your validator you can generate the credentials change operation. ### Generate and publish the credentials change operation (online) The steps for generating and publishing the credentials change operation online depend on the method by which you access your current withdrawal key. #### Using a mnemonic -Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. +Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a _path_. Commonly, keys will have been generated using two paths: - m/12381/3600/_i_/0 is the path to a withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ - m/12381/3600/_i_/0/0 is the path to a validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ @@ -103,10 +103,10 @@ Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726d The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. -Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: +Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do so run: ``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/0/0' --show-withdrawal-credentials +ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0' --show-withdrawal-credentials ``` again replacing the first '0' in the path with the validator number. This will provide an output similar to: @@ -121,7 +121,7 @@ The displayed withdrawal credentials should match the current withdrawal credent Once you are comfortable that the mnemonic and path provide the correct result you can generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/0/0' +ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/3600/0/0' ``` again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. @@ -186,10 +186,10 @@ Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726d The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. -Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do su run: +Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do so run: ``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/0/0' --show-withdrawal-credentials +ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0' --show-withdrawal-credentials ``` again replacing the first '0' in the path with the validator number. This will provide an output similar to: @@ -204,7 +204,7 @@ The displayed withdrawal credentials should match the current withdrawal credent Once you are comfortable that the mnemonic and path provide the correct result you can generate the credentials change operation with the following command: ``` -ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/0/0' +ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/3600/0/0' ``` again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. This will produce output similar to the following: From bcf6ffdaf016ed3eb151c74ae19a311cca5ccbf6 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 15:33:01 +0000 Subject: [PATCH 4/8] Linting. --- cmd/account/derive/process.go | 4 ---- cmd/validatorinfo.go | 7 +------ docs/changingwithdrawalcredentials.md | 12 ++++++------ 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/cmd/account/derive/process.go b/cmd/account/derive/process.go index 3ef744d..4135fa6 100644 --- a/cmd/account/derive/process.go +++ b/cmd/account/derive/process.go @@ -15,7 +15,6 @@ package accountderive import ( "context" - "regexp" "github.com/pkg/errors" "github.com/wealdtech/ethdo/util" @@ -23,9 +22,6 @@ import ( e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) -// pathRegex is the regular expression that matches an HD path. -var pathRegex = regexp.MustCompile("^m/[0-9]+/[0-9]+(/[0-9+])+") - func process(ctx context.Context, data *dataIn) (*dataOut, error) { if data == nil { return nil, errors.New("no data") diff --git a/cmd/validatorinfo.go b/cmd/validatorinfo.go index 97970bf..81f937b 100644 --- a/cmd/validatorinfo.go +++ b/cmd/validatorinfo.go @@ -31,7 +31,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/wealdtech/ethdo/util" - e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" string2eth "github.com/wealdtech/go-string2eth" ) @@ -59,6 +58,7 @@ In quiet mode this will return 0 if the validator information can be obtained, o } validator, err := util.ParseValidator(ctx, eth2Client.(eth2client.ValidatorsProvider), viper.GetString("validator"), "head") + errCheck(err, "Failed to obtain validator") if verbose { network, err := util.Network(ctx, eth2Client) @@ -109,11 +109,6 @@ In quiet mode this will return 0 if the validator information can be obtained, o }, } -// validatorInfoAccount obtains the account for the validator info command. -func validatorInfoAccount(ctx context.Context, eth2Client eth2client.Service) (e2wtypes.Account, error) { - return util.ParseAccount(ctx, viper.GetString("validator"), nil, false) -} - // graphData returns data from the graph about number and amount of deposits func graphData(network string, validatorPubKey []byte) (uint64, spec.Gwei, error) { subgraph := "" diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index bff85c8..4de9ee2 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -124,7 +124,7 @@ Once you are comfortable that the mnemonic and path provide the correct result y ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/3600/0/0' ``` -again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. +again replacing the first '0' in the path with the validator number. #### Using a private key If you have the private key from which the current withdrawal credentials were derived this can be used to generate and broadcast the credentials change operation with the following command: @@ -133,7 +133,7 @@ If you have the private key from which the current withdrawal credentials were d ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --private-key=0x3b…9c ``` -using your own execution address as explained earlier in the guide, and your own private key. +using your own private key. #### Using an account If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate and broadcast the credentials change operation with the following command: @@ -142,10 +142,10 @@ If you used `ethdo` to generate your validator deposit data you will likely have ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --account=Wallet/Account --passphrase=secret ``` -setting the execution address, account and passphrase to your own values. +using your own account and passphrase. ### Generate the credentials change operation (offline) -Generating the credentials change operation offline requires information from the online component, so is somewhat more involved than the online process, however does not expose mnemonics, private keys, or passphrases to servers that are connected to the internet. The process is below. +Generating the credentials change operation offline requires information from the online component and is more involved than the online process, however does not expose mnemonics, private keys, or passphrases to servers that are connected to the internet. The process is below. #### Obtain data required for offline generation. Generating the credentials change operation requires information that comes from an online beacon node. As such, on your _online_ server you need to run the following command: @@ -164,7 +164,7 @@ Add the following to your command to run it offline: This information needs to be copied to your offline server to continue. #### Generate signed operation -Generating the signed operation offline +Generating the signed operation offline is different from the online operation in that it will produce an output that can be copied to the online server for broadcast. Separating generation from broadcast allows the offline server to remain securely disconnected from the internet. The generation steps should be run on the _offline_ server. #### Using a mnemonic Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. @@ -247,7 +247,7 @@ An online server can broadcast the result of the previous step. Note that the d ethdo validator credentials set --signed-operation='{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"}' ``` -Alternatively, if the operation is stored on a filesystem, for example on a USB device from where it was copied from the offline server, it can be used with: +Alternatively, if the operation is stored on a filesystem, for example on a USB device from where it was copied from the offline server, it can be accessed with: ``` ethdo validator credentials set --signed-operation=/path/to/signed/operation From f78b2922ecd42dab994e3bd6ffcc5629cff85808 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 16:15:45 +0000 Subject: [PATCH 5/8] Tidy-ups. --- docs/changingwithdrawalcredentials.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index 4de9ee2..1392574 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -1,4 +1,4 @@ -# Changing withdrawal credentials. +# Changing withdrawal credentials When creating a validator it is possible to set its withdrawal credentials to those based upon a BLS private key (known as BLS withdrawal credentials, or "type 0" withdrawal credentials) or based upon an Ethereum execution address (known as execution withdrawal credentials, or "type 1" withdrawal credentials). With the advent of the Capella hard fork, it is possible for rewards accrued on the consensus chain (also known as the beacon chain) to be sent to the execution chain. However, for this to occur the validator's withdrawal credentials must be type 1. Capella also brings a mechanism to change existing type 0 withdrawal credentials to type 1 withdrawal credentials, and this document outlines the process to change withdrawal credentials from type 0 to type 1 so that consensus rewards can be accessed. **Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure you end up with the ability to access the rewards that will be sent to the execution address within the credentials.** From 0c36239b8be1654ae10049579d6bfd971ca4dacd Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Thu, 6 Oct 2022 18:19:38 +0000 Subject: [PATCH 6/8] Update output and associated documentation. --- cmd/account/derive/output.go | 6 ++++-- cmd/account/derive/run.go | 3 ++- docs/changingwithdrawalcredentials.md | 1 - docs/usage.md | 8 ++++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/account/derive/output.go b/cmd/account/derive/output.go index eae128f..90c643c 100644 --- a/cmd/account/derive/output.go +++ b/cmd/account/derive/output.go @@ -42,11 +42,13 @@ func output(ctx context.Context, data *dataOut) (string, error) { if data.showPrivateKey { builder.WriteString(fmt.Sprintf("Private key: %#x\n", data.key.Marshal())) } - builder.WriteString(fmt.Sprintf("Public key: %#x", data.key.PublicKey().Marshal())) if data.showWithdrawalCredentials { withdrawalCredentials := util.SHA256(data.key.PublicKey().Marshal()) withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX - builder.WriteString(fmt.Sprintf("\nWithdrawal credentials: %#x", withdrawalCredentials)) + builder.WriteString(fmt.Sprintf("Withdrawal credentials: %#x\n", withdrawalCredentials)) + } + if !(data.showPrivateKey || data.showWithdrawalCredentials) { + builder.WriteString(fmt.Sprintf("Public key: %#x\n", data.key.PublicKey().Marshal())) } return builder.String(), nil diff --git a/cmd/account/derive/run.go b/cmd/account/derive/run.go index 2baaaa9..255de55 100644 --- a/cmd/account/derive/run.go +++ b/cmd/account/derive/run.go @@ -15,6 +15,7 @@ package accountderive import ( "context" + "strings" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -45,5 +46,5 @@ func Run(cmd *cobra.Command) (string, error) { return "", errors.Wrap(err, "failed to obtain output") } - return results, nil + return strings.TrimSuffix(results, "\n"), nil } diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index 1392574..d9bb7ab 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -112,7 +112,6 @@ ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0' --sh again replacing the first '0' in the path with the validator number. This will provide an output similar to: ``` -Public key: 0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db Withdrawal credentials: 0x008ba1cc4b091b91c1202bba3f508075d6ff565c77e559f0803c0792e0302bf1 ``` diff --git a/docs/usage.md b/docs/usage.md index 200662c..e1dadc2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -587,6 +587,14 @@ Validator commands focus on interaction with Ethereum 2 validators. $ ethdo validator credentials get --validator=Validators/1 ``` +#### `credentials set` + +`ethdo validator credentials set` updates withdrawal credentials from BLS "type 0" credentials to execution "type 1" credentials. Full information about using this command can be found in the [specific documentation](./changingwithdrawalcredentials.md). + +```sh +$ ethdo validator credentials set --validator=Validators/1 --execution-address=0x8f…9F --private-key=0x3b…9c +``` + #### `depositdata` `ethdo validator depositdata` generates the data required to deposit one or more Ethereum 2 validators. Options include: From 2d96f7cb1359f614eb23c0c94bc54567f2d5e023 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Sat, 29 Oct 2022 12:10:31 +0100 Subject: [PATCH 7/8] Update operation and docs. --- .gitignore | 3 + cmd/validator/credentials/set/chaininfo.go | 127 +++ cmd/validator/credentials/set/command.go | 82 +- cmd/validator/credentials/set/output.go | 10 +- cmd/validator/credentials/set/process.go | 671 +++++++++---- .../credentials/set/validatorinfo.go | 97 ++ cmd/validatorcredentialsset.go | 17 +- docs/changingwithdrawalcredentials.md | 332 +++---- docs/images/credentials-change-offline.png | Bin 0 -> 155564 bytes docs/images/credentials-change-online.png | Bin 0 -> 130765 bytes docs/images/diagrams.svg | 923 ++++++++++++++++++ services/chaintime/service.go | 2 + util/account.go | 25 +- util/mnemonic.go | 47 + 14 files changed, 1870 insertions(+), 466 deletions(-) create mode 100644 cmd/validator/credentials/set/chaininfo.go create mode 100644 cmd/validator/credentials/set/validatorinfo.go create mode 100644 docs/images/credentials-change-offline.png create mode 100644 docs/images/credentials-change-online.png create mode 100644 docs/images/diagrams.svg create mode 100644 util/mnemonic.go diff --git a/.gitignore b/.gitignore index 70fa7ec..616fdea 100644 --- a/.gitignore +++ b/.gitignore @@ -18,5 +18,8 @@ coverage.html # Vim *.sw? +# Local JSON files +*.json + # Local TODO TODO.md diff --git a/cmd/validator/credentials/set/chaininfo.go b/cmd/validator/credentials/set/chaininfo.go new file mode 100644 index 0000000..8fa404a --- /dev/null +++ b/cmd/validator/credentials/set/chaininfo.go @@ -0,0 +1,127 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/pkg/errors" +) + +type chainInfo struct { + Version uint64 + Validators []*validatorInfo + GenesisValidatorsRoot phase0.Root + Epoch phase0.Epoch + ForkVersion phase0.Version + Domain phase0.Domain +} + +type chainInfoJSON struct { + Version string `json:"version"` + Validators []*validatorInfo `json:"validators"` + GenesisValidatorsRoot string `json:"genesis_validators_root"` + Epoch string `json:"epoch"` + ForkVersion string `json:"fork_version"` + Domain string `json:"domain"` +} + +// MarshalJSON implements json.Marshaler. +func (v *chainInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(&chainInfoJSON{ + Version: fmt.Sprintf("%d", v.Version), + Validators: v.Validators, + GenesisValidatorsRoot: fmt.Sprintf("%#x", v.GenesisValidatorsRoot), + Epoch: fmt.Sprintf("%d", v.Epoch), + ForkVersion: fmt.Sprintf("%#x", v.ForkVersion), + Domain: fmt.Sprintf("%#x", v.Domain), + }) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (v *chainInfo) UnmarshalJSON(input []byte) error { + var data chainInfoJSON + if err := json.Unmarshal(input, &data); err != nil { + return errors.Wrap(err, "invalid JSON") + } + + if data.Version == "" { + // Default to 1. + v.Version = 1 + } else { + version, err := strconv.ParseUint(data.Version, 10, 64) + if err != nil { + return errors.Wrap(err, "version invalid") + } + v.Version = version + } + + if len(data.Validators) == 0 { + return errors.New("validators missing") + } + v.Validators = data.Validators + + if data.GenesisValidatorsRoot == "" { + return errors.New("genesis validators root missing") + } + + genesisValidatorsRootBytes, err := hex.DecodeString(strings.TrimPrefix(data.GenesisValidatorsRoot, "0x")) + if err != nil { + return errors.Wrap(err, "genesis validators root invalid") + } + if len(genesisValidatorsRootBytes) != phase0.RootLength { + return errors.New("genesis validators root incorrect length") + } + copy(v.GenesisValidatorsRoot[:], genesisValidatorsRootBytes) + + if data.Epoch == "" { + return errors.New("epoch missing") + } + epoch, err := strconv.ParseUint(data.Epoch, 10, 64) + if err != nil { + return errors.Wrap(err, "epoch invalid") + } + v.Epoch = phase0.Epoch(epoch) + + if data.ForkVersion == "" { + return errors.New("fork version missing") + } + forkVersionBytes, err := hex.DecodeString(strings.TrimPrefix(data.ForkVersion, "0x")) + if err != nil { + return errors.Wrap(err, "fork version invalid") + } + if len(forkVersionBytes) != phase0.ForkVersionLength { + return errors.New("fork version incorrect length") + } + copy(v.ForkVersion[:], forkVersionBytes) + + if data.Domain == "" { + return errors.New("domain missing") + } + domainBytes, err := hex.DecodeString(strings.TrimPrefix(data.Domain, "0x")) + if err != nil { + return errors.Wrap(err, "domain invalid") + } + if len(domainBytes) != phase0.DomainLength { + return errors.New("domain incorrect length") + } + copy(v.Domain[:], domainBytes) + + return nil +} diff --git a/cmd/validator/credentials/set/command.go b/cmd/validator/credentials/set/command.go index 7be9b37..ef64f44 100644 --- a/cmd/validator/credentials/set/command.go +++ b/cmd/validator/credentials/set/command.go @@ -18,14 +18,12 @@ import ( "time" consensusclient "github.com/attestantio/go-eth2-client" - apiv1 "github.com/attestantio/go-eth2-client/api/v1" + "github.com/attestantio/go-eth2-client/spec/bellatrix" capella "github.com/attestantio/go-eth2-client/spec/capella" - "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/pkg/errors" "github.com/spf13/viper" "github.com/wealdtech/ethdo/services/chaintime" "github.com/wealdtech/ethdo/util" - e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) type command struct { @@ -42,75 +40,65 @@ type command struct { path string privateKey string validator string - withdrawalAddress string - signedOperation string + withdrawalAddressStr string forkVersion string genesisValidatorsRoot string + prepareOffline bool // Beacon node connection. timeout time.Duration connection string allowInsecureConnections bool + // Information required to generate the operations. + withdrawalAddress bellatrix.ExecutionAddress + chainInfo *chainInfo + // Processing. - consensusClient consensusclient.Service - chainTime chaintime.Service - withdrawalAccount e2wtypes.Account - validatorInfo *apiv1.Validator - domain phase0.Domain - op *capella.BLSToExecutionChange + consensusClient consensusclient.Service + chainTime chaintime.Service // Output. - signedOp *capella.SignedBLSToExecutionChange + signedOperations []*capella.SignedBLSToExecutionChange } func newCommand(ctx context.Context) (*command, error) { c := &command{ - quiet: viper.GetBool("quiet"), - verbose: viper.GetBool("verbose"), - debug: viper.GetBool("debug"), - offline: viper.GetBool("offline"), - json: viper.GetBool("json"), + quiet: viper.GetBool("quiet"), + verbose: viper.GetBool("verbose"), + debug: viper.GetBool("debug"), + offline: viper.GetBool("offline"), + json: viper.GetBool("json"), + timeout: viper.GetDuration("timeout"), + connection: viper.GetString("connection"), + allowInsecureConnections: viper.GetBool("allow-insecure-connections"), + prepareOffline: viper.GetBool("prepare-offline"), + account: viper.GetString("account"), + passphrases: util.GetPassphrases(), + mnemonic: viper.GetString("mnemonic"), + path: viper.GetString("path"), + privateKey: viper.GetString("private-key"), + + validator: viper.GetString("validator"), + withdrawalAddressStr: viper.GetString("withdrawal-address"), + forkVersion: viper.GetString("fork-version"), + genesisValidatorsRoot: viper.GetString("genesis-validators-root"), } - // Timeout. - if viper.GetDuration("timeout") == 0 { + // Timeout is required. + if c.timeout == 0 { return nil, errors.New("timeout is required") } - c.timeout = viper.GetDuration("timeout") - c.connection = viper.GetString("connection") - c.allowInsecureConnections = viper.GetBool("allow-insecure-connections") - - c.account = viper.GetString("account") - c.passphrases = util.GetPassphrases() - c.mnemonic = viper.GetString("mnemonic") - c.path = viper.GetString("path") - c.privateKey = viper.GetString("private-key") - - if c.account == "" && c.mnemonic == "" && c.privateKey == "" { - return nil, errors.New("one of account, mnemonic or private key required") + // We are generating information for offline use, we don't need any information + // related to the accounts or signing. + if c.prepareOffline { + return c, nil } if c.account != "" && len(c.passphrases) == 0 { return nil, errors.New("passphrase required with account") } - if c.mnemonic != "" && c.path == "" { - return nil, errors.New("path required with mnemonic") - } - - if viper.GetString("validator") == "" { - return nil, errors.New("validator is required") - } - c.validator = viper.GetString("validator") - - c.withdrawalAddress = viper.GetString("withdrawal-address") - - c.signedOperation = viper.GetString("signed-operation") - - c.forkVersion = viper.GetString("fork-version") - c.genesisValidatorsRoot = viper.GetString("genesis-validators-root") - return c, nil } diff --git a/cmd/validator/credentials/set/output.go b/cmd/validator/credentials/set/output.go index 4a367f5..2a94a55 100644 --- a/cmd/validator/credentials/set/output.go +++ b/cmd/validator/credentials/set/output.go @@ -16,6 +16,7 @@ package validatorcredentialsset import ( "context" "encoding/json" + "os" "github.com/pkg/errors" ) @@ -26,11 +27,14 @@ func (c *command) output(ctx context.Context) (string, error) { } if c.json || c.offline { - data, err := json.Marshal(c.signedOp) + data, err := json.Marshal(c.signedOperations) if err != nil { - return "", errors.Wrap(err, "failed to marshal signed operation") + return "", errors.Wrap(err, "failed to marshal signed operations") } - return string(data), nil + if err := os.WriteFile("credentials-operations.json", data, 0600); err != nil { + return "", errors.Wrap(err, "failed to write credentials-operations.json") + } + return "", nil } return "", nil diff --git a/cmd/validator/credentials/set/process.go b/cmd/validator/credentials/set/process.go index a16ef5f..0c2fc89 100644 --- a/cmd/validator/credentials/set/process.go +++ b/cmd/validator/credentials/set/process.go @@ -20,6 +20,7 @@ import ( "encoding/json" "fmt" "os" + "regexp" "strconv" "strings" @@ -32,64 +33,385 @@ import ( "github.com/wealdtech/ethdo/signing" "github.com/wealdtech/ethdo/util" ethutil "github.com/wealdtech/go-eth2-util" + e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" ) +// validatorPath is the regular expression that matches a validator path. +var validatorPath = regexp.MustCompile("^m/12381/3600/[0-9]+/0/0$") + +var offlinePreparationFilename = "offline-preparation.json" +var changeOperationsFilename = "change-operations.json" + func (c *command) process(ctx context.Context) error { if err := c.setup(ctx); err != nil { return err } - if err := c.obtainOp(ctx); err != nil { + if err := c.obtainRequiredInformation(ctx); err != nil { return err } + if c.prepareOffline { + return c.dumpRequiredInformation(ctx) + } + + if err := c.generateOperations(ctx); err != nil { + return err + } + + if validated, reason := c.validateOperations(ctx); !validated { + return fmt.Errorf("operation failed validation: %s", reason) + } + if c.json || c.offline { // Want JSON output, or cannot broadcast. return nil } - if validated, reason := c.validateOp(ctx); !validated { - return fmt.Errorf("operation failed validation: %s", reason) - } - - return c.broadcastOp(ctx) + return c.broadcastOperations(ctx) } -func (c *command) obtainOp(ctx context.Context) error { - // See if we have been given an op. - if c.signedOperation != "" { - // Input could be JSON or a path to JSON. - switch { - case strings.HasPrefix(c.signedOperation, "{"): - // Looks like JSON, nothing to do. - default: - // Assume it's a path to JSON - data, err := os.ReadFile(c.signedOperation) - if err != nil { - return errors.Wrap(err, "failed to read signed operation file") - } - c.signedOperation = string(data) - } - // Unmarshal it to confirm it is valid. - signedOp := &capella.SignedBLSToExecutionChange{} - if err := json.Unmarshal([]byte(c.signedOperation), signedOp); err != nil { - return err - } - return nil +// obtainRequiredInformation obtains the information required to create a +// withdrawal credentials change operation. +func (c *command) obtainRequiredInformation(ctx context.Context) error { + c.chainInfo = &chainInfo{ + Validators: make([]*validatorInfo, 0), } - // Need to create a new op. - if err := c.fetchAccount(ctx); err != nil { + // Use the offline preparation file if present (and we haven't been asked to recreate it). + if !c.prepareOffline { + err := c.loadChainInfo(ctx) + if err == nil { + return nil + } + } + + if c.offline { + return fmt.Errorf("could not find the %s file; this is required to have been previously generated using --offline-preparation on an online mcahine and be readable in the directory in which this command is being run", offlinePreparationFilename) + } + + if err := c.populateChainInfo(ctx); err != nil { return err } - pubkey, err := util.BestPublicKey(c.withdrawalAccount) + + return nil +} + +// populateChainInfo populates chain info structure from a beacon node. +func (c *command) populateChainInfo(ctx context.Context) error { + // Obtain validators. + validators, err := c.consensusClient.(consensusclient.ValidatorsProvider).Validators(ctx, "head", nil) + if err != nil { + return errors.Wrap(err, "failed to obtain validators") + } + + for _, validator := range validators { + c.chainInfo.Validators = append(c.chainInfo.Validators, &validatorInfo{ + Index: validator.Index, + Pubkey: validator.Validator.PublicKey, + WithdrawalCredentials: validator.Validator.WithdrawalCredentials, + }) + } + + // Obtain genesis validators root. + genesis, err := c.consensusClient.(consensusclient.GenesisProvider).Genesis(ctx) + if err != nil { + return errors.Wrap(err, "failed to obtain genesis information") + } + c.chainInfo.GenesisValidatorsRoot = genesis.GenesisValidatorsRoot + + // Obtain epoch. + c.chainInfo.Epoch = c.chainTime.CurrentEpoch() + + // Obtain fork version. + forkSchedule, err := c.consensusClient.(consensusclient.ForkScheduleProvider).ForkSchedule(ctx) + if err != nil { + return errors.Wrap(err, "failed to obtain fork schedule") + } + for i := range forkSchedule { + if forkSchedule[i].Epoch <= c.chainInfo.Epoch { + c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion + } + } + + // Calculate domain. + spec, err := c.consensusClient.(consensusclient.SpecProvider).Spec(ctx) + if err != nil { + return errors.Wrap(err, "failed to obtain spec") + } + domainType, exists := spec["DOMAIN_BLS_TO_EXECUTION_CHANGE"].(phase0.DomainType) + if !exists { + return errors.New("failed to obtain DOMAIN_BLS_TO_EXECUTION_CHANGE") + } + domainProvider, isProvider := c.consensusClient.(consensusclient.DomainProvider) + if !isProvider { + return errors.New("consensus node does not provide domain information") + } + c.chainInfo.Domain, err = domainProvider.Domain(ctx, domainType, c.chainInfo.Epoch) + if err != nil { + return errors.Wrap(err, "failed to obtain domain") + } + + return nil +} + +// dumpRequiredInformation prepares for an offline run of this command by dumping +// the chain information to a file. +func (c *command) dumpRequiredInformation(ctx context.Context) error { + data, err := json.Marshal(c.chainInfo) if err != nil { return err } + if err := os.WriteFile(offlinePreparationFilename, data, 0600); err != nil { + return err + } + + return nil +} + +func (c *command) generateOperations(ctx context.Context) error { + // Ensure that we are beyond the capella hard fork epoch. + if c.chainTime.CurrentEpoch() < c.chainTime.CapellaInitialEpoch() { + return errors.New("chain not yet activated capella hard fork") + } + + if c.account == "" && c.mnemonic == "" && c.privateKey == "" { + // No input information; fetch the operations from a file. + if err := c.loadOperations(ctx); err == nil { + return nil + } + return fmt.Errorf("no account, mnemonic or private key specified and no %s file found; cannot proceed", changeOperationsFilename) + } + + if c.mnemonic != "" && c.path == "" { + // Have a mnemonic and no path; scan mnemonic. + return c.generateOperationsFromMnemonic(ctx) + } + + if c.mnemonic != "" && c.path != "" { + // Have a mnemonic and path. + return c.generateOperationsFromMnemonicAndPath(ctx) + } + + // Have a validator index or public key ; fetch the validator info. + validatorInfo, err := c.fetchValidatorInfo(ctx) + if err != nil { + return err + } + + // Fetch the individual account. + withdrawalAccount, err := c.fetchAccount(ctx) + if err != nil { + return err + } + + // Generate the operation. + if err := c.generateOperationFromAccount(ctx, validatorInfo, withdrawalAccount); err != nil { + return err + } + + return nil +} + +func (c *command) loadChainInfo(ctx context.Context) error { + _, err := os.Stat(offlinePreparationFilename) + if err != nil { + if c.debug { + fmt.Printf("Failed to read offline preparation file: %v\n", err) + } + } + + if c.debug { + fmt.Printf("%s found; loading chain state\n", offlinePreparationFilename) + } + data, err := os.ReadFile(offlinePreparationFilename) + if err != nil { + return errors.Wrap(err, "failed to read offline preparation file") + } + if err := json.Unmarshal(data, c.chainInfo); err != nil { + return errors.Wrap(err, "failed to parse offline preparation file") + } + + return nil +} + +func (c *command) loadOperations(ctx context.Context) error { + _, err := os.Stat(changeOperationsFilename) + if err != nil { + if c.debug { + fmt.Printf("Failed to read change operations file: %v\n", err) + } + return err + } + + if c.debug { + fmt.Printf("%s found; loading operations\n", changeOperationsFilename) + } + data, err := os.ReadFile(changeOperationsFilename) + if err != nil { + return errors.Wrap(err, "failed to read change operations file") + } + if err := json.Unmarshal(data, &c.signedOperations); err != nil { + return errors.Wrap(err, "failed to parse change operations file") + } + + return nil +} + +func (c *command) generateOperationsFromMnemonic(ctx context.Context) error { + seed, err := util.SeedFromMnemonic(c.mnemonic) + if err != nil { + return err + } + + // Turn the validators in to a map for easy lookup. + validators := make(map[string]*validatorInfo, 0) + for _, validator := range c.chainInfo.Validators { + validators[fmt.Sprintf("%#x", validator.Pubkey)] = validator + } + + maxDistance := 1024 + // Start scanning the validator keys. + lastFoundIndex := 0 + for i := 0; ; i++ { + if i-lastFoundIndex > maxDistance { + if c.debug { + fmt.Printf("Gone %d indices without finding a validator, not scanning any further\n", maxDistance) + } + break + } + validatorKeyPath := fmt.Sprintf("m/12381/3600/%d/0/0", i) + + found, err := c.generateOperationFromSeedAndPath(ctx, validators, seed, validatorKeyPath) + if err != nil { + return errors.Wrap(err, "failed to generate operation from seed and path") + } + if found { + lastFoundIndex = i + } + } + return nil +} + +func (c *command) generateOperationFromSeedAndPath(ctx context.Context, + validators map[string]*validatorInfo, + seed []byte, + path string, +) ( + bool, + error, +) { + validatorPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, path) + if err != nil { + return false, errors.Wrap(err, "failed to generate validator private key") + } + validatorPubkey := fmt.Sprintf("%#x", validatorPrivkey.PublicKey().Marshal()) + validator, exists := validators[validatorPubkey] + if !exists { + if c.debug { + fmt.Printf("No validator found with public key %s at path %s\n", validatorPubkey, path) + } + return false, nil + } + + if c.verbose { + fmt.Printf("Validator %d found with public key %s at path %s\n", validator.Index, validatorPubkey, path) + } + + if validator.WithdrawalCredentials[0] != byte(0) { + if c.debug { + fmt.Printf("Validator %s has non-BLS withdrawal credentials %#x\n", validatorPubkey, validator.WithdrawalCredentials) + } + return false, nil + } + + // Recreate the withdrawal credentials to ensure a match. + withdrawalKeyPath := strings.TrimSuffix(path, "/0") + withdrawalPrivkey, err := ethutil.PrivateKeyFromSeedAndPath(seed, withdrawalKeyPath) + if err != nil { + return false, errors.Wrap(err, "failed to generate withdrawal private key") + } + withdrawalPubkey := withdrawalPrivkey.PublicKey() + withdrawalCredentials := ethutil.SHA256(withdrawalPubkey.Marshal()) + withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX + if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) { + if c.verbose { + fmt.Printf("Validator %s withdrawal credentials %#x do not match expected credentials, cannot update\n", validatorPubkey, validator.WithdrawalCredentials) + } + return false, nil + } + + if c.debug { + fmt.Printf("Validator %s eligible for setting credentials\n", validatorPubkey) + } + + withdrawalAccount, err := util.ParseAccount(ctx, c.mnemonic, []string{withdrawalKeyPath}, true) + if err != nil { + return false, errors.Wrap(err, "failed to create withdrawal account") + } + + err = c.generateOperationFromAccount(ctx, validator, withdrawalAccount) + if err != nil { + return false, err + } + + return true, nil +} + +func (c *command) generateOperationFromAccount(ctx context.Context, + validator *validatorInfo, + withdrawalAccount e2wtypes.Account, +) error { + signedOperation, err := c.createSignedOperation(ctx, validator, withdrawalAccount) + if err != nil { + return err + } + c.signedOperations = append(c.signedOperations, signedOperation) + return nil +} + +func (c *command) createSignedOperation(ctx context.Context, + validator *validatorInfo, + withdrawalAccount e2wtypes.Account, +) ( + *capella.SignedBLSToExecutionChange, + error, +) { + pubkey, err := util.BestPublicKey(withdrawalAccount) + if err != nil { + return nil, err + } blsPubkey := phase0.BLSPubKey{} copy(blsPubkey[:], pubkey.Marshal()) - withdrawalAddressBytes, err := hex.DecodeString(strings.TrimPrefix(c.withdrawalAddress, "0x")) + if err := c.parseWithdrawalAddress(ctx); err != nil { + return nil, errors.Wrap(err, "invalid withdrawal address") + } + + operation := &capella.BLSToExecutionChange{ + ValidatorIndex: validator.Index, + FromBLSPubkey: blsPubkey, + ToExecutionAddress: c.withdrawalAddress, + } + root, err := operation.HashTreeRoot() + if err != nil { + return nil, errors.Wrap(err, "failed to generate root for credentials change operation") + } + + // Sign the operation. + signature, err := signing.SignRoot(ctx, withdrawalAccount, nil, root, c.chainInfo.Domain) + if err != nil { + return nil, errors.Wrap(err, "failed to sign credentials change operation") + } + + return &capella.SignedBLSToExecutionChange{ + Message: operation, + Signature: signature, + }, nil +} + +func (c *command) parseWithdrawalAddress(ctx context.Context) error { + withdrawalAddressBytes, err := hex.DecodeString(strings.TrimPrefix(c.withdrawalAddressStr, "0x")) if err != nil { return errors.Wrap(err, "failed to obtain execution address") } @@ -98,154 +420,70 @@ func (c *command) obtainOp(ctx context.Context) error { } // Ensure the address is properly checksummed. checksummedAddress := addressBytesToEIP55(withdrawalAddressBytes) - if checksummedAddress != c.withdrawalAddress { + if checksummedAddress != c.withdrawalAddressStr { return fmt.Errorf("withdrawal address checksum does not match (expected %s)", checksummedAddress) } - withdrawalAddress := bellatrix.ExecutionAddress{} - copy(withdrawalAddress[:], withdrawalAddressBytes) - - if c.offline { - err = c.obtainOpOffline(ctx, blsPubkey, withdrawalAddress) - } else { - err = c.obtainOpOnline(ctx, blsPubkey, withdrawalAddress) - } - if err != nil { - return errors.Wrap(err, "failed to obtain operation") - } - - root, err := c.op.HashTreeRoot() - if err != nil { - return errors.Wrap(err, "failed to generate root for credentials change operation") - } - - // Sign the operation. - signature, err := signing.SignRoot(ctx, c.withdrawalAccount, nil, root, c.domain) - if err != nil { - return errors.Wrap(err, "failed to sign credentials change operation") - } - - c.signedOp = &capella.SignedBLSToExecutionChange{ - Message: c.op, - Signature: signature, - } + copy(c.withdrawalAddress[:], withdrawalAddressBytes) return nil } -func (c *command) obtainOpOffline(ctx context.Context, - pubkey phase0.BLSPubKey, - withdrawalAddress bellatrix.ExecutionAddress, -) error { - if c.validator == "" { - return errors.New("validator index must be supplied when offline") - } - validatorIndex, err := strconv.ParseUint(c.validator, 10, 64) - if err != nil { - return errors.Wrap(err, "validator must be an index when offline") +func (c *command) validateOperations(ctx context.Context) (bool, string) { + // Turn the validators in to a map for easy lookup. + validators := make(map[phase0.ValidatorIndex]*validatorInfo, 0) + for _, validator := range c.chainInfo.Validators { + validators[validator.Index] = validator } - if c.forkVersion == "" { - return errors.New("fork version must be supplied when offline") + for _, signedOperation := range c.signedOperations { + if validated, reason := c.validateOperation(ctx, validators, signedOperation); !validated { + return validated, reason + } } - forkVersionBytes, err := hex.DecodeString(strings.TrimPrefix(c.forkVersion, "0x")) - if err != nil { - return errors.Wrap(err, "fork version invalid") - } - if len(forkVersionBytes) != phase0.ForkVersionLength { - return errors.New("fork version incorrect length") - } - forkVersion := phase0.Version{} - copy(forkVersion[:], forkVersionBytes) - - if c.genesisValidatorsRoot == "" { - return errors.New("genesis validators root must be supplied when offline") - } - genesisValidatorsRootBytes, err := hex.DecodeString(strings.TrimPrefix(c.genesisValidatorsRoot, "0x")) - if err != nil { - return errors.Wrap(err, "genesis validators root invalid") - } - if len(genesisValidatorsRootBytes) != phase0.RootLength { - return errors.New("genesis validators root incorrect length") - } - genesisValidatorsRoot := phase0.Root{} - copy(genesisValidatorsRoot[:], genesisValidatorsRootBytes) - - // Generate the domain. - forkData := &phase0.ForkData{ - CurrentVersion: forkVersion, - GenesisValidatorsRoot: genesisValidatorsRoot, - } - root, err := forkData.HashTreeRoot() - if err != nil { - return errors.Wrap(err, "failed to calculate signature domain") - } - c.domain = phase0.Domain{} - copy(c.domain[:], []byte{0x0a, 0x00, 0x00, 0x00}) // DOMAIN_BLS_TO_EXECUTION_CHANGE. - copy(c.domain[4:], root[:]) - - // Generate the change operation. - c.op = &capella.BLSToExecutionChange{ - ValidatorIndex: phase0.ValidatorIndex(validatorIndex), - FromBLSPubkey: pubkey, - ToExecutionAddress: withdrawalAddress, - } - - return nil + return true, "" } -func (c *command) obtainOpOnline(ctx context.Context, - pubkey phase0.BLSPubKey, - withdrawalAddress bellatrix.ExecutionAddress, -) error { - // Ensure the validator is correct and suitable. - if err := c.fetchChainInfo(ctx); err != nil { - return err - } - // TODO Move to broadcast. - if c.validatorInfo.Validator.WithdrawalCredentials[0] != 0x00 { - return errors.New("validator withdrawal credentials are not using BLS; cannot change") - } - { - // TODO remove. - x, _ := json.Marshal(c.validatorInfo) - fmt.Printf("%s\n", string(x)) - } - - // Generate the change operation. - c.op = &capella.BLSToExecutionChange{ - ValidatorIndex: c.validatorInfo.Index, - FromBLSPubkey: pubkey, - ToExecutionAddress: withdrawalAddress, - } - - return nil -} - -func (c *command) validateOp(ctx context.Context, +func (c *command) validateOperation(ctx context.Context, + validators map[phase0.ValidatorIndex]*validatorInfo, + signedOperation *capella.SignedBLSToExecutionChange, ) ( bool, string, ) { - // Confirm that the public key hashes to the existing withdrawal credentials (if available). - if c.validatorInfo != nil { - pubkey, err := util.BestPublicKey(c.withdrawalAccount) - if err != nil { - return false, "failed to obtain a public key for the withdrawal account" - } - blsHash := ethutil.Keccak256(pubkey.Marshal()) - // TODO remove. - fmt.Printf("BLS pub key is %#x, hash is %#x\n", pubkey, blsHash) - if !bytes.Equal(blsHash[1:], c.validatorInfo.Validator.WithdrawalCredentials[:]) { - return false, "validator withdrawal credentials do not match current withdrawal credentials" + validator, exists := validators[signedOperation.Message.ValidatorIndex] + if !exists { + return false, "validator not known on chain" + } + if c.debug { + fmt.Printf("Credentials change operation: %v", signedOperation) + fmt.Printf("On-chain validator info: %v\n", validator) + } + + if validator.WithdrawalCredentials[0] != byte(0) { + return false, "validator is not using BLS withdrawal credentials" + } + + withdrawalCredentials := ethutil.SHA256(signedOperation.Message.FromBLSPubkey[:]) + withdrawalCredentials[0] = byte(0) // BLS_WITHDRAWAL_PREFIX + if !bytes.Equal(withdrawalCredentials, validator.WithdrawalCredentials) { + if c.debug { + fmt.Printf("validator withdrawal credentials %#x do not match calculated operation withdrawal credentials %#x\n", validator.WithdrawalCredentials, withdrawalCredentials) } + return false, "validator withdrawal credentials do not match those in the operation" } return true, "" } -func (c *command) broadcastOp(ctx context.Context) error { - // Broadcast the operation. - return c.consensusClient.(consensusclient.BLSToExecutionChangeSubmitter).SubmitBLSToExecutionChange(ctx, c.signedOp) +func (c *command) broadcastOperations(ctx context.Context) error { + // Broadcast the operations. + for _, signedOperation := range c.signedOperations { + if err := c.consensusClient.(consensusclient.BLSToExecutionChangeSubmitter).SubmitBLSToExecutionChange(ctx, signedOperation); err != nil { + return err + } + } + + return nil } func (c *command) setup(ctx context.Context) error { @@ -253,9 +491,8 @@ func (c *command) setup(ctx context.Context) error { return nil } - var err error - // Connect to the consensus node. + var err error c.consensusClient, err = util.ConnectToBeaconNode(ctx, c.connection, c.timeout, c.allowInsecureConnections) if err != nil { return errors.Wrap(err, "failed to connect to consensus node") @@ -274,59 +511,74 @@ func (c *command) setup(ctx context.Context) error { return nil } -func (c *command) fetchChainInfo(ctx context.Context) error { - var err error - - // Obtain the validators provider. - validatorsProvider, isProvider := c.consensusClient.(consensusclient.ValidatorsProvider) - if !isProvider { - return errors.New("consensus node does not provide validator information") +func (c *command) fetchValidatorInfo(ctx context.Context) (*validatorInfo, error) { + var validatorInfo *validatorInfo + switch { + case c.validator == "": + return nil, errors.New("no validator specified") + case strings.HasPrefix(c.validator, "0x"): + // A public key + for _, validator := range c.chainInfo.Validators { + if strings.EqualFold(c.validator, fmt.Sprintf("%#x", validator.Pubkey)) { + validatorInfo = validator + break + } + } + case strings.Contains(c.validator, "/"): + // An account. + _, account, err := util.WalletAndAccountFromPath(ctx, c.validator) + if err != nil { + return nil, errors.Wrap(err, "unable to obtain account") + } + accPubKey, err := util.BestPublicKey(account) + if err != nil { + return nil, errors.Wrap(err, "unable to obtain public key for account") + } + pubkey := fmt.Sprintf("%#x", accPubKey.Marshal()) + for _, validator := range c.chainInfo.Validators { + if strings.EqualFold(pubkey, fmt.Sprintf("%#x", validator.Pubkey)) { + validatorInfo = validator + break + } + } + default: + // An index. + index, err := strconv.ParseUint(c.validator, 10, 64) + if err != nil { + return nil, errors.Wrap(err, "failed to parse validator index") + } + validatorIndex := phase0.ValidatorIndex(index) + for _, validator := range c.chainInfo.Validators { + if validator.Index == validatorIndex { + validatorInfo = validator + break + } + } } - c.validatorInfo, err = util.ParseValidator(ctx, validatorsProvider, c.validator, "head") - if err != nil { - return errors.Wrap(err, "failed to obtain validator") + if validatorInfo == nil { + return nil, errors.New("unknown validator") } - epoch := c.chainTime.CurrentEpoch() - - // Obtain the domain type. - spec, err := c.consensusClient.(consensusclient.SpecProvider).Spec(ctx) - if err != nil { - return errors.Wrap(err, "failed to obtain spec") - } - domainType, exists := spec["DOMAIN_BLS_TO_EXECUTION_CHANGE"].(phase0.DomainType) - if !exists { - return errors.New("failed to obtain DOMAIN_BLS_TO_EXECUTION_CHANGE") - } - - domainProvider, isProvider := c.consensusClient.(consensusclient.DomainProvider) - if !isProvider { - return errors.New("consensus node does not provide domain information") - } - c.domain, err = domainProvider.Domain(ctx, domainType, epoch) - if err != nil { - return errors.Wrap(err, "failed to obtain domain") - } - - return nil + return validatorInfo, nil } -func (c *command) fetchAccount(ctx context.Context) error { +func (c *command) fetchAccount(ctx context.Context) (e2wtypes.Account, error) { + var account e2wtypes.Account var err error switch { case c.account != "": - c.withdrawalAccount, err = util.ParseAccount(ctx, c.account, c.passphrases, true) + account, err = util.ParseAccount(ctx, c.account, c.passphrases, true) case c.mnemonic != "": - c.withdrawalAccount, err = util.ParseAccount(ctx, c.mnemonic, []string{c.path}, true) + account, err = util.ParseAccount(ctx, c.mnemonic, []string{c.path}, true) case c.privateKey != "": - c.withdrawalAccount, err = util.ParseAccount(ctx, c.privateKey, nil, true) + account, err = util.ParseAccount(ctx, c.privateKey, nil, true) default: err = errors.New("account, mnemonic or private key must be supplied") } - return err + return account, err } // addressBytesToEIP55 converts a byte array in to an EIP-55 string format. @@ -347,3 +599,28 @@ func addressBytesToEIP55(address []byte) string { return fmt.Sprintf("0x%s", string(bytes)) } + +func (c *command) generateOperationsFromMnemonicAndPath(ctx context.Context) error { + seed, err := util.SeedFromMnemonic(c.mnemonic) + if err != nil { + return err + } + + // Turn the validators in to a map for easy lookup. + validators := make(map[string]*validatorInfo, 0) + for _, validator := range c.chainInfo.Validators { + validators[fmt.Sprintf("%#x", validator.Pubkey)] = validator + } + + validatorKeyPath := c.path + match := validatorPath.Match([]byte(c.path)) + if !match { + return fmt.Errorf("path %s does not match EIP-2334 format", c.path) + } + + if _, err := c.generateOperationFromSeedAndPath(ctx, validators, seed, validatorKeyPath); err != nil { + return errors.Wrap(err, "failed to generate operation from seed and path") + } + + return nil +} diff --git a/cmd/validator/credentials/set/validatorinfo.go b/cmd/validator/credentials/set/validatorinfo.go new file mode 100644 index 0000000..1709b7d --- /dev/null +++ b/cmd/validator/credentials/set/validatorinfo.go @@ -0,0 +1,97 @@ +// Copyright © 2022 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 validatorcredentialsset + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/attestantio/go-eth2-client/spec/phase0" + "github.com/pkg/errors" +) + +type validatorInfo struct { + Index phase0.ValidatorIndex + Pubkey phase0.BLSPubKey + WithdrawalCredentials []byte +} + +type validatorInfoJSON struct { + Index string `json:"index"` + Pubkey string `json:"pubkey"` + WithdrawalCredentials string `json:"withdrawal_credentials"` +} + +// MarshalJSON implements json.Marshaler. +func (v *validatorInfo) MarshalJSON() ([]byte, error) { + return json.Marshal(&validatorInfoJSON{ + Index: fmt.Sprintf("%d", v.Index), + Pubkey: fmt.Sprintf("%#x", v.Pubkey), + WithdrawalCredentials: fmt.Sprintf("%#x", v.WithdrawalCredentials), + }) +} + +// UnmarshalJSON implements json.Unmarshaler. +func (v *validatorInfo) UnmarshalJSON(input []byte) error { + var data validatorInfoJSON + if err := json.Unmarshal(input, &data); err != nil { + return errors.Wrap(err, "invalid JSON") + } + + if data.Index == "" { + return errors.New("index missing") + } + index, err := strconv.ParseUint(data.Index, 10, 64) + if err != nil { + return errors.Wrap(err, "invalid value for index") + } + v.Index = phase0.ValidatorIndex(index) + + if data.Pubkey == "" { + return errors.New("public key missing") + } + pubkey, err := hex.DecodeString(strings.TrimPrefix(data.Pubkey, "0x")) + if err != nil { + return errors.Wrap(err, "invalid value for public key") + } + if len(pubkey) != phase0.PublicKeyLength { + return fmt.Errorf("incorrect length %d for public key", len(pubkey)) + } + copy(v.Pubkey[:], pubkey) + + if data.WithdrawalCredentials == "" { + return errors.New("withdrawal credentials missing") + } + v.WithdrawalCredentials, err = hex.DecodeString(strings.TrimPrefix(data.WithdrawalCredentials, "0x")) + if err != nil { + return errors.Wrap(err, "invalid value for withdrawal credentials") + } + if len(v.WithdrawalCredentials) != phase0.HashLength { + return fmt.Errorf("incorrect length %d for withdrawal credentials", len(v.WithdrawalCredentials)) + } + + return nil +} + +// String implements the Stringer interface. +func (v *validatorInfo) String() string { + data, err := json.Marshal(v) + if err != nil { + return fmt.Sprintf("Err: %v\n", err) + } + return string(data) +} diff --git a/cmd/validatorcredentialsset.go b/cmd/validatorcredentialsset.go index e72beb4..9bdebc5 100644 --- a/cmd/validatorcredentialsset.go +++ b/cmd/validatorcredentialsset.go @@ -24,15 +24,16 @@ import ( var validatorCredentialsSetCmd = &cobra.Command{ Use: "set", Short: "Set withdrawal credentials for an Ethereum consensus validator", - Long: `Set withdrawal credentials for an Ethereum consensus validator. For example: + Long: `Set withdrawal credentials for an Ethereum consensus validator via a "change credentials" operation. For example: - ethdo validator credentials set --validator=primary/validator --execution-address=0x00...13 --private-key=0x00...1f + ethdo validator credentials set --validator=primary/validator --withdrawal-address=0x00...13 --private-key=0x00...1f -The existing account can be specified in one of three ways: +The existing account can be specified in one of a number of ways: - - private key using --private-key - - account and passphrase using --account and --passphrase - - mnemonic and path using --mnemonic and --path + - mnemonic using --mnemonic; this will scan the mnemonic and generate all required operations + - mnemonic and path to the validator key using --mnemonic and --path; this will generate a single operation + - private key using --private-key; this will generate a single operation + - account and passphrase using --account and --passphrase; this will generate a single operation In quiet mode this will return 0 if the credentials operation has been generated (and successfully broadcast if online), otherwise 1.`, RunE: func(cmd *cobra.Command, args []string) error { @@ -53,6 +54,7 @@ In quiet mode this will return 0 if the credentials operation has been generated func init() { validatorCredentialsCmd.AddCommand(validatorCredentialsSetCmd) validatorCredentialsFlags(validatorCredentialsSetCmd) + validatorCredentialsSetCmd.Flags().Bool("prepare-offline", false, "Create files for offline use") validatorCredentialsSetCmd.Flags().String("validator", "", "Validator for which to set validator credentials") validatorCredentialsSetCmd.Flags().String("withdrawal-address", "", "Execution address to which to direct withdrawals") validatorCredentialsSetCmd.Flags().String("signed-operation", "", "Use pre-defined JSON signed operation as created by --json to transmit the credentials change operation") @@ -63,6 +65,9 @@ func init() { } func validatorCredentialsSetBindings() { + if err := viper.BindPFlag("prepare-offline", validatorCredentialsSetCmd.Flags().Lookup("prepare-offline")); err != nil { + panic(err) + } if err := viper.BindPFlag("validator", validatorCredentialsSetCmd.Flags().Lookup("validator")); err != nil { panic(err) } diff --git a/docs/changingwithdrawalcredentials.md b/docs/changingwithdrawalcredentials.md index d9bb7ab..0b0e869 100644 --- a/docs/changingwithdrawalcredentials.md +++ b/docs/changingwithdrawalcredentials.md @@ -1,13 +1,54 @@ # Changing withdrawal credentials When creating a validator it is possible to set its withdrawal credentials to those based upon a BLS private key (known as BLS withdrawal credentials, or "type 0" withdrawal credentials) or based upon an Ethereum execution address (known as execution withdrawal credentials, or "type 1" withdrawal credentials). With the advent of the Capella hard fork, it is possible for rewards accrued on the consensus chain (also known as the beacon chain) to be sent to the execution chain. However, for this to occur the validator's withdrawal credentials must be type 1. Capella also brings a mechanism to change existing type 0 withdrawal credentials to type 1 withdrawal credentials, and this document outlines the process to change withdrawal credentials from type 0 to type 1 so that consensus rewards can be accessed. -**Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure you end up with the ability to access the rewards that will be sent to the execution address within the credentials.** +**Once a validator has Ethereum execution credentials set they cannot be changed. Please be careful when following this or any similar process to ensure that you have access to the private key (either as a software file, a hardware key or a mnemonic) of the withdrawal address you use so that you have the ability to access your rewards.** -## Preparing for the process -A number of steps need to be taken to prepare for generating and broadcasting the credentials change operation. +## Concepts +The following concepts are useful when understanding the rest of this guide. -### Accessing the beacon node -`ethdo` requires access to the beacon node at various points during the operation. `ethdo` will attempt to find a local beacon node automatically, but if not then an explicit connection value will be required. To find out if `ethdo` has access to the beacon node run: +### Validator +A validator is a logical entity that secures the Ethereum beacon chain (and hence the execution chain) by proposing blocks and attesting to blocks proposed by other validators. + +### Withdrawal credentials +Withdrawal credentials, held as part of a validator's on-chain definition, define where consensus rewards will be sent. + +### Private key +A private key is a hexadecimal string (_e.g._ 0x010203…a1a2a3) that can be used to generate a public key and (in the case of the execution chain) Ethereum address. + +### Mnemonic +A mnemonic is a 24-word phrase that can be used to generate multiple private keys with the use of _paths_. + +### Path +A path is a string starting with "m" and containing a number of components separated by "/", for example "m/12381/3600/0/0". The process to obtain a key from a mnemonic and path is known as "hierarchical derivation". + +### Withdrawal address +A withdrawal address is an Ethereum execution address that will receive consensus rewards periodically during the operation of the validator and, ultimately, to which the initial deposit will be returned when the validator is exited. It is important to understand that at time of writing this value cannot be changed, so it is critical that one of the following criteria are met: + +- the private keys for the Ethereum address are known +- the Ethereum address is secured by a hardware wallet +- the Ethereum address is that of a smart contract with the ability to withdraw funds + +The execution address must be supplied in [EIP-55](https://eips.ethereum.org/EIPS/eip-55) format, _i.e._ using mixed case for checksum. An example of a mixed-case Ethereum address is `0x8f0844Fd51E31ff6Bf5baBe21DCcf7328E19Fd9F` + +### Online and Offline +An _online_ computer is one that is is connected to the internet. It should be running a consensus node connected to the larger Ethereum network. An online computer is required to carry out the process, to obtain information from the consensus node and to broadcast your actions to the rest of the Ethereum network. + +An _offline_ computer is one that is not connected to the internet. As such, it will not be running a consensus node. It can optionally be used in conjunction with an online computer to provide higher levels of security for your mnemonic or private key, but is less convenient because it requires manual transfer of files from the online computer to the offline computer, and back. + +With only an online computer the flow of information is roughly as follows: + +![Online process](images/credentials-change-online.png) + +Here it can be seen that a copy of `ethdo` with access to private keys connects to a consensus node with access to the internet. Due to its connection to the internet it is possible that the computer on which `ethdo` and the consensus node runs has been compromised, and as such would expose the private keys to an attacker. + +With both an offline and an online computer the flow of information is roughly as follows: + +![Offline process](images/credentials-change-offline.png) + +Here the copy of `ethdo` with access to private keys is on an offline computer, which protects it from being compromised via the internet. Data is physically moved from the offline to the online computer via a USB storage key or similar, and none of the information on the online computer is sensitive. + +## Preparation +Regardless of the method selected, preparation must take place on the online computer to ensure that `ethdo` can access your consensus node. `ethdo` will attempt to find a local consensus node automatically, but if not then an explicit connection value will be required. To find out if `ethdo` has access to the consensus node run: ``` ethdo node info --verbose @@ -22,235 +63,144 @@ Syncing: false It is important to confirm that the "Syncing" value is "false". If this is "true" it means that the node is currently syncing, and you will need to wait for the process to finish before proceeding. -If this command instead returns an error you will need to add an explicit connection string. For example, if your beacon node is serving its REST API on port 12345 then you should add `--connection=http://localhost:12345` to all `ethdo` commands in this process, for example: +If this command instead returns an error you will need to add an explicit connection string. For example, if your consensus node is serving its REST API on port 12345 then you should add `--connection=http://localhost:12345` to all `ethdo` commands in this process, for example: ```sh ethdo --connection=http://localhost:12345 node info --verbose ``` -Note that some beacon nodes may require configuration to serve their REST API. Please refer to the documentation of your specific beacon node to enable this. +Note that some consensus nodes may require configuration to serve their REST API. Please refer to the documentation of your specific consensus node to enable this. + +Once the preparation is complete you should select either basic or advanced operation, depending on your requirements. + +## Basic operation +Given the above concepts, the purpose of this guide is to allow a change of validators' withdrawal credentials to be changed to a withdrawal address, allowing validator rewards to be accessed on the Ethereum execution chain. + +Basic operation is suitable in the majority of cases. If you: + +- generated your validators using a mnemonic (_e.g._ using the deposit CLI or launchpad) +- want to change all of your validators to have the same withdrawal address +- want to change all of your validators' withdrawal credentials at the same time + +then this method is for you. If any of the above does not apply then please go to the "Advanced operation" section. + +### Online process +The online process generates and broadcasts the operations to change withdrawal credentials for all of your validators tied to a mnemonic in a single action. + +Two pieces of information are required for carrying out this process online: the mnemonic and withdrawal address. + +On your _online_ computer run the following: + +``` +ethdo validator credentials set --mnemonic="abandon abandon abandon … art" --withdrawal-address=0x0123…cdef +``` + +Replacing the `mnemonic` and `withdrawal-address` values with your own values. This command will: + +1. obtain information from your consensus node about all currently-running validators and various additional information required to generate the operations +2. scan your mnemonic to find any validators that were generated by it, and create the operations to change their credentials +3. broadcast the credentials change operations to the Ethereum network + +### Online and Offline process +The online and offline process contains three steps. In the first, data is gathered on the online computer. In the second, the credentials change operations are generated on the offline computer. In the third, the operations are broadcast on the online computer. + +Two pieces of information are required for carrying out this process online: the mnemonic and withdrawal address. + +On your _online_ computer run the following: + +``` +ethdo validator credentials set --prepare-offline +``` + +This command will: + +1. obtain information from your consensus node about all currently-running validators and various additional information required to generate the operations +2. write this information to a file called `offline-preparation.json` + +The `offline-preparation.json` file must be copied to your _offline_ computer. Once this has been done, on your _offline_ computer run the following: + +``` +ethdo validator credentials set --offline --mnemonic="abandon abandon abandon … art" --withdrawal-address=0x0123…cdef +``` + +Replacing the `mnemonic` and `withdrawal-address` values with your own values. This command will: + +1. read the `offline-preparation.json` file to obtain information about all currently-running validators and various additional information required to generate the operations +2. scan your mnemonic to find any validators that were generated by it, and create the operations to change their credentials +3. write this information to a file called `change-operations.json` + +The `change-operations.json` file must be copied to your _online_ computer. Once this has been done, on your _online_ computer run the following: + +``` +ethdo validator credentials set +``` + +This command will: + +1. read the `change-operations.json` file to obtain the operations to change the validators' credentials +2. broadcast the credentials change operations to the Ethereum network + +## Advanced operation +Advanced operation is required when any of the following conditions are met: + +- your validators were created using something other than the deposit CLI or launchpad (_e.g._ `ethdo`) +- you want to set your validators to have different withdrawal addresses +- you want to change your validators' withdrawal credentials individually ### Validator reference There are three options to reference a validator: - the `ethdo` account of the validator (in format wallet/account) - the validator's public key (in format 0x…) -- the validator's index (in format 123…) +- the validator's on-chain index (in format 123…) Any of these can be passed to the following commands with the `--validator` parameter. You need to ensure that you have this information before starting the process. **In the following examples we will use the validator with index 123. Please replace this with the reference to your validator in all commands.** -### Execution address -The execution address will be the address to which all Ether held by the validator from the consensus chain will be sent. It is important to understand that at time of writing this value cannot be changed, so it is critical that one of the following criteria are met: +### Withdrawal address +The withdrawal address is defined above in the concepts section. -- the private keys for the Ethereum address are known -- the Ethereum address is secured by a hardware wallet -- the Ethereum address is that of a smart contract with the ability to withdraw funds +**In the following examples we will use a withdrawal address of 0x8f…9F. Please replace this with the your withdrawal address in all commands.** -The execution address must be supplied in [EIP-55](https://eips.ethereum.org/EIPS/eip-55) format, _i.e._ using mixed case for checksum. An example of a mixed-case Ethereum address is `0x8f0844Fd51E31ff6Bf5baBe21DCcf7328E19Fd9F` +### Generating credentials change operations +Note that if you are carrying out this process offline then you still need to carry out the first and third steps outlined in the "Basic operation" section above. This is to ensure that the offline computer has the correct information to generate the operations, and that the operations are made available to the online computer for broadcasting to the network. -**In the following examples we will use an execution address of 0x8f…9F. Please replace this with the your execution address in all commands.** +If using the online and offline process run the commands below on the offline computer, and add the `--offline` flag to the commands below. You will need to copy the resultant `change-operations.json` file to the online computer to broadcast to the network. -### Online or offline -It is possible to generate the withdrawal credentials change operation either online or offline. +If using the online process run the commands below on the online computer. The operation will be broadcast to the network automatically. -In _online_ mode the credentials will be generated on a server that has both access to the internet and access to the private keys of the existing withdrawal credentials. This is the easiest process, however due to it involving private keys on a computer connected to the internet some consider this insecure. - -In _offline_ mode there are two servers: one with access to the internet, and one with access to the private keys. This is the most secure process, however requires additional steps to accomplish. - -It is a personal choice as to if an online or offline method is chosen to generate the credentials change operation. Instructions for both methods are present. - -## The process -### Check your current validator credentials -The first step will be to confirm that the validator can be found on-chain. To do so, run the following command: - -```sh -ethdo validator credentials get --validator=123 -``` - -This should return information similar to the following: - -``` -BLS credentials: 0x00ebf119d469a31ff2a534d176e6d594046a2367f7a36848009f70f3cb9a9dd1 -``` - -This result should start with the phrase "BLS credentials", which means that these credentials must be upgraded to an Ethereum execution address to receive withdrawals. If instead the result starts with the phrase "Ethereum execution address" it means that the credentials are already set to an Ethereum execution address and no further action is necessary (or possible). - - -Once you have the correct information to refer to your validator you can generate the credentials change operation. - -### Generate and publish the credentials change operation (online) -The steps for generating and publishing the credentials change operation online depend on the method by which you access your current withdrawal key. - -#### Using a mnemonic -Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a _path_. Commonly, keys will have been generated using two paths: +#### Using a mnemonic and path. +A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a _path_. Commonly, keys will have been generated using two paths: - m/12381/3600/_i_/0 is the path to a withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ - m/12381/3600/_i_/0/0 is the path to a validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ -The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: +however this is only a standard and not a restriction, and it is possible for users to have created validators using paths of their own choice. ``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0/0' +ethdo validator credentials set --validator=123 --mnemonic="abandon abandon abandon … art" --path='m/12381/3600/0/0/0' --withdrawal-address=0x0123…cdef ``` -replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: - -``` -Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726dbfc3c7463884c68a531515aab94c87 -``` - -The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. - -Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do so run: - -``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0' --show-withdrawal-credentials -``` - -again replacing the first '0' in the path with the validator number. This will provide an output similar to: - -``` -Withdrawal credentials: 0x008ba1cc4b091b91c1202bba3f508075d6ff565c77e559f0803c0792e0302bf1 -``` - -The displayed withdrawal credentials should match the current withdrawal credentials of your validator (note that these were obtained in an earlier step so you can use the output there to confirm that they match). If not, then do not proceed further and obtain help to understand why there is a mismatch. - -Once you are comfortable that the mnemonic and path provide the correct result you can generate and broadcast the credentials change operation with the following command: - -``` -ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/3600/0/0' -``` - -again replacing the first '0' in the path with the validator number. +replacing the path with the path to your _withdrawal_ key, and all other parameters with your own values. #### Using a private key If you have the private key from which the current withdrawal credentials were derived this can be used to generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --private-key=0x3b…9c +ethdo validator credentials set --validator=123 --withdrawal-address=0x8f…9F --private-key=0x3b…9c ``` -using your own private key. +replacing the parameters with your own values. #### Using an account If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate and broadcast the credentials change operation with the following command: ``` -ethdo validator credentials set --validator=123 --execution-address=0x8f…9F --account=Wallet/Account --passphrase=secret +ethdo validator credentials set --validator=123 --withdrawal-address=0x8f…9F --account=Wallet/Account --passphrase=secret ``` -using your own account and passphrase. - -### Generate the credentials change operation (offline) -Generating the credentials change operation offline requires information from the online component and is more involved than the online process, however does not expose mnemonics, private keys, or passphrases to servers that are connected to the internet. The process is below. - -#### Obtain data required for offline generation. -Generating the credentials change operation requires information that comes from an online beacon node. As such, on your _online_ server you need to run the following command: - -``` -ethdo chain info --prepare-offline -``` - -This will return something similar to the following response: - -``` -Add the following to your command to run it offline: - --offline --genesis-validators=root=0x043db0d9a83813551ee2f33450d23797757d430911a9320530ad8a0eabc43efb --fork-version=0x03001020 -``` - -This information needs to be copied to your offline server to continue. - -#### Generate signed operation -Generating the signed operation offline is different from the online operation in that it will produce an output that can be copied to the online server for broadcast. Separating generation from broadcast allows the offline server to remain securely disconnected from the internet. The generation steps should be run on the _offline_ server. - -#### Using a mnemonic -Many stakers will have generated their validators from a mnemonic. A mnemonic is a 24-word phrase from which withdrawal and validator keys are derived using a path. - -- m/12381/3600/_i_/0 is the path to the _i_th withdrawal key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ -- m/12381/3600/_i_/0/0 is the path to the _i_th validator key, where _i_ starts at 0 for the first validator, 1 for the second validator, _etc._ - -The first step will be to confirm that the mnemonic provides the appropriate validator key. To do so run: - -``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0/0' -``` - -replacing the first '0' in the path with the validator number (remember that numbering starts at 0 for the first validator). This will provide an output similar to: - -``` -Public key: 0xb384f767d964e100c8a9b21018d08c25ffebae268b3ab6d610353897541971726dbfc3c7463884c68a531515aab94c87 -``` - -The displayed public key should match the public key of the validator of which you are attempting to change the credentials. If not, then do not proceed further and obtain help to understand why there is a mismatch. - -Assuming the displayed public key does match the public key of the validator the next step is to confirm the current withdrawal credentials. To do so run: - -``` -ethdo account derive --mnemonic='abandon … art' --path='m/12381/3600/0/0' --show-withdrawal-credentials -``` - -again replacing the first '0' in the path with the validator number. This will provide an output similar to: - -``` -Public key: 0x99b1f1d84d76185466d86c34bde1101316afddae76217aa86cd066979b19858c2c9d9e56eebc1e067ac54277a61790db -Withdrawal credentials: 0x008ba1cc4b091b91c1202bba3f508075d6ff565c77e559f0803c0792e0302bf1 -``` - -The displayed withdrawal credentials should match the current withdrawal credentials of your validator (note that these were obtained in an earlier step so you can use the output there to confirm that they match). If not, then do not proceed further and obtain help to understand why there is a mismatch. - -Once you are comfortable that the mnemonic and path provide the correct result you can generate the credentials change operation with the following command: - -``` -ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --mnemonic='abandon … art' --path='m/12381/3600/0/0' -``` - -again replacing the first '0' in the path with the validator number, and using your own execution address as explained earlier in the guide. This will produce output similar to the following: - -``` -{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} - -``` - -#### Using a private key -If you have the private key from which the current withdrawal credentials were derived this can be used to generate the credentials change operation with the following command: - -``` -ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --private-key=0x3b…9c -``` - -using your own execution address as explained earlier in the guide, and your own private key. This will produce output similar to the following: - -``` -{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} -``` - -#### Using an account -If you used `ethdo` to generate your validator deposit data you will likely have used a separate account to generate the withdrawal credentials. You can specify the account to generate the credentials change operation with the following command: - -``` -ethdo validator credentials set --offline --genesis-validators=root=0x04…fb --fork-version=0x03…20 --validator=123 --execution-address=0x8f…9F --account=Wallet/Account --passphrase=secret -``` - -setting the execution address, account and passphrase to your own values. This will produce output similar to the following: - -``` -{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"} -``` - -### Broadcasting a previously-generated credentials change operation -An online server can broadcast the result of the previous step. Note that the data does not expose any sensitive information such as private keys, and as such is safe to be accessed by the online server. Broadcasting the operation is a simple case of supplying it to `ethdo`: - -``` -ethdo validator credentials set --signed-operation='{"message":{"validator_index":"123","from_bls_pubkey":"0xad1868210a0cff7aff22633c003c503d4c199c8dcca13bba5b3232fc784d39d3855936e94ce184c3ce27bf15d4347695","to_execution_address":"0x388ea662ef2c223ec0b047d41bf3c0f362142ad5"},"signature":"0x8fcc8ceb75cbea891540150efc7df3e482a74592f89f3fc62a2d034381c776fcd42faad82af7a4af7fb84168a74981ce0ec96cf059e134eaa979c67425138f1915d1a8b1b6056401a9f7a2e79ed673f4b0c6b6ae1f60cff5996318e4769d0642"}' -``` - -Alternatively, if the operation is stored on a filesystem, for example on a USB device from where it was copied from the offline server, it can be accessed with: - -``` -ethdo validator credentials set --signed-operation=/path/to/signed/operation -``` +replacing the parameters with your own values. ## Confirming the process has succeeded The final step is confirming the operation has taken place. To do so, run the following command on an online server: diff --git a/docs/images/credentials-change-offline.png b/docs/images/credentials-change-offline.png new file mode 100644 index 0000000000000000000000000000000000000000..831a16762055195f8f7e790ad30bef99fb71d4b8 GIT binary patch literal 155564 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])&@#T3*jukN__1R##QkVCx*ygi0MVTg{(X&3Bnh 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

g%A`k}DQx9{KY1ns}e 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 literal 0 HcmV?d00001 diff --git a/docs/images/credentials-change-online.png b/docs/images/credentials-change-online.png new file mode 100644 index 0000000000000000000000000000000000000000..15c6f72a41c5f15834ecf9b3e207ea91ca840391 GIT binary patch literal 130765 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�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 literal 0 HcmV?d00001 diff --git a/docs/images/diagrams.svg b/docs/images/diagrams.svg new file mode 100644 index 0000000..a7000f2 --- /dev/null +++ b/docs/images/diagrams.svg @@ -0,0 +1,923 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Localconsensus node + Consensusnetwork + Consensusnetwork + User + + + + + + + + + + + + + + + + ethdo(with keys) + Online + + + diff --git a/services/chaintime/service.go b/services/chaintime/service.go index 911e3ac..6934f0d 100644 --- a/services/chaintime/service.go +++ b/services/chaintime/service.go @@ -54,4 +54,6 @@ type Service interface { AltairInitialEpoch() phase0.Epoch // AltairInitialSyncCommitteePeriod provides the sync committee period in which the Altair hard fork takes place. AltairInitialSyncCommitteePeriod() uint64 + // CapellaInitialEpoch provides the epoch at which the Capella hard fork takes place. + CapellaInitialEpoch() phase0.Epoch } diff --git a/util/account.go b/util/account.go index 78304c3..07a7c48 100644 --- a/util/account.go +++ b/util/account.go @@ -17,14 +17,11 @@ import ( "context" "encoding/hex" "fmt" - "regexp" "strings" "github.com/pkg/errors" - "github.com/tyler-smith/go-bip39" util "github.com/wealdtech/go-eth2-util" e2wtypes "github.com/wealdtech/go-eth2-wallet-types/v2" - "golang.org/x/text/unicode/norm" ) // ParseAccount parses input to obtain an account. @@ -111,27 +108,11 @@ func ParseAccount(ctx context.Context, return account, nil } -// hdPathRegex is the regular expression that matches an HD path. -var hdPathRegex = regexp.MustCompile("^m/[0-9]+/[0-9]+(/[0-9+])+") - func accountFromMnemonicAndPath(mnemonic string, path string) (e2wtypes.Account, error) { - // If there are more than 24 words we treat the additional characters as the passphrase. - mnemonicParts := strings.Split(mnemonic, " ") - mnemonicPassphrase := "" - if len(mnemonicParts) > 24 { - mnemonic = strings.Join(mnemonicParts[:24], " ") - mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ") + seed, err := SeedFromMnemonic(mnemonic) + if err != nil { + return nil, err } - // Normalise the input. - mnemonic = string(norm.NFKD.Bytes([]byte(mnemonic))) - mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase))) - - if !bip39.IsMnemonicValid(mnemonic) { - return nil, errors.New("mnemonic is invalid") - } - - // Create seed from mnemonic and passphrase. - seed := bip39.NewSeed(mnemonic, mnemonicPassphrase) // Ensure the path is valid. match := hdPathRegex.Match([]byte(path)) diff --git a/util/mnemonic.go b/util/mnemonic.go new file mode 100644 index 0000000..2d8e98a --- /dev/null +++ b/util/mnemonic.go @@ -0,0 +1,47 @@ +// Copyright © 2020, 2022 Weald Technology Trading +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package util + +import ( + "regexp" + "strings" + + "github.com/pkg/errors" + "github.com/tyler-smith/go-bip39" + "golang.org/x/text/unicode/norm" +) + +// hdPathRegex is the regular expression that matches an HD path. +var hdPathRegex = regexp.MustCompile("^m/[0-9]+/[0-9]+(/[0-9+])+") + +// SeedFromMnemonic creates a seed from a mnemonic. +func SeedFromMnemonic(mnemonic string) ([]byte, error) { + // If there are more than 24 words we treat the additional characters as the passphrase. + mnemonicParts := strings.Split(mnemonic, " ") + mnemonicPassphrase := "" + if len(mnemonicParts) > 24 { + mnemonic = strings.Join(mnemonicParts[:24], " ") + mnemonicPassphrase = strings.Join(mnemonicParts[24:], " ") + } + // Normalise the input. + mnemonic = string(norm.NFKD.Bytes([]byte(mnemonic))) + mnemonicPassphrase = string(norm.NFKD.Bytes([]byte(mnemonicPassphrase))) + + if !bip39.IsMnemonicValid(mnemonic) { + return nil, errors.New("mnemonic is invalid") + } + + // Create seed from mnemonic and passphrase. + return bip39.NewSeed(mnemonic, mnemonicPassphrase), nil +} From 7eb2c68a19bdf3c27bad24c2ad6e252d63fdf1b7 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Sat, 29 Oct 2022 12:15:14 +0100 Subject: [PATCH 8/8] Update operation and docs. --- cmd/account/derive/output_internal_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/account/derive/output_internal_test.go b/cmd/account/derive/output_internal_test.go index 8bc8c82..aeb98f0 100644 --- a/cmd/account/derive/output_internal_test.go +++ b/cmd/account/derive/output_internal_test.go @@ -64,7 +64,7 @@ func TestOutput(t *testing.T) { key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"), showPrivateKey: true, }, - needs: []string{"Public key", "Private key"}, + needs: []string{"Private key"}, }, { name: "WithdrawalCredentials", @@ -72,7 +72,7 @@ func TestOutput(t *testing.T) { key: blsPrivateKey("0x068dce0c90cb428ab37a74af0191eac49648035f1aaef077734b91e05985ec55"), showWithdrawalCredentials: true, }, - needs: []string{"Public key", "Withdrawal credentials"}, + needs: []string{"Withdrawal credentials"}, }, { name: "All", @@ -81,7 +81,7 @@ func TestOutput(t *testing.T) { showPrivateKey: true, showWithdrawalCredentials: true, }, - needs: []string{"Public key", "Private key", "Withdrawal credentials"}, + needs: []string{"Private key", "Withdrawal credentials"}, }, }