From 16a94d726a6eec2dd0aa355fc1d1265fd8ee7551 Mon Sep 17 00:00:00 2001 From: Jim McDonald Date: Tue, 29 Nov 2022 14:20:46 +0000 Subject: [PATCH] Withdrawal credentials operations in advance. Allow withdrawal credentials change operations to be generated prior to the Capella hard fork, allowing queueing if the beacon node supports it. --- CHANGELOG.md | 3 ++ cmd/validator/credentials/set/process.go | 68 ++++++++++++++++++++---- cmd/validatorcredentialsset.go | 4 +- cmd/version.go | 2 +- 4 files changed, 63 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ecc86..780f5a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +1.26.1 + - add ability to generate validator credentials change operations prior to the fork in which they become usable + 1.26.0 - add commands and documentation to set user validator credentials (not usable until capella) diff --git a/cmd/validator/credentials/set/process.go b/cmd/validator/credentials/set/process.go index 0c2fc89..135924f 100644 --- a/cmd/validator/credentials/set/process.go +++ b/cmd/validator/credentials/set/process.go @@ -114,24 +114,70 @@ func (c *command) populateChainInfo(ctx context.Context) error { } // Obtain genesis validators root. - genesis, err := c.consensusClient.(consensusclient.GenesisProvider).Genesis(ctx) - if err != nil { - return errors.Wrap(err, "failed to obtain genesis information") + if c.genesisValidatorsRoot != "" { + // Genesis validators root supplied manually. + genesisValidatorsRoot, err := hex.DecodeString(strings.TrimPrefix(c.genesisValidatorsRoot, "0x")) + if err != nil { + return errors.Wrap(err, "invalid genesis validators root supplied") + } + if len(genesisValidatorsRoot) != phase0.RootLength { + return errors.New("invalid length for genesis validators root") + } + copy(c.chainInfo.GenesisValidatorsRoot[:], genesisValidatorsRoot) + } else { + // Genesis validators root obtained from beacon node. + 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 + } + if c.debug { + fmt.Printf("Genesis validators root is %#x\n", c.chainInfo.GenesisValidatorsRoot) } - 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 + if c.forkVersion != "" { + // Fork version supplied manually. + forkVersion, err := hex.DecodeString(strings.TrimPrefix(c.forkVersion, "0x")) + if err != nil { + return errors.Wrap(err, "invalid fork version supplied") } + if len(forkVersion) != phase0.ForkVersionLength { + return errors.New("invalid length for fork version") + } + copy(c.chainInfo.ForkVersion[:], forkVersion) + } else { + // Fork version obtained from beacon node. + forkSchedule, err := c.consensusClient.(consensusclient.ForkScheduleProvider).ForkSchedule(ctx) + if err != nil { + return errors.Wrap(err, "failed to obtain fork schedule") + } + if len(forkSchedule) < 4 { + return errors.New("beacon node not providing capella fork schedule; provide manually with --fork-version") + } + for i := range forkSchedule { + // Need to be at least fork 3 (i.e. capella) + if i < 3 { + continue + } + if i == 3 { + // Force use of capella even if we aren't there yet, to allow credential + // change operations to be signed in advance with a signature that will be + // valid once capella goes live. + c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion + continue + } + if forkSchedule[i].Epoch <= c.chainInfo.Epoch { + c.chainInfo.ForkVersion = forkSchedule[i].CurrentVersion + } + } + } + if c.debug { + fmt.Printf("Fork version is %#x\n", c.chainInfo.ForkVersion) } // Calculate domain. diff --git a/cmd/validatorcredentialsset.go b/cmd/validatorcredentialsset.go index 9bdebc5..6febf52 100644 --- a/cmd/validatorcredentialsset.go +++ b/cmd/validatorcredentialsset.go @@ -60,8 +60,8 @@ func init() { 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)") + validatorCredentialsSetCmd.Flags().String("fork-version", "", "Fork version to use for signing (overrides fetching from beacon node)") + validatorCredentialsSetCmd.Flags().String("genesis-validators-root", "", "Genesis validators root to use for signing (overrides fetching from beacon node)") } func validatorCredentialsSetBindings() { diff --git a/cmd/version.go b/cmd/version.go index aab0a29..82f4543 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -24,7 +24,7 @@ import ( // ReleaseVersion is the release version of the codebase. // Usually overridden by tag names when building binaries. -var ReleaseVersion = "local build (latest release 1.26.0)" +var ReleaseVersion = "local build (latest release 1.26.1)" // versionCmd represents the version command var versionCmd = &cobra.Command{