feat(client/v2): get keyring from context (#19646)

This commit is contained in:
Julien Robert 2024-06-19 16:53:13 +02:00 committed by GitHub
parent b48fd66678
commit ca195c1527
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 184 additions and 134 deletions

View File

@ -36,7 +36,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
<!-- ## [v2.1.0-beta.1] to be tagged after v0.51 final or in SDK agnostic version -->
<!-- ## [v2.1.0-rc.1] to be tagged after v0.51 final or in SDK agnostic version -->
### 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

View File

@ -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
<appd> 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",

View File

@ -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,

View File

@ -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
}
}

View File

@ -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

View File

@ -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{}
}

View File

@ -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{}
}

View File

@ -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{}
}

View File

@ -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{}
}

View File

@ -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{}
}

View File

@ -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{},

View File

@ -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

View File

@ -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},

View File

@ -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
}

View File

@ -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,

View File

@ -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.

View File

@ -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{}
}

View File

@ -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 &timestampValue{}
}

View File

@ -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)
}

View File

@ -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,

View File

@ -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{

View File

@ -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

View File

@ -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 {

View File

@ -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)
}