From 685fbf26a35b2f2cb517e15f90d28e08d5d5d419 Mon Sep 17 00:00:00 2001 From: Devon Bear Date: Wed, 11 Sep 2024 17:45:19 -0400 Subject: [PATCH] fix(cli): Re-add create validator (#2004) --- mod/cli/go.mod | 2 +- mod/cli/pkg/commands/deposit/create.go | 169 ++++++++++++++++++++++++ mod/cli/pkg/commands/deposit/deposit.go | 1 + mod/cli/pkg/commands/deposit/errors.go | 6 +- mod/cli/pkg/commands/deposit/flags.go | 56 ++++++++ 5 files changed, 228 insertions(+), 6 deletions(-) create mode 100644 mod/cli/pkg/commands/deposit/create.go create mode 100644 mod/cli/pkg/commands/deposit/flags.go diff --git a/mod/cli/go.mod b/mod/cli/go.mod index de6cd6c740..bed60d46e9 100644 --- a/mod/cli/go.mod +++ b/mod/cli/go.mod @@ -22,6 +22,7 @@ replace ( require ( cosmossdk.io/depinject v1.0.0 + cosmossdk.io/log v1.4.1 github.com/berachain/beacon-kit/mod/config v0.0.0-20240705193247-d464364483df github.com/berachain/beacon-kit/mod/consensus v0.0.0-20240821053614-036c5d2945f0 github.com/berachain/beacon-kit/mod/consensus-types v0.0.0-20240821182712-08bbb9c7d685 @@ -43,7 +44,6 @@ require ( require ( cosmossdk.io/core v1.0.0 // indirect cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect - cosmossdk.io/log v1.4.1 // indirect cosmossdk.io/schema v0.1.1 // indirect github.com/berachain/beacon-kit/mod/beacon v0.0.0-20240821052951-c15422305b4e // indirect github.com/berachain/beacon-kit/mod/chain-spec v0.0.0-20240705193247-d464364483df // indirect diff --git a/mod/cli/pkg/commands/deposit/create.go b/mod/cli/pkg/commands/deposit/create.go new file mode 100644 index 0000000000..e31c31db3f --- /dev/null +++ b/mod/cli/pkg/commands/deposit/create.go @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package deposit + +import ( + "os" + + "cosmossdk.io/log" + "github.com/berachain/beacon-kit/mod/cli/pkg/utils/parser" + "github.com/berachain/beacon-kit/mod/consensus-types/pkg/types" + "github.com/berachain/beacon-kit/mod/node-core/pkg/components" + "github.com/berachain/beacon-kit/mod/node-core/pkg/components/signer" + "github.com/berachain/beacon-kit/mod/primitives/pkg/common" + "github.com/berachain/beacon-kit/mod/primitives/pkg/constraints" + "github.com/berachain/beacon-kit/mod/primitives/pkg/crypto" + "github.com/cosmos/cosmos-sdk/client" + "github.com/spf13/cobra" +) + +// NewCreateValidator creates a new command to create a validator deposit. +func NewCreateValidator[ + ExecutionPayloadT constraints.EngineType[ExecutionPayloadT], +]( + chainSpec common.ChainSpec, +) *cobra.Command { + cmd := &cobra.Command{ + Use: "create-validator", + Short: "Creates a validator deposit", + Long: `Creates a validator deposit with the necessary credentials. The + arguments are expected in the order of withdrawal credentials, deposit + amount, current version, and genesis validator root. If the broadcast + flag is set to true, a private key must be provided to sign the transaction.`, + Args: cobra.ExactArgs(4), //nolint:mnd // The number of arguments. + RunE: createValidatorCmd[ExecutionPayloadT](chainSpec), + } + cmd.Flags().BoolP( + overrideNodeKey, overrideNodeKeyShorthand, + defaultOverrideNodeKey, overrideNodeKeyMsg, + ) + cmd.Flags(). + String(valPrivateKey, defaultValidatorPrivateKey, valPrivateKeyMsg) + + return cmd +} + +// createValidatorCmd returns a command that builds a create validator request. +// + +func createValidatorCmd[ + ExecutionPayloadT constraints.EngineType[ExecutionPayloadT], +]( + chainSpec common.ChainSpec, +) func(*cobra.Command, []string) error { + return func(cmd *cobra.Command, args []string) error { + logger := log.NewLogger(os.Stdout) + + // Get the BLS signer. + blsSigner, err := getBLSSigner(cmd) + if err != nil { + return err + } + + credentials, err := parser.ConvertWithdrawalCredentials(args[0]) + if err != nil { + return err + } + + amount, err := parser.ConvertAmount(args[1]) + if err != nil { + return err + } + + currentVersion, err := parser.ConvertVersion(args[2]) + if err != nil { + return err + } + + genesisValidatorRoot, err := parser.ConvertGenesisValidatorRoot(args[3]) + if err != nil { + return err + } + + // Create and sign the deposit message. + depositMsg, signature, err := types.CreateAndSignDepositMessage( + types.NewForkData(currentVersion, genesisValidatorRoot), + chainSpec.DomainTypeDeposit(), + blsSigner, + credentials, + amount, + ) + if err != nil { + return err + } + + // Verify the deposit message. + if err = depositMsg.VerifyCreateValidator( + types.NewForkData(currentVersion, genesisValidatorRoot), + signature, + chainSpec.DomainTypeDeposit(), + signer.BLSSigner{}.VerifySignature, + ); err != nil { + return err + } + + // If the broadcast flag is not set, output the deposit message and + // signature and return early. + logger.Info( + "Deposit Message CallData", + "pubkey", depositMsg.Pubkey.String(), + "withdrawal credentials", depositMsg.Credentials.String(), + "amount", depositMsg.Amount, + "signature", signature.String(), + ) + + return nil + } +} + +// getBLSSigner returns a BLS signer based on the override commands key flag. +func getBLSSigner( + cmd *cobra.Command, +) (crypto.BLSSigner, error) { + var legacyKey components.LegacyKey + overrideFlag, err := cmd.Flags().GetBool(overrideNodeKey) + if err != nil { + return nil, err + } + + // Build the BLS signer. + if overrideFlag { + var validatorPrivKey string + validatorPrivKey, err = cmd.Flags().GetString(valPrivateKey) + if err != nil { + return nil, err + } + if validatorPrivKey == "" { + return nil, ErrValidatorPrivateKeyRequired + } + legacyKey, err = signer.LegacyKeyFromString(validatorPrivKey) + if err != nil { + return nil, err + } + } + + return components.ProvideBlsSigner( + components.BlsSignerInput{ + AppOpts: client.GetViperFromCmd(cmd), + PrivKey: legacyKey, + }, + ) +} diff --git a/mod/cli/pkg/commands/deposit/deposit.go b/mod/cli/pkg/commands/deposit/deposit.go index 452516eeea..3be682ef98 100644 --- a/mod/cli/pkg/commands/deposit/deposit.go +++ b/mod/cli/pkg/commands/deposit/deposit.go @@ -44,6 +44,7 @@ func Commands[ExecutionPayloadT constraints.EngineType[ExecutionPayloadT]]( cmd.AddCommand( NewValidateDeposit(chainSpec), + NewCreateValidator[ExecutionPayloadT](chainSpec), ) return cmd diff --git a/mod/cli/pkg/commands/deposit/errors.go b/mod/cli/pkg/commands/deposit/errors.go index 90d11fdd43..8b78750cb9 100644 --- a/mod/cli/pkg/commands/deposit/errors.go +++ b/mod/cli/pkg/commands/deposit/errors.go @@ -28,11 +28,7 @@ var ( ErrValidatorPrivateKeyRequired = errors.New( "validator private key required", ) - // ErrDepositTransactionFailed is returned when the deposit transaction - // fails. - ErrDepositTransactionFailed = errors.New( - "deposit transaction failed", - ) + // ErrPrivateKeyRequired is returned when the broadcast flag is set but a // private key is not provided. ErrPrivateKeyRequired = errors.New( diff --git a/mod/cli/pkg/commands/deposit/flags.go b/mod/cli/pkg/commands/deposit/flags.go new file mode 100644 index 0000000000..48096d41ba --- /dev/null +++ b/mod/cli/pkg/commands/deposit/flags.go @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: BUSL-1.1 +// +// Copyright (C) 2024, Berachain Foundation. All rights reserved. +// Use of this software is governed by the Business Source License included +// in the LICENSE file of this repository and at www.mariadb.com/bsl11. +// +// ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY +// TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER +// VERSIONS OF THE LICENSED WORK. +// +// THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF +// LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF +// LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). +// +// TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON +// AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, +// EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND +// TITLE. + +package deposit + +const ( + // overrideNodeKey is the flag for overriding the node key. + overrideNodeKey = "override-node-key" + + // validatorPrivateKey is the flag for the validator private key. + valPrivateKey = "validator-private-key" +) + +const ( + + // overrideNodeKeyShorthand is the shorthand flag for the overrideNodeKey + // flag. + overrideNodeKeyShorthand = "o" +) + +const ( + // defaultOverrideNodeKey is the default value for the overrideNodeKey flag. + defaultOverrideNodeKey = false + + // defaultValidatorPrivateKey is the default value for the + // validatorPrivateKey flag. + defaultValidatorPrivateKey = "" +) + +const ( + // overrideNodeKeyFlagMsg is the usage description for the overrideNodeKey + // flag. + overrideNodeKeyMsg = "override the node private key" + + // valPrivateKeyMsg is the usage description for the + // valPrivateKey flag. + valPrivateKeyMsg = `validator private key. This is required if the + override-node-key flag is set.` +)