From 3ec128b4d1518446daed9ae928969a8ba2ebf544 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 2 Apr 2025 15:03:54 +0000 Subject: [PATCH] feat(client): add default key name (backport #18101) (#24332) Co-authored-by: Julien Robert Co-authored-by: Alex | Interchain Labs --- CHANGELOG.md | 3 +- client/config/config.go | 26 +++++++------ client/config/toml.go | 2 + client/context.go | 75 +++++++++++++++++++++--------------- crypto/keyring/keyring.go | 4 ++ scripts/init-simapp.sh | 1 + x/auth/client/cli/tx_sign.go | 8 +--- x/staking/client/cli/tx.go | 2 - 8 files changed, 70 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b63c204d5f..e687165d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,7 +57,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/auth) [#24030](https://github.com/cosmos/cosmos-sdk/pull/24030) Allow usage of ed25519 keys for transaction signing. * (baseapp) [#24163](https://github.com/cosmos/cosmos-sdk/pull/24163) Add `StreamingManager` to baseapp to extend the abci listeners. * (x/protocolpool) [#23933](https://github.com/cosmos/cosmos-sdk/pull/23933) Add x/protocolpool module. - * x/distribution can now utilize an externally managed community pool. NOTE: this will make the message handlers for FundCommunityPool and CommunityPoolSpend error, as well as the query handler for CommunityPool. + * x/distribution can now utilize an externally managed community pool. NOTE: this will make the message handlers for FundCommunityPool and CommunityPoolSpend error, as well as the query handler for CommunityPool. +* (client) [#18101](https://github.com/cosmos/cosmos-sdk/pull/18101) Add a `keyring-default-keyname` in `client.toml` for specifying a default key name, and skip the need to use the `--from` flag when signing transactions. ### Improvements diff --git a/client/config/config.go b/client/config/config.go index bc428e45cc..82abdbc649 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -8,22 +8,25 @@ import ( "github.com/cosmos/cosmos-sdk/client" ) +// DefaultConfig returns default config for the client.toml func DefaultConfig() *ClientConfig { return &ClientConfig{ - ChainID: "", - KeyringBackend: "os", - Output: "text", - Node: "tcp://localhost:26657", - BroadcastMode: "sync", + ChainID: "", + KeyringBackend: "os", + KeyringDefaultKeyName: "", + Output: "text", + Node: "tcp://localhost:26657", + BroadcastMode: "sync", } } type ClientConfig struct { - ChainID string `mapstructure:"chain-id" json:"chain-id"` - KeyringBackend string `mapstructure:"keyring-backend" json:"keyring-backend"` - Output string `mapstructure:"output" json:"output"` - Node string `mapstructure:"node" json:"node"` - BroadcastMode string `mapstructure:"broadcast-mode" json:"broadcast-mode"` + ChainID string `mapstructure:"chain-id" json:"chain-id"` + KeyringBackend string `mapstructure:"keyring-backend" json:"keyring-backend"` + KeyringDefaultKeyName string `mapstructure:"keyring-default-keyname" json:"keyring-default-keyname"` + Output string `mapstructure:"output" json:"output"` + Node string `mapstructure:"node" json:"node"` + BroadcastMode string `mapstructure:"broadcast-mode" json:"broadcast-mode"` } func (c *ClientConfig) SetChainID(chainID string) { @@ -94,7 +97,8 @@ func ReadFromClientConfig(ctx client.Context) (client.Context, error) { // we need to update KeyringDir field on Client Context first cause it is used in NewKeyringFromBackend ctx = ctx.WithOutputFormat(conf.Output). WithChainID(conf.ChainID). - WithKeyringDir(ctx.HomeDir) + WithKeyringDir(ctx.HomeDir). + WithKeyringDefaultKeyName(conf.KeyringDefaultKeyName) keyring, err := client.NewKeyringFromBackend(ctx, conf.KeyringBackend) if err != nil { diff --git a/client/config/toml.go b/client/config/toml.go index b3ef23ee51..9b9a79b07f 100644 --- a/client/config/toml.go +++ b/client/config/toml.go @@ -19,6 +19,8 @@ const defaultConfigTemplate = `# This is a TOML config file. chain-id = "{{ .ChainID }}" # The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) keyring-backend = "{{ .KeyringBackend }}" +# Default key name, if set, defines the default key to use for signing transaction when the --from flag is not specified +keyring-default-keyname = "{{ .KeyringDefaultKeyName }}" # CLI output format (text|json) output = "{{ .Output }}" # : to CometBFT RPC interface for this chain diff --git a/client/context.go b/client/context.go index 7327d99dfe..3c98d625c3 100644 --- a/client/context.go +++ b/client/context.go @@ -27,37 +27,38 @@ type PreprocessTxFn func(chainID string, key keyring.KeyType, tx TxBuilder) erro // Context implements a typical context created in SDK modules for transaction // handling and queries. type Context struct { - FromAddress sdk.AccAddress - Client CometRPC - GRPCClient *grpc.ClientConn - ChainID string - Codec codec.Codec - InterfaceRegistry codectypes.InterfaceRegistry - Input io.Reader - Keyring keyring.Keyring - KeyringOptions []keyring.Option - Output io.Writer - OutputFormat string - Height int64 - HomeDir string - KeyringDir string - From string - BroadcastMode string - FromName string - SignModeStr string - UseLedger bool - Simulate bool - GenerateOnly bool - Offline bool - SkipConfirm bool - TxConfig TxConfig - AccountRetriever AccountRetriever - NodeURI string - FeePayer sdk.AccAddress - FeeGranter sdk.AccAddress - Viper *viper.Viper - LedgerHasProtobuf bool - PreprocessTxHook PreprocessTxFn + FromAddress sdk.AccAddress + Client CometRPC + GRPCClient *grpc.ClientConn + ChainID string + Codec codec.Codec + InterfaceRegistry codectypes.InterfaceRegistry + Input io.Reader + Keyring keyring.Keyring + KeyringOptions []keyring.Option + KeyringDir string + KeyringDefaultKeyName string + Output io.Writer + OutputFormat string + Height int64 + HomeDir string + From string + BroadcastMode string + FromName string + SignModeStr string + UseLedger bool + Simulate bool + GenerateOnly bool + Offline bool + SkipConfirm bool + TxConfig TxConfig + AccountRetriever AccountRetriever + NodeURI string + FeePayer sdk.AccAddress + FeeGranter sdk.AccAddress + Viper *viper.Viper + LedgerHasProtobuf bool + PreprocessTxHook PreprocessTxFn // IsAux is true when the signer is an auxiliary signer (e.g. the tipper). IsAux bool @@ -180,6 +181,12 @@ func (ctx Context) WithKeyringDir(dir string) Context { return ctx } +// WithKeyringDefaultKeyName returns a copy of the Context with KeyringDefaultKeyName set. +func (ctx Context) WithKeyringDefaultKeyName(keyName string) Context { + ctx.KeyringDefaultKeyName = keyName + return ctx +} + // WithGenerateOnly returns a copy of the context with updated GenerateOnly value func (ctx Context) WithGenerateOnly(generateOnly bool) Context { ctx.GenerateOnly = generateOnly @@ -380,7 +387,13 @@ func (ctx Context) printOutput(out []byte) error { // GetFromFields returns a from account address, account name and keyring type, given either an address or key name. // If clientCtx.Simulate is true the keystore is not accessed and a valid address must be provided // If clientCtx.GenerateOnly is true the keystore is only accessed if a key name is provided +// If from is empty, the default key if specified in the context will be used func GetFromFields(clientCtx Context, kr keyring.Keyring, from string) (sdk.AccAddress, string, keyring.KeyType, error) { + if from == "" && clientCtx.KeyringDefaultKeyName != "" { + from = clientCtx.KeyringDefaultKeyName + _ = clientCtx.PrintString(fmt.Sprintf("No key name or address provided; using the default key: %s\n", clientCtx.KeyringDefaultKeyName)) + } + if from == "" { return nil, "", 0, nil } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index d8fe412d33..e9a3a42eea 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -949,6 +949,10 @@ func (ks keystore) migrate(key string) (*Record, error) { // 1. get the key. item, err := ks.db.Get(key) if err != nil { + if key == fmt.Sprintf(".%s", infoSuffix) { + return nil, errors.New("no key name or address provided; have you forgotten the --from flag?") + } + return nil, wrapKeyNotFound(err, key) } diff --git a/scripts/init-simapp.sh b/scripts/init-simapp.sh index 6913079e0a..e7038522f5 100755 --- a/scripts/init-simapp.sh +++ b/scripts/init-simapp.sh @@ -7,6 +7,7 @@ echo "using $SIMD_BIN" if [ -d "$($SIMD_BIN config home)" ]; then rm -rv $($SIMD_BIN config home); fi $SIMD_BIN config set client chain-id demo $SIMD_BIN config set client keyring-backend test +$SIMD_BIN config set client keyring-default-keyname alice $SIMD_BIN config set app api.enable true $SIMD_BIN keys add alice $SIMD_BIN keys add bob diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 14b21d6bac..91e93cff13 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -60,8 +60,6 @@ account key. It implies --signature-only. flags.AddTxFlagsToCmd(cmd) - _ = cmd.MarkFlagRequired(flags.FlagFrom) - return cmd } @@ -271,7 +269,7 @@ func multisigSign(clientCtx client.Context, txBuilder client.TxBuilder, txFactor txFactory, clientCtx, multisigAddr, - clientCtx.GetFromName(), + clientCtx.FromName, txBuilder, clientCtx.Offline, true, @@ -355,8 +353,6 @@ be generated via the 'multisign' command. cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT") flags.AddTxFlagsToCmd(cmd) - _ = cmd.MarkFlagRequired(flags.FlagFrom) - return cmd } @@ -459,7 +455,7 @@ func signTx(cmd *cobra.Command, clientCtx client.Context, txF tx.Factory, newTx } printSignatureOnly = true } else { - err = authclient.SignTx(txF, clientCtx, clientCtx.GetFromName(), txBuilder, clientCtx.Offline, overwrite) + err = authclient.SignTx(txF, clientCtx, clientCtx.FromName, txBuilder, clientCtx.Offline, overwrite) } if err != nil { return err diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index ce4b57c6fa..f2bdf0f2c6 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -113,8 +113,6 @@ where we can get the pubkey using "%s tendermint show-validator" cmd.Flags().String(FlagNodeID, "", "The node's ID") flags.AddTxFlagsToCmd(cmd) - _ = cmd.MarkFlagRequired(flags.FlagFrom) - return cmd }