diff --git a/client/v2/CHANGELOG.md b/client/v2/CHANGELOG.md index 910698c8c283..1d4daf255c79 100644 --- a/client/v2/CHANGELOG.md +++ b/client/v2/CHANGELOG.md @@ -36,7 +36,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] - + ### Features @@ -47,6 +47,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* [#19646](https://github.com/cosmos/cosmos-sdk/pull/19646) Use keyring from command context. * [#20083](https://github.com/cosmos/cosmos-sdk/pull/20083) Integrate latest version of cosmos-proto and improve version filtering. * [#19618](https://github.com/cosmos/cosmos-sdk/pull/19618) Marshal enum as string in queries. * [#19060](https://github.com/cosmos/cosmos-sdk/pull/19060) Use client context from root (or enhanced) command in autocli commands. @@ -62,6 +63,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* [#19646](https://github.com/cosmos/cosmos-sdk/pull/19646) Remove keyring from `autocli.AppOptions` and `flag.Builder` options. * [#17709](https://github.com/cosmos/cosmos-sdk/pull/17709) Address codecs have been removed from `autocli.AppOptions` and `flag.Builder`. Instead client/v2 uses the address codecs present in the context (introduced in [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503)). ## [v2.0.0-beta.1] - 2023-11-07 diff --git a/client/v2/README.md b/client/v2/README.md index 50d1684c2876..80e6e65e9f3e 100644 --- a/client/v2/README.md +++ b/client/v2/README.md @@ -75,10 +75,10 @@ if err := rootCmd.Execute(); err != nil { ### Keyring -`autocli` uses a keyring for key name resolving and signing transactions. Providing a keyring is optional, but if you want to use the `autocli` generated commands to sign transactions, you must provide a keyring. +`autocli` uses a keyring for key name resolving names and signing transactions. :::tip -This provides a better UX as it allows to resolve key names directly from the keyring in all transactions and commands. +AutoCLI provides a better UX than normal CLI as it allows to resolve key names directly from the keyring in all transactions and commands. ```sh q bank balances alice @@ -87,8 +87,9 @@ This provides a better UX as it allows to resolve key names directly from the ke ::: -The keyring to be provided to `client/v2` must match the `client/v2` keyring interface. -The keyring should be provided in the `appOptions` struct as follows, and can be gotten from the client context: +The keyring used for resolving names and signing transactions is provided via the `client.Context`. +The keyring is then converted to the `client/v2/autocli/keyring` interface. +If no keyring is provided, the `autocli` generated command will not be able to sign transactions, but will still be able to query the chain. :::tip The Cosmos SDK keyring and Hubl keyring both implement the `client/v2/autocli/keyring` interface, thanks to the following wrapper: @@ -99,18 +100,6 @@ keyring.NewAutoCLIKeyring(kb) ::: -:::warning -When using AutoCLI the keyring will only be created once and before any command flag parsing. -::: - -```go -// Set the keyring in the appOptions -appOptions.Keyring = keyring - -err := autoCliOpts.EnhanceRootCommand(rootCmd) -... -``` - ## Signing `autocli` supports signing transactions with the keyring. @@ -255,7 +244,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", @@ -266,7 +255,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json --encoding base64` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", @@ -277,7 +266,7 @@ The `encoding` flag lets you choose how the contents of the file should be encod * `simd off-chain sign-file alice myFile.json --encoding hex` - * ```json + * ```json { "@type": "/offchain.MsgSignArbitraryData", "appDomain": "simd", diff --git a/client/v2/autocli/app.go b/client/v2/autocli/app.go index 9f3207e53afa..ec793eee67fa 100644 --- a/client/v2/autocli/app.go +++ b/client/v2/autocli/app.go @@ -7,7 +7,6 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" "cosmossdk.io/client/v2/autocli/flag" - "cosmossdk.io/client/v2/autocli/keyring" "cosmossdk.io/core/appmodule" "cosmossdk.io/depinject" @@ -35,9 +34,6 @@ type AppOptions struct { // module or need to be improved. ModuleOptions map[string]*autocliv1.ModuleOptions `optional:"true"` - // Keyring is the keyring to use for client/v2. - Keyring keyring.Keyring `optional:"true"` - // ClientCtx contains the necessary information needed to execute the commands. ClientCtx client.Context } @@ -62,7 +58,6 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error { Builder: flag.Builder{ TypeResolver: protoregistry.GlobalTypes, FileResolver: appOptions.ClientCtx.InterfaceRegistry, - Keyring: appOptions.Keyring, AddressCodec: appOptions.ClientCtx.AddressCodec, ValidatorAddressCodec: appOptions.ClientCtx.ValidatorAddressCodec, ConsensusAddressCodec: appOptions.ClientCtx.ConsensusAddressCodec, diff --git a/client/v2/autocli/common.go b/client/v2/autocli/common.go index 99656f4bda72..5c32f16ca32a 100644 --- a/client/v2/autocli/common.go +++ b/client/v2/autocli/common.go @@ -53,14 +53,18 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip Version: options.Version, } - binder, err := b.AddMessageFlags(cmd.Context(), cmd.Flags(), inputType, options) + // we need to use a pointer to the context as the correct context is set in the RunE function + // however we need to set the flags before the RunE function is called + ctx := cmd.Context() + binder, err := b.AddMessageFlags(&ctx, cmd.Flags(), inputType, options) if err != nil { return nil, err } - cmd.Args = binder.CobraArgs cmd.RunE = func(cmd *cobra.Command, args []string) error { + ctx = cmd.Context() + input, err := binder.BuildMessage(args) if err != nil { return err @@ -72,17 +76,12 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip // the client context uses the from flag to determine the signer. // this sets the signer flags to the from flag value if a custom signer flag is set. // marks the custom flag as required. - if binder.SignerInfo.FieldName != flags.FlagFrom { - if err := cmd.MarkFlagRequired(binder.SignerInfo.FieldName); err != nil { + if binder.SignerInfo.FlagName != flags.FlagFrom { + if err := cmd.MarkFlagRequired(binder.SignerInfo.FlagName); err != nil { return err } - signer, err := cmd.Flags().GetString(binder.SignerInfo.FieldName) - if err != nil { - return fmt.Errorf("failed to get signer flag: %w", err) - } - - if err := cmd.Flags().Set(flags.FlagFrom, signer); err != nil { + if err := cmd.Flags().Set(flags.FlagFrom, cmd.Flag(binder.SignerInfo.FlagName).Value.String()); err != nil { return err } } diff --git a/client/v2/autocli/common_test.go b/client/v2/autocli/common_test.go index 9e8613be07ca..30827fb3d278 100644 --- a/client/v2/autocli/common_test.go +++ b/client/v2/autocli/common_test.go @@ -56,9 +56,6 @@ func initFixture(t *testing.T) *fixture { kr, err := sdkkeyring.New(sdk.KeyringServiceName(), sdkkeyring.BackendMemory, home, nil, encodingConfig.Codec) assert.NilError(t, err) - akr, err := sdkkeyring.NewAutoCLIKeyring(kr) - assert.NilError(t, err) - interfaceRegistry := encodingConfig.Codec.InterfaceRegistry() banktypes.RegisterInterfaces(interfaceRegistry) @@ -83,7 +80,6 @@ func initFixture(t *testing.T) *fixture { AddressCodec: clientCtx.AddressCodec, ValidatorAddressCodec: clientCtx.ValidatorAddressCodec, ConsensusAddressCodec: clientCtx.ConsensusAddressCodec, - Keyring: akr, }, GetClientConn: func(*cobra.Command) (grpc.ClientConnInterface, error) { return conn, nil diff --git a/client/v2/autocli/flag/address.go b/client/v2/autocli/flag/address.go index 99d1a9c3284b..58108d094990 100644 --- a/client/v2/autocli/flag/address.go +++ b/client/v2/autocli/flag/address.go @@ -9,16 +9,18 @@ import ( "cosmossdk.io/client/v2/autocli/keyring" "cosmossdk.io/core/address" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) type addressStringType struct{} -func (a addressStringType) NewValue(_ context.Context, b *Builder) Value { - return &addressValue{addressCodec: b.AddressCodec, keyring: b.Keyring} +func (a addressStringType) NewValue(ctx *context.Context, b *Builder) Value { + return &addressValue{addressCodec: b.AddressCodec, ctx: ctx} } func (a addressStringType) DefaultValue() string { @@ -27,8 +29,8 @@ func (a addressStringType) DefaultValue() string { type validatorAddressStringType struct{} -func (a validatorAddressStringType) NewValue(_ context.Context, b *Builder) Value { - return &addressValue{addressCodec: b.ValidatorAddressCodec, keyring: b.Keyring} +func (a validatorAddressStringType) NewValue(ctx *context.Context, b *Builder) Value { + return &addressValue{addressCodec: b.ValidatorAddressCodec, ctx: ctx} } func (a validatorAddressStringType) DefaultValue() string { @@ -36,9 +38,10 @@ func (a validatorAddressStringType) DefaultValue() string { } type addressValue struct { - value string + ctx *context.Context addressCodec address.Codec - keyring keyring.Keyring + + value string } func (a addressValue) Get(protoreflect.Value) (protoreflect.Value, error) { @@ -51,7 +54,9 @@ func (a addressValue) String() string { // Set implements the flag.Value interface for addressValue. func (a *addressValue) Set(s string) error { - addr, err := a.keyring.LookupAddressByKeyName(s) + // we get the keyring on set, as in NewValue the context is the parent context (before RunE) + keyring := getKeyringFromCtx(a.ctx) + addr, err := keyring.LookupAddressByKeyName(s) if err == nil { addrStr, err := a.addressCodec.BytesToString(addr) if err != nil { @@ -62,9 +67,11 @@ func (a *addressValue) Set(s string) error { return nil } - // failed all validation, just accept the input. - // TODO(@julienrbrt), for final client/v2 2.0.0 revert the logic and - // do a better keyring instantiation. + _, err = a.addressCodec.StringToBytes(s) + if err != nil { + return fmt.Errorf("invalid account address or key name: %w", err) + } + a.value = s return nil @@ -76,11 +83,11 @@ func (a addressValue) Type() string { type consensusAddressStringType struct{} -func (a consensusAddressStringType) NewValue(ctx context.Context, b *Builder) Value { +func (a consensusAddressStringType) NewValue(ctx *context.Context, b *Builder) Value { return &consensusAddressValue{ addressValue: addressValue{ addressCodec: b.ConsensusAddressCodec, - keyring: b.Keyring, + ctx: ctx, }, } } @@ -102,7 +109,9 @@ func (a consensusAddressValue) String() string { } func (a *consensusAddressValue) Set(s string) error { - addr, err := a.keyring.LookupAddressByKeyName(s) + // we get the keyring on set, as in NewValue the context is the parent context (before RunE) + keyring := getKeyringFromCtx(a.ctx) + addr, err := keyring.LookupAddressByKeyName(s) if err == nil { addrStr, err := a.addressCodec.BytesToString(addr) if err != nil { @@ -127,11 +136,7 @@ func (a *consensusAddressValue) Set(s string) error { var pk cryptotypes.PubKey err2 := cdc.UnmarshalInterfaceJSON([]byte(s), &pk) if err2 != nil { - // failed all validation, just accept the input. - // TODO(@julienrbrt), for final client/v2 2.0.0 revert the logic and - // do a better keyring instantiation. - a.value = s - return nil + return fmt.Errorf("input isn't a pubkey (%w) or is an invalid account address (%w)", err, err2) } a.value, err = a.addressCodec.BytesToString(pk.Address()) @@ -141,3 +146,21 @@ func (a *consensusAddressValue) Set(s string) error { return nil } + +func getKeyringFromCtx(ctx *context.Context) keyring.Keyring { + dctx := *ctx + if dctx != nil { + if clientCtx := dctx.Value(client.ClientContextKey); clientCtx != nil { + k, err := sdkkeyring.NewAutoCLIKeyring(clientCtx.(*client.Context).Keyring) + if err != nil { + panic(fmt.Errorf("failed to create keyring: %w", err)) + } + + return k + } else if k := dctx.Value(keyring.KeyringContextKey); k != nil { + return k.(*keyring.KeyringImpl) + } + } + + return keyring.NoKeyring{} +} diff --git a/client/v2/autocli/flag/binary.go b/client/v2/autocli/flag/binary.go index fc954d763148..5567d5f8f775 100644 --- a/client/v2/autocli/flag/binary.go +++ b/client/v2/autocli/flag/binary.go @@ -14,7 +14,7 @@ type binaryType struct{} var _ Value = (*fileBinaryValue)(nil) -func (f binaryType) NewValue(context.Context, *Builder) Value { +func (f binaryType) NewValue(*context.Context, *Builder) Value { return &fileBinaryValue{} } diff --git a/client/v2/autocli/flag/builder.go b/client/v2/autocli/flag/builder.go index 84cd794faec6..6ff325c53bdb 100644 --- a/client/v2/autocli/flag/builder.go +++ b/client/v2/autocli/flag/builder.go @@ -16,7 +16,6 @@ import ( autocliv1 "cosmossdk.io/api/cosmos/autocli/v1" msgv1 "cosmossdk.io/api/cosmos/msg/v1" - "cosmossdk.io/client/v2/autocli/keyring" "cosmossdk.io/client/v2/internal/flags" "cosmossdk.io/client/v2/internal/util" "cosmossdk.io/core/address" @@ -48,9 +47,6 @@ type Builder struct { messageFlagTypes map[protoreflect.FullName]Type scalarFlagTypes map[string]Type - // Keyring is the keyring to use for client/v2. - Keyring keyring.Keyring - // Address Codecs are the address codecs to use for client/v2. AddressCodec address.Codec ValidatorAddressCodec address.ValidatorAddressCodec @@ -90,10 +86,6 @@ func (b *Builder) ValidateAndComplete() error { return errors.New("consensus address codec is required in flag builder") } - if b.Keyring == nil { - b.Keyring = keyring.NoKeyring{} - } - if b.TypeResolver == nil { return errors.New("type resolver is required in flag builder") } @@ -118,12 +110,12 @@ func (b *Builder) DefineScalarFlagType(scalarName string, flagType Type) { } // AddMessageFlags adds flags for each field in the message to the flag set. -func (b *Builder) AddMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions) (*MessageBinder, error) { +func (b *Builder) AddMessageFlags(ctx *context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions) (*MessageBinder, error) { return b.addMessageFlags(ctx, flagSet, messageType, commandOptions, namingOptions{}) } // addMessageFlags adds flags for each field in the message to the flag set. -func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions, options namingOptions) (*MessageBinder, error) { +func (b *Builder) addMessageFlags(ctx *context.Context, flagSet *pflag.FlagSet, messageType protoreflect.MessageType, commandOptions *autocliv1.RpcCommandOptions, options namingOptions) (*MessageBinder, error) { messageBinder := &MessageBinder{ messageType: messageType, // positional args are also parsed using a FlagSet so that we can reuse all the same parsers @@ -135,7 +127,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m isPositional := map[string]bool{} - lengthPositionalArgsOptions := len(commandOptions.PositionalArgs) + positionalArgsLen := len(commandOptions.PositionalArgs) for i, arg := range commandOptions.PositionalArgs { isPositional[arg.ProtoField] = true @@ -147,17 +139,12 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m } } - field := fields.ByName(protoreflect.Name(arg.ProtoField)) - if field == nil { - return nil, fmt.Errorf("can't find field %s on %s", arg.ProtoField, messageType.Descriptor().FullName()) - } - if arg.Optional && arg.Varargs { return nil, fmt.Errorf("positional argument %s can't be both optional and varargs", arg.ProtoField) } if arg.Varargs { - if i != lengthPositionalArgsOptions-1 { + if i != positionalArgsLen-1 { return nil, fmt.Errorf("varargs positional argument %s must be the last argument", arg.ProtoField) } @@ -165,13 +152,18 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m } if arg.Optional { - if i != lengthPositionalArgsOptions-1 { + if i != positionalArgsLen-1 { return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField) } messageBinder.hasOptional = true } + field := fields.ByName(protoreflect.Name(arg.ProtoField)) + if field == nil { + return nil, fmt.Errorf("can't find field %s on %s", arg.ProtoField, messageType.Descriptor().FullName()) + } + _, hasValue, err := b.addFieldFlag( ctx, messageBinder.positionalFlagSet, @@ -189,19 +181,20 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m }) } - if messageBinder.hasVarargs { - messageBinder.CobraArgs = cobra.MinimumNArgs(lengthPositionalArgsOptions - 1) - messageBinder.mandatoryArgUntil = lengthPositionalArgsOptions - 1 - } else if messageBinder.hasOptional { - messageBinder.CobraArgs = cobra.RangeArgs(lengthPositionalArgsOptions-1, lengthPositionalArgsOptions) - messageBinder.mandatoryArgUntil = lengthPositionalArgsOptions - 1 - } else { - messageBinder.CobraArgs = cobra.ExactArgs(lengthPositionalArgsOptions) - messageBinder.mandatoryArgUntil = lengthPositionalArgsOptions + switch { + case messageBinder.hasVarargs: + messageBinder.CobraArgs = cobra.MinimumNArgs(positionalArgsLen - 1) + messageBinder.mandatoryArgUntil = positionalArgsLen - 1 + case messageBinder.hasOptional: + messageBinder.CobraArgs = cobra.RangeArgs(positionalArgsLen-1, positionalArgsLen) + messageBinder.mandatoryArgUntil = positionalArgsLen - 1 + default: + messageBinder.CobraArgs = cobra.ExactArgs(positionalArgsLen) + messageBinder.mandatoryArgUntil = positionalArgsLen } // validate flag options - for name := range commandOptions.FlagOptions { + for name, opts := range commandOptions.FlagOptions { if fields.ByName(protoreflect.Name(name)) == nil { return nil, fmt.Errorf("can't find field %s on %s specified as a flag", name, messageType.Descriptor().FullName()) } @@ -210,14 +203,15 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m if name == signerFieldName { messageBinder.SignerInfo = SignerInfo{ FieldName: name, - IsFlag: false, + IsFlag: true, + FlagName: opts.Name, } } } // if signer has not been specified as positional arguments, // add it as `--from` flag (instead of --field-name flags) - if signerFieldName != "" && messageBinder.SignerInfo.FieldName == "" { + if signerFieldName != "" && messageBinder.SignerInfo == (SignerInfo{}) { if commandOptions.FlagOptions == nil { commandOptions.FlagOptions = make(map[string]*autocliv1.FlagOptions) } @@ -229,8 +223,9 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m } messageBinder.SignerInfo = SignerInfo{ - FieldName: flags.FlagFrom, + FieldName: signerFieldName, IsFlag: true, + FlagName: flags.FlagFrom, } } @@ -238,13 +233,15 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m flagOptsByFlagName := map[string]*autocliv1.FlagOptions{} for i := 0; i < fields.Len(); i++ { field := fields.Get(i) + fieldName := string(field.Name()) + // skips positional args and signer field if already set - if isPositional[string(field.Name())] || - (string(field.Name()) == signerFieldName && messageBinder.SignerInfo.FieldName == flags.FlagFrom) { + if isPositional[fieldName] || + (fieldName == signerFieldName && messageBinder.SignerInfo.FlagName == flags.FlagFrom) { continue } - flagOpts := commandOptions.FlagOptions[string(field.Name())] + flagOpts := commandOptions.FlagOptions[fieldName] name, hasValue, err := b.addFieldFlag(ctx, flagSet, field, flagOpts, options) if err != nil { return nil, err @@ -274,7 +271,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m } // bindPageRequest create a flag for pagination -func (b *Builder) bindPageRequest(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor) (HasValue, error) { +func (b *Builder) bindPageRequest(ctx *context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor) (HasValue, error) { return b.addMessageFlags( ctx, flagSet, @@ -291,7 +288,7 @@ type namingOptions struct { } // addFieldFlag adds a flag for the provided field to the flag set. -func (b *Builder) addFieldFlag(ctx context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor, opts *autocliv1.FlagOptions, options namingOptions) (name string, hasValue HasValue, err error) { +func (b *Builder) addFieldFlag(ctx *context.Context, flagSet *pflag.FlagSet, field protoreflect.FieldDescriptor, opts *autocliv1.FlagOptions, options namingOptions) (name string, hasValue HasValue, err error) { if opts == nil { opts = &autocliv1.FlagOptions{} } diff --git a/client/v2/autocli/flag/coin.go b/client/v2/autocli/flag/coin.go index 8496a2b0f656..6ed842a34a93 100644 --- a/client/v2/autocli/flag/coin.go +++ b/client/v2/autocli/flag/coin.go @@ -17,7 +17,7 @@ type coinValue struct { value *basev1beta1.Coin } -func (c coinType) NewValue(context.Context, *Builder) Value { +func (c coinType) NewValue(*context.Context, *Builder) Value { return &coinValue{} } diff --git a/client/v2/autocli/flag/duration.go b/client/v2/autocli/flag/duration.go index cf9fe67af495..df02cba700f7 100644 --- a/client/v2/autocli/flag/duration.go +++ b/client/v2/autocli/flag/duration.go @@ -10,7 +10,7 @@ import ( type durationType struct{} -func (d durationType) NewValue(context.Context, *Builder) Value { +func (d durationType) NewValue(*context.Context, *Builder) Value { return &durationValue{} } diff --git a/client/v2/autocli/flag/enum.go b/client/v2/autocli/flag/enum.go index 8b555d9232ec..72b27528a9a5 100644 --- a/client/v2/autocli/flag/enum.go +++ b/client/v2/autocli/flag/enum.go @@ -14,7 +14,7 @@ type enumType struct { enum protoreflect.EnumDescriptor } -func (b enumType) NewValue(context.Context, *Builder) Value { +func (b enumType) NewValue(*context.Context, *Builder) Value { val := &enumValue{ enum: b.enum, valMap: map[string]protoreflect.EnumValueDescriptor{}, diff --git a/client/v2/autocli/flag/interface.go b/client/v2/autocli/flag/interface.go index c7bb61b9d148..1d983c09c630 100644 --- a/client/v2/autocli/flag/interface.go +++ b/client/v2/autocli/flag/interface.go @@ -9,9 +9,8 @@ import ( // Type specifies a custom flag type. type Type interface { - // NewValue returns a new pflag.Value which must also implement either - // SimpleValue or ListValue. - NewValue(context.Context, *Builder) Value + // NewValue returns a new pflag.Value which must also implement either SimpleValue or ListValue. + NewValue(*context.Context, *Builder) Value // DefaultValue is the default value for this type. DefaultValue() string diff --git a/client/v2/autocli/flag/json_message.go b/client/v2/autocli/flag/json_message.go index cc1a6ce285cb..8f485271556e 100644 --- a/client/v2/autocli/flag/json_message.go +++ b/client/v2/autocli/flag/json_message.go @@ -20,7 +20,7 @@ type jsonMessageFlagType struct { messageDesc protoreflect.MessageDescriptor } -func (j jsonMessageFlagType) NewValue(_ context.Context, builder *Builder) Value { +func (j jsonMessageFlagType) NewValue(_ *context.Context, builder *Builder) Value { return &jsonMessageFlagValue{ messageType: util.ResolveMessageType(builder.TypeResolver, j.messageDesc), jsonMarshalOptions: protojson.MarshalOptions{Resolver: builder.TypeResolver}, diff --git a/client/v2/autocli/flag/list.go b/client/v2/autocli/flag/list.go index 72f84c8be3ee..d30f2992ebd9 100644 --- a/client/v2/autocli/flag/list.go +++ b/client/v2/autocli/flag/list.go @@ -52,7 +52,7 @@ type compositeListType struct { simpleType Type } -func (t compositeListType) NewValue(ctx context.Context, opts *Builder) Value { +func (t compositeListType) NewValue(ctx *context.Context, opts *Builder) Value { return &compositeListValue{ simpleType: t.simpleType, values: nil, @@ -68,7 +68,7 @@ func (t compositeListType) DefaultValue() string { type compositeListValue struct { simpleType Type values []protoreflect.Value - ctx context.Context + ctx *context.Context opts *Builder } diff --git a/client/v2/autocli/flag/map.go b/client/v2/autocli/flag/map.go index f6b21f8a963a..cd999dceb1d4 100644 --- a/client/v2/autocli/flag/map.go +++ b/client/v2/autocli/flag/map.go @@ -180,7 +180,7 @@ type compositeMapValue[T comparable] struct { keyType string valueType Type values map[T]protoreflect.Value - ctx context.Context + ctx *context.Context opts *Builder } @@ -188,7 +188,7 @@ func (m compositeMapType[T]) DefaultValue() string { return "" } -func (m compositeMapType[T]) NewValue(ctx context.Context, opts *Builder) Value { +func (m compositeMapType[T]) NewValue(ctx *context.Context, opts *Builder) Value { return &compositeMapValue[T]{ keyValueResolver: m.keyValueResolver, valueType: m.valueType, diff --git a/client/v2/autocli/flag/messager_binder.go b/client/v2/autocli/flag/messager_binder.go index ecd822395030..46a28baa285a 100644 --- a/client/v2/autocli/flag/messager_binder.go +++ b/client/v2/autocli/flag/messager_binder.go @@ -15,7 +15,9 @@ import ( type SignerInfo struct { PositionalArgIndex int IsFlag bool - FieldName string + + FieldName string + FlagName string // flag name (always set if IsFlag is true) } // MessageBinder binds multiple flags in a flag set to a protobuf message. @@ -25,12 +27,12 @@ type MessageBinder struct { positionalFlagSet *pflag.FlagSet positionalArgs []fieldBinding + flagBindings []fieldBinding + messageType protoreflect.MessageType + hasVarargs bool hasOptional bool mandatoryArgUntil int - - flagBindings []fieldBinding - messageType protoreflect.MessageType } // BuildMessage builds and returns a new message for the bound flags. diff --git a/client/v2/autocli/flag/pubkey.go b/client/v2/autocli/flag/pubkey.go index c5ec2535a2fc..adc07956f690 100644 --- a/client/v2/autocli/flag/pubkey.go +++ b/client/v2/autocli/flag/pubkey.go @@ -14,7 +14,7 @@ import ( type pubkeyType struct{} -func (a pubkeyType) NewValue(_ context.Context, _ *Builder) Value { +func (a pubkeyType) NewValue(_ *context.Context, _ *Builder) Value { return &pubkeyValue{} } diff --git a/client/v2/autocli/flag/timestamp.go b/client/v2/autocli/flag/timestamp.go index c759c70f2178..d77f0293bd97 100644 --- a/client/v2/autocli/flag/timestamp.go +++ b/client/v2/autocli/flag/timestamp.go @@ -10,7 +10,7 @@ import ( type timestampType struct{} -func (t timestampType) NewValue(context.Context, *Builder) Value { +func (t timestampType) NewValue(*context.Context, *Builder) Value { return ×tampValue{} } diff --git a/client/v2/autocli/keyring/keyring.go b/client/v2/autocli/keyring/keyring.go new file mode 100644 index 000000000000..a838b12d8455 --- /dev/null +++ b/client/v2/autocli/keyring/keyring.go @@ -0,0 +1,48 @@ +package keyring + +import ( + "context" + + signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + + "github.com/cosmos/cosmos-sdk/crypto/types" +) + +// KeyringContextKey is the key used to store the keyring in the context. +// The keyring must be wrapped using the KeyringImpl. +var KeyringContextKey struct{} + +var _ Keyring = &KeyringImpl{} + +type KeyringImpl struct { + k Keyring +} + +// NewKeyringInContext returns a new context with the keyring set. +func NewKeyringInContext(ctx context.Context, k Keyring) context.Context { + return context.WithValue(ctx, KeyringContextKey, NewKeyringImpl(k)) +} + +func NewKeyringImpl(k Keyring) *KeyringImpl { + return &KeyringImpl{k: k} +} + +// GetPubKey implements Keyring. +func (k *KeyringImpl) GetPubKey(name string) (types.PubKey, error) { + return k.k.GetPubKey(name) +} + +// List implements Keyring. +func (k *KeyringImpl) List() ([]string, error) { + return k.k.List() +} + +// LookupAddressByKeyName implements Keyring. +func (k *KeyringImpl) LookupAddressByKeyName(name string) ([]byte, error) { + return k.k.LookupAddressByKeyName(name) +} + +// Sign implements Keyring. +func (k *KeyringImpl) Sign(name string, msg []byte, signMode signingv1beta1.SignMode) ([]byte, error) { + return k.k.Sign(name, msg, signMode) +} diff --git a/client/v2/autocli/msg.go b/client/v2/autocli/msg.go index 25e7bbfa3c6d..68a19ab69062 100644 --- a/client/v2/autocli/msg.go +++ b/client/v2/autocli/msg.go @@ -110,9 +110,7 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc continue } - if methodCmd != nil { - cmd.AddCommand(methodCmd) - } + cmd.AddCommand(methodCmd) } return nil @@ -135,7 +133,7 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor // handle gov proposals commands skipProposal, _ := cmd.Flags().GetBool(flags.FlagNoProposal) if options.GovProposal && !skipProposal { - return b.handleGovProposal(options, cmd, input, clientCtx, addressCodec, fd) + return b.handleGovProposal(cmd, input, clientCtx, addressCodec, fd) } // set signer to signer field if empty @@ -179,9 +177,7 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor } // silence usage only for inner txs & queries commands - if cmd != nil { - cmd.SilenceUsage = true - } + cmd.SilenceUsage = true // set gov proposal flags if command is a gov proposal if options.GovProposal { @@ -194,7 +190,6 @@ func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor // handleGovProposal sets the authority field of the message to the gov module address and creates a gov proposal. func (b *Builder) handleGovProposal( - options *autocliv1.RpcCommandOptions, cmd *cobra.Command, input protoreflect.Message, clientCtx client.Context, diff --git a/client/v2/autocli/msg_test.go b/client/v2/autocli/msg_test.go index 1d7b039c504e..2c08022fde80 100644 --- a/client/v2/autocli/msg_test.go +++ b/client/v2/autocli/msg_test.go @@ -59,6 +59,25 @@ func TestMsg(t *testing.T) { assert.NilError(t, err) assertNormalizedJSONEqual(t, out.Bytes(), goldenLoad(t, "msg-output.golden")) + out, err = runCmd(fixture, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{ + Service: bankv1beta1.Msg_ServiceDesc.ServiceName, + RpcCommandOptions: []*autocliv1.RpcCommandOptions{ + { + RpcMethod: "Send", + Use: "send [from_key_or_address] [to_address] [amount] [flags]", + Short: "Send coins from one account to another", + PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "from_address"}, {ProtoField: "to_address"}, {ProtoField: "amount"}}, + }, + }, + EnhanceCustomCommand: true, + }), "send", + "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "1foo", + "--generate-only", + "--output", "json", + ) + assert.NilError(t, err) + assertNormalizedJSONEqual(t, out.Bytes(), goldenLoad(t, "msg-output.golden")) + out, err = runCmd(fixture, buildCustomModuleMsgCommand(&autocliv1.ServiceCommandDescriptor{ Service: bankv1beta1.Msg_ServiceDesc.ServiceName, RpcCommandOptions: []*autocliv1.RpcCommandOptions{ diff --git a/client/v2/autocli/query_test.go b/client/v2/autocli/query_test.go index 6652bc6441cb..f5db25c40b36 100644 --- a/client/v2/autocli/query_test.go +++ b/client/v2/autocli/query_test.go @@ -684,7 +684,7 @@ func TestNotFoundErrorsQuery(t *testing.T) { b.AddQueryConnFlags = nil b.AddTxConnFlags = nil - buildModuleQueryCommand := func(moduleName string, cmdDescriptor *autocliv1.ServiceCommandDescriptor) (*cobra.Command, error) { + buildModuleQueryCommand := func(_ string, cmdDescriptor *autocliv1.ServiceCommandDescriptor) (*cobra.Command, error) { cmd := topLevelCmd(context.Background(), "query", "Querying subcommands") err := b.AddMsgServiceCommands(cmd, cmdDescriptor) return cmd, err diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 2b66d8cbe577..9367365676ac 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -19,7 +19,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/config" addresscodec "github.com/cosmos/cosmos-sdk/codec/address" - "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" sdk "github.com/cosmos/cosmos-sdk/types" @@ -121,7 +120,6 @@ func NewRootCmd() *cobra.Command { } autoCliOpts := tempApp.AutoCliOpts() - autoCliOpts.Keyring, _ = keyring.NewAutoCLIKeyring(initClientCtx.Keyring) autoCliOpts.ClientCtx = initClientCtx if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil { diff --git a/simapp/simd/cmd/root_di.go b/simapp/simd/cmd/root_di.go index adf8b6cef37c..2302ace1a3fd 100644 --- a/simapp/simd/cmd/root_di.go +++ b/simapp/simd/cmd/root_di.go @@ -10,7 +10,6 @@ import ( authv1 "cosmossdk.io/api/cosmos/auth/module/v1" stakingv1 "cosmossdk.io/api/cosmos/staking/module/v1" "cosmossdk.io/client/v2/autocli" - clientv2keyring "cosmossdk.io/client/v2/autocli/keyring" "cosmossdk.io/core/address" "cosmossdk.io/core/legacy" "cosmossdk.io/depinject" @@ -24,7 +23,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/config" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/types/module" @@ -46,7 +44,6 @@ func NewRootCmd() *cobra.Command { ), depinject.Provide( ProvideClientContext, - ProvideKeyring, ), ), &autoCliOpts, @@ -146,12 +143,3 @@ func ProvideClientContext( return clientCtx } - -func ProvideKeyring(clientCtx client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) { - kb, err := client.NewKeyringFromBackend(clientCtx, clientCtx.Keyring.Backend()) - if err != nil { - return nil, err - } - - return keyring.NewAutoCLIKeyring(kb) -}