feat(client/v2): signing (backport #17913) (#17972)

Co-authored-by: Julien Robert <julien@rbrt.fr>
This commit is contained in:
mergify[bot] 2023-10-05 15:41:50 +02:00 committed by GitHub
parent 3da9f9c9ec
commit 8334eefaaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 742 additions and 640 deletions

View File

@ -38,6 +38,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
### Improvements
* (keyring) [#17913](https://github.com/cosmos/cosmos-sdk/pull/17913) Add `NewAutoCLIKeyring` for creating an AutoCLI keyring from a SDK keyring.
### Bug Fixes
* (x/gov) [#17873](https://github.com/cosmos/cosmos-sdk/pull/17873) Fail any inactive and active proposals that cannot be decoded.

View File

@ -117,7 +117,9 @@ func AddQueryFlagsToCmd(cmd *cobra.Command) {
func AddTxFlagsToCmd(cmd *cobra.Command) {
f := cmd.Flags()
f.StringP(FlagOutput, "o", OutputFormatJSON, "Output format (text|json)")
f.String(FlagFrom, "", "Name or address of private key with which to sign")
if cmd.Flag(FlagFrom) == nil { // avoid flag redefinition when it's already been added by AutoCLI
f.String(FlagFrom, "", "Name or address of private key with which to sign")
}
f.Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)")
f.Uint64P(FlagSequence, "s", 0, "The sequence number of the signing account (offline mode only)")
f.String(FlagNote, "", "Note to add a description to the transaction (previously --memo)")

View File

@ -410,7 +410,12 @@ func (f Factory) BuildSimTx(msgs ...sdk.Msg) ([]byte, error) {
return nil, err
}
return f.txConfig.TxEncoder()(txb.GetTx())
encoder := f.txConfig.TxEncoder()
if encoder == nil {
return nil, fmt.Errorf("cannot simulate tx: tx encoder is nil")
}
return encoder(txb.GetTx())
}
// getSimPK gets the public key to use for building a simulation tx.

View File

@ -107,7 +107,7 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error {
txBytes, err := encoder(tx.GetTx())
if err != nil {
return err
return fmt.Errorf("failed to encode transaction: %w", err)
}
if err := clientCtx.PrintRaw(json.RawMessage(txBytes)); err != nil {

View File

@ -1,2 +1,2 @@
codegen:
@(cd internal; buf generate)
@(cd internal; buf generate)

View File

@ -75,7 +75,7 @@ if err := rootCmd.Execute(); err != nil {
### Keyring
`autocli` supports 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 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.
:::tip
This provides a better UX as it allows to resolve key names directly from the keyring in all transactions and commands.
@ -87,16 +87,23 @@ 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 Cosmos SDK keyring and Hubl keyring both implement this interface.
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:
:::tip
The Cosmos SDK keyring and Hubl keyring both implement the `client/v2/autocli/keyring` interface, thanks to the following wrapper:
```go
keyring.NewAutoCLIKeyring(kb)
```
:::
:::warning
When using AutoCLI the keyring will only be created once and before any command flag parsing.
:::
```go
// Get the keyring from the client context
keyring := ctx.Keyring
// Set the keyring in the appOptions
appOptions.Keyring = keyring
@ -104,6 +111,16 @@ err := autoCliOpts.EnhanceRootCommand(rootCmd)
...
```
## Signing
`autocli` supports signing transactions with the keyring.
The [`cosmos.msg.v1.signer` protobuf annotation](https://github.com/cosmos/cosmos-sdk/blob/9dd34510e27376005e7e7ff3628eab9dbc8ad6dc/docs/build/building-modules/05-protobuf-annotations.md#L9) defines the signer field of the message.
This field is automatically filled when using the `--from` flag or defining the signer as a positional argument.
:::warning
AutoCLI currently supports only one signer per transaction.
:::
## Module Wiring & Customization
The `AutoCLIOptions()` method on your module allows to specify custom commands, sub-commands or flags for each service, as it was a `cobra.Command` instance, within the `RpcCommandOptions` struct. Defining such options will customize the behavior of the `autocli` command generation, which by default generates a command for each method in your gRPC service.

View File

@ -12,11 +12,11 @@ import (
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
)
// AppOptions are autocli options for an app. These options can be built via depinject based on an app config. Ex:
@ -30,9 +30,6 @@ import (
type AppOptions struct {
depinject.In
// Logger is the logger to use for client/v2.
Logger log.Logger
// Modules are the AppModule implementations for the modules in the app.
Modules map[string]appmodule.AppModule
@ -42,9 +39,6 @@ type AppOptions struct {
// module or need to be improved.
ModuleOptions map[string]*autocliv1.ModuleOptions `optional:"true"`
// ClientCtx contains the necessary information needed to execute the commands.
ClientCtx *client.Context
// AddressCodec is the address codec to use for the app.
AddressCodec address.Codec
ValidatorAddressCodec runtime.ValidatorAddressCodec
@ -52,6 +46,12 @@ type AppOptions struct {
// 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
// TxConfigOptions are the transactions config options.
TxConfigOpts tx.ConfigOptions
}
// EnhanceRootCommand enhances the provided root command with autocli AppOptions,
@ -71,21 +71,21 @@ type AppOptions struct {
// err = autoCliOpts.EnhanceRootCommand(rootCmd)
func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
builder := &Builder{
Logger: appOptions.Logger,
Builder: flag.Builder{
TypeResolver: protoregistry.GlobalTypes,
FileResolver: proto.HybridResolver,
ClientCtx: appOptions.ClientCtx,
AddressCodec: appOptions.AddressCodec,
ValidatorAddressCodec: appOptions.ValidatorAddressCodec,
ConsensusAddressCodec: appOptions.ConsensusAddressCodec,
Keyring: appOptions.Keyring,
},
ClientCtx: appOptions.ClientCtx,
TxConfigOpts: appOptions.TxConfigOpts,
GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
return client.GetClientQueryContext(cmd)
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
AddQueryConnFlags: sdkflags.AddQueryFlagsToCmd,
AddTxConnFlags: sdkflags.AddTxFlagsToCmd,
}
return appOptions.EnhanceRootCommandWithBuilder(rootCmd, builder)

View File

@ -8,7 +8,9 @@ import (
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/client/v2/autocli/keyring"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/client"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)
// Builder manages options for building CLI commands.
@ -16,13 +18,16 @@ type Builder struct {
// flag.Builder embeds the flag builder and its options.
flag.Builder
// Logger is the logger used by the builder.
Logger log.Logger
// GetClientConn specifies how CLI commands will resolve a grpc.ClientConnInterface
// from a given context.
GetClientConn func(*cobra.Command) (grpc.ClientConnInterface, error)
// ClientCtx contains the necessary information needed to execute the commands.
ClientCtx client.Context
// TxConfigOptions is required to support sign mode textual
TxConfigOpts authtx.ConfigOptions
// AddQueryConnFlags and AddTxConnFlags are functions that add flags to query and transaction commands
AddQueryConnFlags func(*cobra.Command)
AddTxConnFlags func(*cobra.Command)
@ -33,40 +38,28 @@ type Builder struct {
// If the Logger is nil, it will be set to a nop logger.
// If the keyring is nil, it will be set to a no keyring.
func (b *Builder) ValidateAndComplete() error {
if b.Logger == nil {
b.Logger = log.NewNopLogger()
if b.Builder.AddressCodec == nil {
return errors.New("address codec is required in flag builder")
}
if b.ClientCtx == nil {
return errors.New("client context is required in builder")
if b.Builder.ValidatorAddressCodec == nil {
return errors.New("validator address codec is required in flag builder")
}
if b.AddressCodec == nil {
return errors.New("address codec is required in builder")
if b.Builder.ConsensusAddressCodec == nil {
return errors.New("consensus address codec is required in flag builder")
}
if b.ValidatorAddressCodec == nil {
return errors.New("validator address codec is required in builder")
if b.Builder.Keyring == nil {
b.Keyring = keyring.NoKeyring{}
}
if b.ConsensusAddressCodec == nil {
return errors.New("consensus address codec is required in builder")
if b.Builder.TypeResolver == nil {
return errors.New("type resolver is required in flag builder")
}
if b.Keyring == nil {
if b.ClientCtx.Keyring != nil {
b.Keyring = b.ClientCtx.Keyring
} else {
b.Keyring = keyring.NoKeyring{}
}
}
if b.TypeResolver == nil {
return errors.New("type resolver is required in builder")
}
if b.FileResolver == nil {
return errors.New("file resolver is required in builder")
if b.Builder.FileResolver == nil {
return errors.New("file resolver is required in flag builder")
}
return nil

View File

@ -9,9 +9,8 @@ import (
"sigs.k8s.io/yaml"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/internal/flags"
"cosmossdk.io/client/v2/internal/util"
"github.com/cosmos/cosmos-sdk/client/flags"
)
type cmdType int
@ -66,6 +65,37 @@ func (b *Builder) buildMethodCommandCommon(descriptor protoreflect.MethodDescrip
return err
}
// signer related logic, triggers only when there is a signer defined
if binder.SignerInfo.FieldName != "" {
// mark the signer flag as required if defined
// TODO(@julienrbrt): UX improvement by only marking the flag as required when there is more than one key in the keyring;
// when there is only one key, use that key by default.
if binder.SignerInfo.IsFlag {
if err := cmd.MarkFlagRequired(binder.SignerInfo.FieldName); err != nil {
return err
}
// 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.
if binder.SignerInfo.FieldName != flags.FlagFrom {
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 {
return err
}
}
} else {
// if the signer is not a flag, it is a positional argument
// we need to get the correct positional arguments
if err := cmd.Flags().Set(flags.FlagFrom, args[binder.SignerInfo.PositionalArgIndex]); err != nil {
return err
}
}
}
return exec(cmd, input)
}

View File

@ -12,6 +12,7 @@ import (
"google.golang.org/protobuf/reflect/protoregistry"
"gotest.tools/v3/assert"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv2alpha1 "cosmossdk.io/api/cosmos/base/reflection/v2alpha1"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/client/v2/internal/testpb"
@ -19,9 +20,11 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
addresscodec "github.com/cosmos/cosmos-sdk/codec/address"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil"
"github.com/cosmos/cosmos-sdk/x/bank"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type fixture struct {
@ -47,24 +50,33 @@ func initFixture(t *testing.T) *fixture {
clientConn, err := grpc.Dial(listener.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()))
assert.NilError(t, err)
appCodec := moduletestutil.MakeTestEncodingConfig().Codec
kr, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, home, nil, appCodec)
encodingConfig := moduletestutil.MakeTestEncodingConfig(bank.AppModuleBasic{})
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)
var initClientCtx client.Context
initClientCtx = initClientCtx.
WithKeyring(kr).
WithKeyringDir(home).
WithHomeDir(home).
WithViper("")
WithViper("").
WithInterfaceRegistry(interfaceRegistry).
WithTxConfig(encodingConfig.TxConfig).
WithAccountRetriever(client.MockAccountRetriever{}).
WithChainID("autocli-test")
conn := &testClientConn{ClientConn: clientConn}
b := &Builder{
Builder: flag.Builder{
TypeResolver: protoregistry.GlobalTypes,
FileResolver: protoregistry.GlobalFiles,
ClientCtx: &initClientCtx,
Keyring: kr,
Keyring: akr,
AddressCodec: addresscodec.NewBech32Codec("cosmos"),
ValidatorAddressCodec: addresscodec.NewBech32Codec("cosmosvaloper"),
ConsensusAddressCodec: addresscodec.NewBech32Codec("cosmosvalcons"),
@ -74,6 +86,7 @@ func initFixture(t *testing.T) *fixture {
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
ClientCtx: initClientCtx,
}
assert.NilError(t, b.ValidateAndComplete())
@ -131,3 +144,82 @@ func (t testEchoServer) Echo(_ context.Context, request *testpb.EchoRequest) (*t
}
var _ testpb.QueryServer = testEchoServer{}
func TestEnhanceCommand(t *testing.T) {
b := &Builder{}
// Test that the command has a subcommand
cmd := &cobra.Command{Use: "test"}
cmd.AddCommand(&cobra.Command{Use: "test"})
for i := 0; i < 2; i++ {
cmdTp := cmdType(i)
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {},
},
}
err := b.enhanceCommandCommon(cmd, cmdTp, appOptions, map[string]*cobra.Command{})
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions = AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{},
}
customCommands := map[string]*cobra.Command{
"test2": {Use: "test"},
}
err = b.enhanceCommandCommon(cmd, cmdTp, appOptions, customCommands)
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions = AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {Tx: nil},
},
}
err = b.enhanceCommandCommon(cmd, cmdTp, appOptions, map[string]*cobra.Command{})
assert.NilError(t, err)
}
}
func TestErrorBuildCommand(t *testing.T) {
fixture := initFixture(t)
b := fixture.b
b.AddQueryConnFlags = nil
b.AddTxConnFlags = nil
commandDescriptor := &autocliv1.ServiceCommandDescriptor{
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{
ProtoField: "un-existent-proto-field",
},
},
},
},
}
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {
Query: commandDescriptor,
Tx: commandDescriptor,
},
},
ClientCtx: b.ClientCtx,
}
_, err := b.BuildMsgCommand(appOptions, nil)
assert.ErrorContains(t, err, "can't find field un-existent-proto-field")
appOptions.ModuleOptions["test"].Tx = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
appOptions.ModuleOptions["test"].Query = &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
_, err = b.BuildMsgCommand(appOptions, nil)
assert.ErrorContains(t, err, "can't find service un-existent-service")
}

View File

@ -80,7 +80,12 @@ func (a addressValue) Type() string {
type consensusAddressStringType struct{}
func (a consensusAddressStringType) NewValue(ctx context.Context, b *Builder) Value {
return &consensusAddressValue{addressValue: addressValue{addressCodec: b.ConsensusAddressCodec, keyring: b.Keyring}}
return &consensusAddressValue{
addressValue: addressValue{
addressCodec: b.ConsensusAddressCodec,
keyring: b.Keyring,
},
}
}
func (a consensusAddressStringType) DefaultValue() string {

View File

@ -14,11 +14,12 @@ import (
"google.golang.org/protobuf/reflect/protoregistry"
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"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/runtime"
)
@ -41,16 +42,13 @@ type Builder struct {
messageFlagTypes map[protoreflect.FullName]Type
scalarFlagTypes map[string]Type
// AddressCodec is the address codec to use for the app.
// 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 runtime.ValidatorAddressCodec
ConsensusAddressCodec runtime.ConsensusAddressCodec
// Keyring implementation
Keyring keyring.Keyring
// ClientCtx contains the necessary information needed to execute the commands.
ClientCtx *client.Context
}
func (b *Builder) init() {
@ -69,35 +67,48 @@ func (b *Builder) init() {
}
}
// DefineMessageFlagType allows to extend custom protobuf message type handling for flags (and positional arguments).
func (b *Builder) DefineMessageFlagType(messageName protoreflect.FullName, flagType Type) {
b.init()
b.messageFlagTypes[messageName] = flagType
}
// DefineScalarFlagType allows to extend custom scalar type handling for flags (and positional arguments).
func (b *Builder) DefineScalarFlagType(scalarName string, flagType Type) {
b.init()
b.scalarFlagTypes[scalarName] = flagType
}
// 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) {
return b.addMessageFlags(ctx, flagSet, messageType, commandOptions, namingOptions{})
}
// AddMessageFlags adds flags for each field in the message to the flag set.
// 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) {
fields := messageType.Descriptor().Fields()
numFields := fields.Len()
handler := &MessageBinder{
messageBinder := &MessageBinder{
messageType: messageType,
// positional args are also parsed using a FlagSet so that we can reuse all the same parsers
positionalFlagSet: pflag.NewFlagSet("positional", pflag.ContinueOnError),
}
fields := messageType.Descriptor().Fields()
signerFieldName := GetSignerFieldName(messageType.Descriptor())
isPositional := map[string]bool{}
n := len(commandOptions.PositionalArgs)
// positional args are also parsed using a FlagSet so that we can reuse all the same parsers
handler.positionalFlagSet = pflag.NewFlagSet("positional", pflag.ContinueOnError)
lengthPositionalArgsOptions := len(commandOptions.PositionalArgs)
for i, arg := range commandOptions.PositionalArgs {
isPositional[arg.ProtoField] = true
// verify if a positional field is a signer field
if arg.ProtoField == signerFieldName {
messageBinder.SignerInfo = SignerInfo{
PositionalArgIndex: i,
FieldName: arg.ProtoField,
}
}
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())
@ -108,24 +119,24 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
}
if arg.Varargs {
if i != n-1 {
if i != lengthPositionalArgsOptions-1 {
return nil, fmt.Errorf("varargs positional argument %s must be the last argument", arg.ProtoField)
}
handler.hasVarargs = true
messageBinder.hasVarargs = true
}
if arg.Optional {
if i != n-1 {
if i != lengthPositionalArgsOptions-1 {
return nil, fmt.Errorf("optional positional argument %s must be the last argument", arg.ProtoField)
}
handler.hasOptional = true
messageBinder.hasOptional = true
}
_, hasValue, err := b.addFieldFlag(
ctx,
handler.positionalFlagSet,
messageBinder.positionalFlagSet,
field,
&autocliv1.FlagOptions{Name: fmt.Sprintf("%d", i)},
namingOptions{},
@ -134,21 +145,21 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
return nil, err
}
handler.positionalArgs = append(handler.positionalArgs, fieldBinding{
messageBinder.positionalArgs = append(messageBinder.positionalArgs, fieldBinding{
field: field,
hasValue: hasValue,
})
}
if handler.hasVarargs {
handler.CobraArgs = cobra.MinimumNArgs(n - 1)
handler.MandatoryArgUntil = n - 1
} else if handler.hasOptional {
handler.CobraArgs = cobra.RangeArgs(n-1, n)
handler.MandatoryArgUntil = n - 1
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 {
handler.CobraArgs = cobra.ExactArgs(n)
handler.MandatoryArgUntil = n
messageBinder.CobraArgs = cobra.ExactArgs(lengthPositionalArgsOptions)
messageBinder.mandatoryArgUntil = lengthPositionalArgsOptions
}
// validate flag options
@ -156,12 +167,42 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
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())
}
// verify if a flag is a signer field
if name == signerFieldName {
messageBinder.SignerInfo = SignerInfo{
FieldName: name,
IsFlag: false,
}
}
}
// 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 commandOptions.FlagOptions == nil {
commandOptions.FlagOptions = make(map[string]*autocliv1.FlagOptions)
}
commandOptions.FlagOptions[signerFieldName] = &autocliv1.FlagOptions{
Name: flags.FlagFrom,
Usage: "Name or address with which to sign the message",
Shorthand: "f",
}
messageBinder.SignerInfo = SignerInfo{
FieldName: flags.FlagFrom,
IsFlag: true,
}
}
// define all other fields as flags
flagOptsByFlagName := map[string]*autocliv1.FlagOptions{}
for i := 0; i < numFields; i++ {
for i := 0; i < fields.Len(); i++ {
field := fields.Get(i)
if isPositional[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) {
continue
}
@ -172,7 +213,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
return nil, err
}
handler.flagBindings = append(handler.flagBindings, fieldBinding{
messageBinder.flagBindings = append(messageBinder.flagBindings, fieldBinding{
hasValue: hasValue,
field: field,
})
@ -191,7 +232,7 @@ func (b *Builder) addMessageFlags(ctx context.Context, flagSet *pflag.FlagSet, m
}
})
return handler, nil
return messageBinder, nil
}
// bindPageRequest create a flag for pagination
@ -266,10 +307,11 @@ func (b *Builder) addFieldFlag(ctx context.Context, flagSet *pflag.FlagSet, fiel
// This is a bit of hacking around the pflag API, but the
// defaultValue is set in this way because this is much easier than trying
// to parse the string into the types that StringSliceP, Int32P, etc. expect
// to parse the string into the types that StringSliceP, Int32P, etc.
if defaultValue != "" {
err = flagSet.Set(name, defaultValue)
}
return name, val, err
}
@ -370,3 +412,14 @@ func (b *Builder) resolveFlagTypeBasic(field protoreflect.FieldDescriptor) Type
return nil
}
}
// GetSignerFieldName gets signer field name of a message.
// AutoCLI supports only one signer field per message.
func GetSignerFieldName(descriptor protoreflect.MessageDescriptor) string {
signersFields := proto.GetExtension(descriptor.Options(), msgv1.E_Signer).([]string)
if len(signersFields) == 0 {
return ""
}
return signersFields[0]
}

View File

@ -8,15 +8,26 @@ import (
"google.golang.org/protobuf/reflect/protoreflect"
)
// SignerInfo contains information about the signer field.
// That field is special because it needs to be known for signing.
// This struct keeps track of the field name and whether it is a flag.
// IsFlag and PositionalArgIndex are mutually exclusive.
type SignerInfo struct {
PositionalArgIndex int
IsFlag bool
FieldName string
}
// MessageBinder binds multiple flags in a flag set to a protobuf message.
type MessageBinder struct {
MandatoryArgUntil int
CobraArgs cobra.PositionalArgs
CobraArgs cobra.PositionalArgs
SignerInfo SignerInfo
positionalFlagSet *pflag.FlagSet
positionalArgs []fieldBinding
hasVarargs bool
hasOptional bool
mandatoryArgUntil int
flagBindings []fieldBinding
messageType protoreflect.MessageType
@ -39,15 +50,14 @@ func (m MessageBinder) Bind(msg protoreflect.Message, positionalArgs []string) e
}
name := fmt.Sprintf("%d", i)
if i == m.MandatoryArgUntil && m.hasVarargs {
if i == m.mandatoryArgUntil && m.hasVarargs {
for _, v := range positionalArgs[i:] {
if err := m.positionalFlagSet.Set(name, v); err != nil {
return err
}
}
} else {
err := m.positionalFlagSet.Set(name, positionalArgs[i])
if err != nil {
if err := m.positionalFlagSet.Set(name, positionalArgs[i]); err != nil {
return err
}
}
@ -55,16 +65,14 @@ func (m MessageBinder) Bind(msg protoreflect.Message, positionalArgs []string) e
// bind positional arg values to the message
for _, arg := range m.positionalArgs {
err := arg.bind(msg)
if err != nil {
if err := arg.bind(msg); err != nil {
return err
}
}
// bind flag values to the message
for _, binding := range m.flagBindings {
err := binding.bind(msg)
if err != nil {
if err := binding.bind(msg); err != nil {
return err
}
}

View File

@ -1,3 +0,0 @@
package autocli
var flagNoIndent = "no-indent"

View File

@ -1,6 +1,23 @@
package keyring
import (
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
// Keyring is an interface used for signing transactions.
// It aims to be simplistic and easy to use.
type Keyring interface {
// List returns the names of all keys stored in the keyring.
List() ([]string, error)
// LookupAddressByKeyName returns the address of the key with the given name.
LookupAddressByKeyName(name string) ([]byte, error)
// GetPubKey returns the public key of the key with the given name.
GetPubKey(name string) (cryptotypes.PubKey, error)
// Sign signs the given bytes with the key with the given name.
Sign(name string, msg []byte, signMode signingv1beta1.SignMode) ([]byte, error)
}

View File

@ -1,11 +1,31 @@
package keyring
import "errors"
import (
"errors"
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
var _ Keyring = NoKeyring{}
var errNoKeyring = errors.New("no keyring configured")
type NoKeyring struct{}
func (k NoKeyring) LookupAddressByKeyName(name string) ([]byte, error) {
return nil, errors.New("no keyring configured")
func (k NoKeyring) List() ([]string, error) {
return nil, errNoKeyring
}
func (k NoKeyring) LookupAddressByKeyName(name string) ([]byte, error) {
return nil, errNoKeyring
}
func (k NoKeyring) GetPubKey(name string) (cryptotypes.PubKey, error) {
return nil, errNoKeyring
}
func (k NoKeyring) Sign(name string, msg []byte, signMode signingv1beta1.SignMode) ([]byte, error) {
return nil, errNoKeyring
}

View File

@ -4,12 +4,21 @@ import (
"context"
"fmt"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"github.com/cockroachdb/errors"
"github.com/cosmos/cosmos-sdk/client"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/dynamicpb"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/autocli/flag"
"github.com/cosmos/cosmos-sdk/client"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtxconfig "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
)
// BuildMsgCommand builds the msg commands for all the provided modules. If a custom command is provided for a
@ -97,46 +106,56 @@ func (b *Builder) AddMsgServiceCommands(cmd *cobra.Command, cmdDescriptor *autoc
// BuildMsgMethodCommand returns a command that outputs the JSON representation of the message.
func (b *Builder) BuildMsgMethodCommand(descriptor protoreflect.MethodDescriptor, options *autocliv1.RpcCommandOptions) (*cobra.Command, error) {
jsonMarshalOptions := protojson.MarshalOptions{
Indent: " ",
UseProtoNames: true,
UseEnumNumbers: false,
EmitUnpopulated: true,
Resolver: b.TypeResolver,
}
cmd, err := b.buildMethodCommandCommon(descriptor, options, func(cmd *cobra.Command, input protoreflect.Message) error {
if noIdent, _ := cmd.Flags().GetBool(flagNoIndent); noIdent {
jsonMarshalOptions.Indent = ""
}
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &b.ClientCtx))
bz, err := jsonMarshalOptions.Marshal(input.Interface())
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
clientCtx, err := client.ReadPersistentCommandFlags(*b.ClientCtx, cmd.Flags())
// enable sign mode textual and config tx options
b.TxConfigOpts.EnabledSignModes = append(b.TxConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
b.TxConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfigWithTextual, err := authtx.NewTxConfigWithOptions(
codec.NewProtoCodec(clientCtx.InterfaceRegistry),
b.TxConfigOpts,
)
if err != nil {
return err
}
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
clientCtx.Output = cmd.OutOrStdout()
cmd.SetContext(context.WithValue(context.Background(), client.ClientContextKey, &clientCtx))
if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
// set signer to signer field if empty
fd := input.Descriptor().Fields().ByName(protoreflect.Name(flag.GetSignerFieldName(input.Descriptor())))
if addr := input.Get(fd).String(); addr == "" {
signerFromFlag := clientCtx.GetFromAddress()
signer, err := b.AddressCodec.BytesToString(signerFromFlag.Bytes())
if err != nil {
return fmt.Errorf("failed to set signer on message, got %v: %w", signerFromFlag, err)
}
input.Set(fd, protoreflect.ValueOfString(signer))
}
clientCtx, err = client.GetClientTxContext(cmd)
if err != nil {
return err
}
// AutoCLI uses protov2 messages, while the SDK only supports proto v1 messages.
// Here we use dynamicpb, to create a proto v1 compatible message.
// The SDK codec will handle protov2 -> protov1 (marshal)
msg := dynamicpb.NewMessage(input.Descriptor())
proto.Merge(msg, input.Interface())
return b.outOrStdoutFormat(cmd, bz)
return clienttx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
})
if b.AddTxConnFlags != nil {
b.AddTxConnFlags(cmd)
}
cmd.Flags().BoolP(flagNoIndent, "", false, "Do not indent JSON output")
// silence usage only for inner txs & queries commands
if cmd != nil {
cmd.SilenceUsage = true
}
return cmd, err

View File

@ -2,135 +2,97 @@ package autocli
import (
"fmt"
"strings"
"testing"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/protojson"
"gotest.tools/v3/assert"
"gotest.tools/v3/golden"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
"cosmossdk.io/client/v2/internal/testpb"
)
var buildModuleMsgCommand = func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := b.AddMsgServiceCommands(cmd, testCmdMsgDesc)
err := b.AddMsgServiceCommands(cmd, bankAutoCLI)
return cmd, err
}
var testCmdMsgDesc = &autocliv1.ServiceCommandDescriptor{
Service: testpb.Msg_ServiceDesc.ServiceName,
func buildCustomModuleMsgCommand(cmdDescriptor *autocliv1.ServiceCommandDescriptor) func(moduleName string, b *Builder) (*cobra.Command, error) {
return func(moduleName string, b *Builder) (*cobra.Command, error) {
cmd := topLevelCmd(moduleName, fmt.Sprintf("Transactions commands for the %s module", moduleName))
err := b.AddMsgServiceCommands(cmd, cmdDescriptor)
return cmd, err
}
}
var bankAutoCLI = &autocliv1.ServiceCommandDescriptor{
Service: bankv1beta1.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
Use: "send [pos1] [pos2] [pos3...]",
Version: "1.0",
Alias: []string{"s"},
SuggestFor: []string{"send"},
Example: "send 1 abc {}",
Short: "send msg the value provided by the user",
Long: "send msg the value provided by the user as a proto JSON object with populated with the provided fields and positional arguments",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{
ProtoField: "positional1",
},
{
ProtoField: "positional2",
},
{
ProtoField: "positional3_varargs",
Varargs: true,
},
},
FlagOptions: map[string]*autocliv1.FlagOptions{
"u32": {
Name: "uint32",
Shorthand: "u",
Usage: "some random uint32",
},
"i32": {
Usage: "some random int32",
DefaultValue: "3",
},
"u64": {
Usage: "some random uint64",
DefaultValue: "5",
},
"deprecated_field": {
Deprecated: "don't use this",
},
"shorthand_deprecated_field": {
Shorthand: "d",
Deprecated: "bad idea",
},
"hidden_bool": {
Hidden: true,
},
},
},
},
SubCommands: map[string]*autocliv1.ServiceCommandDescriptor{
// we test the sub-command functionality using the same service with different options
"deprecatedmsg": {
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
Deprecated: "dont use this",
Short: "deprecated subcommand",
},
},
},
"skipmsg": {
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
Skip: true,
Short: "skip subcommand",
},
},
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,
}
func TestMsgOptions(t *testing.T) {
func TestMsg(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "send",
"5", "6", "1foo",
"--uint32", "7",
"--u64", "8",
"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "1foo",
"--generate-only",
"--output", "json",
)
assert.NilError(t, err)
golden.Assert(t, out.String(), "msg-output.golden")
response := out.String()
var output testpb.MsgRequest
err = protojson.Unmarshal([]byte(response), &output)
assert.NilError(t, err)
assert.Equal(t, output.GetU32(), uint32(7))
assert.Equal(t, output.GetPositional1(), int32(5))
assert.Equal(t, output.GetPositional2(), "6")
}
func TestMsgOutputFormat(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "5", "6", "1foo",
out, err = runCmd(fixture.conn, fixture.b, 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: "to_address"}, {ProtoField: "amount"}},
// from_address should be automatically added
},
},
EnhanceCustomCommand: true,
}), "send",
"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "1foo",
"--from", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
"--generate-only",
"--output", "json",
)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "{"))
golden.Assert(t, out.String(), "msg-output.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "5", "6", "1foo",
"--output", "text",
out, err = runCmd(fixture.conn, fixture.b, 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: "to_address"}, {ProtoField: "amount"}},
FlagOptions: map[string]*autocliv1.FlagOptions{
"from_address": {Name: "sender"}, // use a custom flag for signer
},
},
},
EnhanceCustomCommand: true,
}), "send",
"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk", "1foo",
"--sender", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
"--generate-only",
"--output", "json",
)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "positional1: 5"))
golden.Assert(t, out.String(), "msg-output.golden")
}
func TestMsgOptionsError(t *testing.T) {
@ -138,92 +100,13 @@ func TestMsgOptionsError(t *testing.T) {
_, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "5",
"--uint32", "7",
"--u64", "8",
)
assert.ErrorContains(t, err, "requires at least 2 arg(s)")
assert.ErrorContains(t, err, "accepts 3 arg(s)")
_, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "5", "6", `{"denom":"foo","amount":"1"}`,
"--uint32", "7",
"--u64", "abc",
"send", "foo", "bar", "invalid",
)
assert.ErrorContains(t, err, "invalid argument ")
}
func TestDeprecatedMsg(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "1", "abc", "--deprecated-field", "foo",
)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "--deprecated-field has been deprecated"))
out, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send", "1", "abc", "5stake", "-d", "foo",
)
assert.NilError(t, err)
assert.Assert(t, strings.Contains(out.String(), "--shorthand-deprecated-field has been deprecated"))
}
func TestEverythingMsg(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleMsgCommand,
"send",
"1",
"abc",
"1234foo",
"4321foo",
"--output", "json",
"--a-bool",
"--an-enum", "two",
"--a-message", `{"bar":"abc", "baz":-3}`,
"--duration", "4h3s",
"--uint32", "27",
"--u64", "3267246890",
"--i32", "-253",
"--i64", "-234602347",
"--str", "def",
"--timestamp", "2019-01-02T00:01:02Z",
"--a-coin", "10000000foo",
"--an-address", "cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk",
"--bz", "c2RncXdlZndkZ3NkZw==",
"--page-count-total",
"--page-key", "MTIzNTQ4N3NnaGRhcw==",
"--page-limit", "1000",
"--page-offset", "10",
"--page-reverse",
"--bools", "true",
"--bools", "false,false,true",
"--enums", "one",
"--enums", "five",
"--enums", "two",
"--strings", "abc",
"--strings", "xyz",
"--strings", "xyz,qrs",
"--durations", "3s",
"--durations", "5s",
"--durations", "10h",
"--some-messages", "{}",
"--some-messages", `{"bar":"baz"}`,
"--some-messages", `{"baz":-1}`,
"--uints", "1,2,3",
"--uints", "4",
)
assert.NilError(t, err)
response := out.String()
var output testpb.MsgRequest
err = protojson.Unmarshal([]byte(response), &output)
assert.NilError(t, err)
assert.Equal(t, output.GetU32(), uint32(27))
assert.Equal(t, output.GetU64(), uint64(3267246890))
assert.Equal(t, output.GetPositional1(), int32(1))
assert.Equal(t, output.GetPositional2(), "abc")
assert.Equal(t, output.GetABool(), true)
assert.Equal(t, output.GetAnEnum(), testpb.Enum_ENUM_TWO)
assert.ErrorContains(t, err, "invalid argument")
}
func TestHelpMsg(t *testing.T) {
@ -236,19 +119,18 @@ func TestHelpMsg(t *testing.T) {
out, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "send", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-echo-msg.golden")
out, err = runCmd(fixture.conn, fixture.b, buildModuleMsgCommand, "deprecatedmsg", "send", "-h")
assert.NilError(t, err)
golden.Assert(t, out.String(), "help-deprecated-msg.golden")
}
func TestBuildMsgCommand(t *testing.T) {
func TestBuildCustomMsgCommand(t *testing.T) {
b := &Builder{}
customCommandCalled := false
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {
Tx: testCmdMsgDesc,
Tx: &autocliv1.ServiceCommandDescriptor{
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{},
},
},
},
}
@ -264,46 +146,6 @@ func TestBuildMsgCommand(t *testing.T) {
assert.Assert(t, customCommandCalled)
}
func TestErrorBuildMsgCommand(t *testing.T) {
fixture := initFixture(t)
b := fixture.b
b.AddQueryConnFlags = nil
b.AddTxConnFlags = nil
commandDescriptor := &autocliv1.ServiceCommandDescriptor{
Service: testpb.Msg_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "Send",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{
{
ProtoField: "un-existent-proto-field",
},
},
},
},
}
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {
Tx: commandDescriptor,
},
},
AddressCodec: b.AddressCodec,
ValidatorAddressCodec: b.ValidatorAddressCodec,
ClientCtx: b.ClientCtx,
}
_, err := b.BuildMsgCommand(appOptions, nil)
assert.ErrorContains(t, err, "can't find field un-existent-proto-field")
nonExistentService := &autocliv1.ServiceCommandDescriptor{Service: "un-existent-service"}
appOptions.ModuleOptions["test"].Tx = nonExistentService
_, err = b.BuildMsgCommand(appOptions, nil)
assert.ErrorContains(t, err, "can't find service un-existent-service")
}
func TestNotFoundErrorsMsg(t *testing.T) {
fixture := initFixture(t)
b := fixture.b
@ -355,38 +197,3 @@ func TestNotFoundErrorsMsg(t *testing.T) {
})
assert.ErrorContains(t, err, "can't find field un-existent-flag")
}
func TestEnhanceMessageCommand(t *testing.T) {
b := &Builder{}
// Test that the command has a subcommand
cmd := &cobra.Command{Use: "test"}
cmd.AddCommand(&cobra.Command{Use: "test"})
appOptions := AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {},
},
}
err := b.enhanceCommandCommon(cmd, msgCmdType, appOptions, map[string]*cobra.Command{})
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions.ModuleOptions = map[string]*autocliv1.ModuleOptions{}
customCommands := map[string]*cobra.Command{
"test2": {Use: "test"},
}
err = b.enhanceCommandCommon(cmd, msgCmdType, appOptions, customCommands)
assert.NilError(t, err)
cmd = &cobra.Command{Use: "test"}
appOptions = AppOptions{
ModuleOptions: map[string]*autocliv1.ModuleOptions{
"test": {Tx: nil},
},
}
customCommands = map[string]*cobra.Command{}
err = b.enhanceCommandCommon(cmd, msgCmdType, appOptions, customCommands)
assert.NilError(t, err)
}

View File

@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra"
"google.golang.org/protobuf/reflect/protoreflect"
"cosmossdk.io/client/v2/internal/flags"
"cosmossdk.io/client/v2/internal/util"
)
@ -111,7 +112,7 @@ func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescript
}
cmd, err := b.buildMethodCommandCommon(descriptor, options, func(cmd *cobra.Command, input protoreflect.Message) error {
if noIndent, _ := cmd.Flags().GetBool(flagNoIndent); noIndent {
if noIndent, _ := cmd.Flags().GetBool(flags.FlagNoIndent); noIndent {
encoderOptions.Indent = ""
}
@ -141,7 +142,12 @@ func (b *Builder) BuildQueryMethodCommand(descriptor protoreflect.MethodDescript
if b.AddQueryConnFlags != nil {
b.AddQueryConnFlags(cmd)
cmd.Flags().BoolP(flagNoIndent, "", false, "Do not indent JSON output")
cmd.Flags().BoolP(flags.FlagNoIndent, "", false, "Do not indent JSON output")
}
// silence usage only for inner txs & queries commands
if cmd != nil {
cmd.SilenceUsage = true
}
return cmd, nil

View File

@ -613,7 +613,7 @@ func TestOutputFormat(t *testing.T) {
assert.Assert(t, strings.Contains(out.String(), " positional1: 1"))
}
func TestHelp(t *testing.T) {
func TestHelpQuery(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "-h")
@ -633,7 +633,7 @@ func TestHelp(t *testing.T) {
golden.Assert(t, out.String(), "help-skip.golden")
}
func TestDeprecated(t *testing.T) {
func TestDeprecatedQuery(t *testing.T) {
fixture := initFixture(t)
out, err := runCmd(fixture.conn, fixture.b, buildModuleQueryCommand, "echo",
@ -670,7 +670,7 @@ func TestBuildCustomQueryCommand(t *testing.T) {
assert.Assert(t, customCommandCalled)
}
func TestNotFoundErrors(t *testing.T) {
func TestNotFoundErrorsQuery(t *testing.T) {
fixture := initFixture(t)
b := fixture.b
b.AddQueryConnFlags = nil

View File

@ -1,65 +0,0 @@
Command "send" is deprecated, dont use this
deprecated subcommand
Usage:
test deprecatedmsg send [flags]
Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin
--a-message testpb.AMessage (json)
--a-validator-address account address or key name
-a, --account-number uint The account number of the signing account (offline mode only)
--an-address account address or key name
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--aux Generate aux signer data instead of sending a tx
--bools bools (default [])
-b, --broadcast-mode string Transaction broadcasting mode (sync|async) (default "sync")
--bz binary
--chain-id string The network chain ID
--deprecated-field string
--dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
--duration duration
--durations duration (repeated)
--enums Enum (unspecified | one | two | five | neg-three) (repeated)
--fee-granter string Fee granter grants fees for the transaction
--fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer
--fees string Fees to pay along with transaction; eg: 10uatom
--from string Name or address of private key with which to sign
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
-h, --help help for send
--hidden-bool
--i32 int32
--i64 int
--keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory) (default "os")
--keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used
--ledger Use a connected Ledger device
--no-indent Do not indent JSON output
--node string <host>:<port> to CometBFT rpc interface for this chain (default "tcp://localhost:26657")
--note string Note to add a description to the transaction (previously --memo)
--offline Offline mode (does not allow any online functionality)
-o, --output string Output format (text|json) (default "json")
--page-count-total
--page-key binary
--page-limit uint
--page-offset uint
--page-reverse
--positional1 int32
--positional2 string
--positional3-varargs cosmos.base.v1beta1.Coin (repeated)
-s, --sequence uint The sequence number of the signing account (offline mode only)
--shorthand-deprecated-field string
--sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature
--some-messages testpb.AMessage (json) (repeated)
--str string
--strings strings
--timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height
--timestamp timestamp (RFC 3339)
--tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator
--u32 uint32
--u64 uint
--uints uints (default [])
-y, --yes Skip tx broadcasting prompt confirmation

View File

@ -1,67 +1,32 @@
send msg the value provided by the user as a proto JSON object with populated with the provided fields and positional arguments
Send coins from one account to another
Usage:
test send [pos1] [pos2] [pos3...] [flags]
Aliases:
send, s
Examples:
send 1 abc {}
test send [from_key_or_address] [to_address] [amount] [flags]
Flags:
--a-bool
--a-coin cosmos.base.v1beta1.Coin
--a-message testpb.AMessage (json)
--a-validator-address account address or key name
-a, --account-number uint The account number of the signing account (offline mode only)
--an-address account address or key name
--an-enum Enum (unspecified | one | two | five | neg-three) (default unspecified)
--aux Generate aux signer data instead of sending a tx
--bools bools (default [])
-b, --broadcast-mode string Transaction broadcasting mode (sync|async) (default "sync")
--bz binary
--chain-id string The network chain ID
--deprecated-field string (DEPRECATED: don't use this)
--dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
--duration duration
--durations duration (repeated)
--enums Enum (unspecified | one | two | five | neg-three) (repeated)
--fee-granter string Fee granter grants fees for the transaction
--fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer
--fees string Fees to pay along with transaction; eg: 10uatom
--from string Name or address of private key with which to sign
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
-h, --help help for send
--i32 int32 some random int32
--i64 int
--keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory) (default "os")
--keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used
--ledger Use a connected Ledger device
--no-indent Do not indent JSON output
--node string <host>:<port> to CometBFT rpc interface for this chain (default "tcp://localhost:26657")
--note string Note to add a description to the transaction (previously --memo)
--offline Offline mode (does not allow any online functionality)
-o, --output string Output format (text|json) (default "json")
--page-count-total
--page-key binary
--page-limit uint
--page-offset uint
--page-reverse
-s, --sequence uint The sequence number of the signing account (offline mode only)
-d, --shorthand-deprecated-field string (DEPRECATED: bad idea)
--sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature
--some-messages testpb.AMessage (json) (repeated)
--str string
--strings strings
--timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height
--timestamp timestamp (RFC 3339)
--tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator
--u64 uint some random uint64
-u, --uint32 uint32 some random uint32
--uints uints (default [])
-v, --version version for send
-y, --yes Skip tx broadcasting prompt confirmation
-a, --account-number uint The account number of the signing account (offline mode only)
--aux Generate aux signer data instead of sending a tx
-b, --broadcast-mode string Transaction broadcasting mode (sync|async) (default "sync")
--chain-id string The network chain ID
--dry-run ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)
--fee-granter string Fee granter grants fees for the transaction
--fee-payer string Fee payer pays fees for the transaction instead of deducting from the signer
--fees string Fees to pay along with transaction; eg: 10uatom
--from string Name or address of private key with which to sign
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
-h, --help help for send
--keyring-backend string Select keyring's backend (os|file|kwallet|pass|test|memory) (default "os")
--keyring-dir string The client Keyring directory; if omitted, the default 'home' directory will be used
--ledger Use a connected Ledger device
--node string <host>:<port> to CometBFT rpc interface for this chain (default "tcp://localhost:26657")
--note string Note to add a description to the transaction (previously --memo)
--offline Offline mode (does not allow any online functionality)
-o, --output string Output format (text|json) (default "json")
-s, --sequence uint The sequence number of the signing account (offline mode only)
--sign-mode string Choose sign mode (direct|amino-json|direct-aux), this is an advanced feature
--timeout-height uint Set a block timeout height to prevent the tx from being committed past a certain height
--tip string Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator
-y, --yes Skip tx broadcasting prompt confirmation

View File

@ -5,11 +5,13 @@ Usage:
test [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
deprecatedmsg Tx commands for the testpb.Msg service
help Help about any command
send send msg the value provided by the user
skipmsg Tx commands for the testpb.Msg service
burn
completion Generate the autocompletion script for the specified shell
help Help about any command
multi-send
send Send coins from one account to another
set-send-enabled
update-params
Flags:
-h, --help help for test

View File

@ -0,0 +1 @@
{"body":{"messages":[{"@type":"/cosmos.bank.v1beta1.MsgSend","from_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","to_address":"cosmos1y74p8wyy4enfhfn342njve6cjmj5c8dtl6emdk","amount":[{"denom":"foo","amount":"1"}]}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""},"tip":null},"signatures":[]}

View File

@ -6,15 +6,14 @@ require (
cosmossdk.io/api v0.7.1
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
cosmossdk.io/log v1.2.1
cosmossdk.io/x/tx v0.10.0
github.com/cockroachdb/errors v1.11.1
github.com/cosmos/cosmos-proto v1.0.0-beta.3
github.com/cosmos/cosmos-sdk v0.50.0-rc.1
github.com/cosmos/cosmos-sdk v0.50.0-rc.1.0.20231005110808-059498db8691
github.com/cosmos/gogoproto v1.4.11
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
google.golang.org/grpc v1.58.1
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
gotest.tools/v3 v3.5.0
sigs.k8s.io/yaml v1.3.0
@ -23,6 +22,7 @@ require (
require (
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/errors v1.0.0 // indirect
cosmossdk.io/log v1.2.1 // indirect
cosmossdk.io/math v1.1.3-rc.1 // indirect
cosmossdk.io/store v1.0.0-rc.0 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
@ -69,6 +69,7 @@ require (
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.1.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.2 // indirect
@ -109,7 +110,7 @@ require (
github.com/mtibben/percent v0.2.1 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@ -142,12 +143,14 @@ require (
golang.org/x/sys v0.12.0 // indirect
golang.org/x/term v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
nhooyr.io/websocket v1.8.6 // indirect
pgregory.net/rapid v1.1.0 // indirect
)
replace github.com/cosmos/cosmos-sdk => ./../../

View File

@ -178,8 +178,6 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0
github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U=
github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o=
github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I=
github.com/cosmos/cosmos-sdk v0.50.0-rc.1 h1:1Z+SgLg8S2+DoiePz9aO5dSjJUgag8VFhFUSD/HGvOU=
github.com/cosmos/cosmos-sdk v0.50.0-rc.1/go.mod h1:JbgPLZrh+yX+4+n1CPJ/uL9HrhZw6QVg0q7cTq2Iwq0=
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
@ -641,8 +639,8 @@ github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0Mw
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b h1:vab8deKC4QoIfm9fJM59iuNz1ELGsuLoYYpiF+pHiG8=
@ -795,6 +793,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zondax/hid v0.9.1 h1:gQe66rtmyZ8VeGFcOpbuH3r7erYtNEAezCAYu8LdkJo=
github.com/zondax/hid v0.9.1/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v0.14.1 h1:Pip65OOl4iJ84WTpA4BKChvOufMhhbxED3BaihoZN4c=
@ -874,6 +873,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -944,6 +944,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1099,6 +1100,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E=
golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1176,12 +1178,12 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1208,8 +1210,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@ -0,0 +1,19 @@
package flags
// This defines flag names that can be used in autocli.
const (
// FlagFrom is the flag to set the from address with which to sign the transaction.
FlagFrom = "from"
// FlagOutput is the flag to set the output format.
FlagOutput = "output"
// FlagNoIndent is the flag to not indent the output.
FlagNoIndent = "no-indent"
)
// List of supported output formats
const (
OutputFormatJSON = "json"
OutputFormatText = "text"
)

View File

@ -12,16 +12,26 @@ import (
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type bankSendWrapper struct {
*banktypes.MsgSend
}
func (msg bankSendWrapper) GetSigners() []sdk.AccAddress {
fromAddress, _ := sdk.AccAddressFromBech32(msg.FromAddress)
return []sdk.AccAddress{fromAddress}
}
func BenchmarkLegacyGetSigners(b *testing.B) {
_, _, addr := testdata.KeyTestPubAddr()
msg := &banktypes.MsgSend{
msg := bankSendWrapper{&banktypes.MsgSend{
FromAddress: addr.String(),
ToAddress: "",
Amount: nil,
}
}}
b.ResetTimer()
for i := 0; i < b.N; i++ {

View File

@ -4,6 +4,7 @@ import (
fmt "fmt"
"github.com/cosmos/gogoproto/proto"
protov2 "google.golang.org/protobuf/proto"
errorsmod "cosmossdk.io/errors"
@ -63,13 +64,21 @@ func NewAnyWithValue(v proto.Message) (*Any, error) {
return nil, errorsmod.Wrap(sdkerrors.ErrPackAny, "Expecting non nil value to create a new Any")
}
bz, err := proto.Marshal(v)
var (
bz []byte
err error
)
if msg, ok := v.(protov2.Message); ok {
bz, err = protov2.Marshal(msg)
} else {
bz, err = proto.Marshal(v)
}
if err != nil {
return nil, err
}
return &Any{
TypeUrl: "/" + proto.MessageName(v),
TypeUrl: MsgTypeURL(v),
Value: bz,
cachedValue: v,
}, nil
@ -94,8 +103,17 @@ func UnsafePackAny(x interface{}) *Any {
// the packed value so that it can be retrieved from GetCachedValue without
// unmarshaling
func (any *Any) pack(x proto.Message) error {
any.TypeUrl = "/" + proto.MessageName(x)
bz, err := proto.Marshal(x)
any.TypeUrl = MsgTypeURL(x)
var (
bz []byte
err error
)
if msg, ok := x.(protov2.Message); ok {
bz, err = protov2.Marshal(msg)
} else {
bz, err = proto.Marshal(x)
}
if err != nil {
return err
}

View File

@ -187,7 +187,7 @@ func (registry *interfaceRegistry) EnsureRegistered(impl interface{}) error {
// same typeURL.
func (registry *interfaceRegistry) RegisterImplementations(iface interface{}, impls ...proto.Message) {
for _, impl := range impls {
typeURL := "/" + proto.MessageName(impl)
typeURL := MsgTypeURL(impl)
registry.registerImpl(iface, typeURL, impl)
}
}

15
codec/types/util.go Normal file
View File

@ -0,0 +1,15 @@
package types
import (
"github.com/cosmos/gogoproto/proto"
protov2 "google.golang.org/protobuf/proto"
)
// MsgTypeURL returns the TypeURL of a `sdk.Msg`.
func MsgTypeURL(msg proto.Message) string {
if m, ok := msg.(protov2.Message); ok {
return "/" + string(m.ProtoReflect().Descriptor().FullName())
}
return "/" + proto.MessageName(msg)
}

86
crypto/keyring/autocli.go Normal file
View File

@ -0,0 +1,86 @@
package keyring
import (
signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// autoCLIKeyring represents the keyring interface used by the AutoCLI.
// It purposely does not import the AutoCLI package to avoid circular dependencies.
type autoCLIKeyring interface {
// List returns the names of all keys stored in the keyring.
List() ([]string, error)
// LookupAddressByKeyName returns the address of the key with the given name.
LookupAddressByKeyName(name string) ([]byte, error)
// GetPubKey returns the public key of the key with the given name.
GetPubKey(name string) (cryptotypes.PubKey, error)
// Sign signs the given bytes with the key with the given name.
Sign(name string, msg []byte, signMode signingv1beta1.SignMode) ([]byte, error)
}
// NewAutoCLIKeyring wraps the SDK keyring and make it compatible with the AutoCLI keyring interfaces.
func NewAutoCLIKeyring(kr Keyring) (autoCLIKeyring, error) {
return &autoCLIKeyringAdapter{kr}, nil
}
type autoCLIKeyringAdapter struct {
Keyring
}
func (a *autoCLIKeyringAdapter) List() ([]string, error) {
list, err := a.Keyring.List()
if err != nil {
return nil, err
}
names := make([]string, len(list))
for i, key := range list {
names[i] = key.Name
}
return names, nil
}
// LookupAddressByKeyName returns the address of a key stored in the keyring
func (a *autoCLIKeyringAdapter) LookupAddressByKeyName(name string) ([]byte, error) {
record, err := a.Keyring.Key(name)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}
func (a *autoCLIKeyringAdapter) GetPubKey(name string) (cryptotypes.PubKey, error) {
record, err := a.Keyring.Key(name)
if err != nil {
return nil, err
}
return record.GetPubKey()
}
func (a *autoCLIKeyringAdapter) Sign(name string, msg []byte, signMode signingv1beta1.SignMode) ([]byte, error) {
record, err := a.Keyring.Key(name)
if err != nil {
return nil, err
}
sdkSignMode, err := authsigning.APISignModeToInternal(signMode)
if err != nil {
return nil, err
}
signBytes, _, err := a.Keyring.Sign(record.Name, msg, sdkSignMode)
return signBytes, err
}

View File

@ -102,9 +102,6 @@ type Keyring interface {
Exporter
Migrator
// Implements client/v2 keyring interface
LookupAddressByKeyName(name string) ([]byte, error)
}
// Signer is implemented by key stores that want to provide signing capabilities.
@ -622,21 +619,6 @@ func (ks keystore) SupportedAlgorithms() (SigningAlgoList, SigningAlgoList) {
return ks.options.SupportedAlgos, ks.options.SupportedAlgosLedger
}
// LookupAddressByKeyName returns the address of a key stored in the keyring
func (ks keystore) LookupAddressByKeyName(name string) ([]byte, error) {
record, err := ks.Key(name)
if err != nil {
return nil, err
}
addr, err := record.GetAddress()
if err != nil {
return nil, err
}
return addr, nil
}
// SignWithLedger signs a binary message with the ledger device referenced by an Info object
// and returns the signed bytes and the public key. It returns an error if the device could
// not be queried or it returned an error.

View File

@ -4,7 +4,7 @@ go 1.21
require (
cosmossdk.io/api v0.7.1
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/core v0.11.0
cosmossdk.io/depinject v1.0.0-alpha.4
@ -33,7 +33,7 @@ require (
)
require (
cloud.google.com/go v0.110.6 // indirect
cloud.google.com/go v0.110.7 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.1 // indirect
@ -142,7 +142,7 @@ require (
github.com/mtibben/percent v0.2.1 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@ -177,10 +177,10 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/grpc v1.58.1 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -32,8 +32,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q=
cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/api v0.7.1 h1:PNQ1xN8+/0hj/sSD0ANqjkgfXFys+bZ5L8Hg7uzoUTU=
cosmossdk.io/api v0.7.1/go.mod h1:ure9edhcROIHsngavM6mBLilMGFnfjhV/AaYhEMUkdo=
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834 h1:08rY7bypF6jSE8XGJ9i5iiEO20gExOziLnI2NbKIxWo=
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834/go.mod h1:6kpnEjoEwZIFZkxMPy+/8tKJggRy2OQ6X1LzrrVu8nM=
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141 h1:ovyUcvPX740eqC7bnGZpw4yn5GS2bNZ5jacRqiDwqU8=
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141/go.mod h1:0ycdqzdjVeUdKqgBbaxqSsc1C18GJc3uEF+uphv/MPg=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=
@ -866,8 +866,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b h1:vab8deKC4QoIfm9fJM59iuNz1ELGsuLoYYpiF+pHiG8=
@ -1605,12 +1605,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1652,8 +1652,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

View File

@ -14,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
"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/tx/signing"
@ -97,8 +98,8 @@ func NewRootCmd() *cobra.Command {
// add keyring to autocli opts
autoCliOpts := tempApp.AutoCliOpts()
initClientCtx, _ = config.ReadFromClientConfig(initClientCtx)
autoCliOpts.Keyring = initClientCtx.Keyring
autoCliOpts.ClientCtx = &initClientCtx
autoCliOpts.Keyring, _ = keyring.NewAutoCLIKeyring(initClientCtx.Keyring)
autoCliOpts.ClientCtx = initClientCtx
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)

View File

@ -18,6 +18,7 @@ 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"
@ -33,7 +34,7 @@ func NewRootCmd() *cobra.Command {
txConfigOpts tx.ConfigOptions
autoCliOpts autocli.AppOptions
moduleBasicManager module.BasicManager
initClientCtx *client.Context
clientCtx client.Context
)
if err := depinject.Inject(
@ -50,7 +51,7 @@ func NewRootCmd() *cobra.Command {
&txConfigOpts,
&autoCliOpts,
&moduleBasicManager,
&initClientCtx,
&clientCtx,
); err != nil {
panic(err)
}
@ -64,7 +65,6 @@ func NewRootCmd() *cobra.Command {
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
clientCtx := *initClientCtx
clientCtx = clientCtx.WithCmdContext(cmd.Context())
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
@ -87,7 +87,6 @@ func NewRootCmd() *cobra.Command {
return err
}
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
if err := client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
@ -99,7 +98,7 @@ func NewRootCmd() *cobra.Command {
},
}
initRootCmd(rootCmd, initClientCtx.TxConfig, initClientCtx.InterfaceRegistry, initClientCtx.Codec, moduleBasicManager)
initRootCmd(rootCmd, clientCtx.TxConfig, clientCtx.InterfaceRegistry, clientCtx.Codec, moduleBasicManager)
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
@ -113,7 +112,7 @@ func ProvideClientContext(
interfaceRegistry codectypes.InterfaceRegistry,
txConfig client.TxConfig,
legacyAmino *codec.LegacyAmino,
) *client.Context {
) client.Context {
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
@ -127,14 +126,14 @@ func ProvideClientContext(
// Read the config again to overwrite the default values with the values from the config file
clientCtx, _ = config.ReadFromClientConfig(clientCtx)
return &clientCtx
return clientCtx
}
func ProvideKeyring(clientCtx *client.Context, addressCodec address.Codec) (clientv2keyring.Keyring, error) {
kb, err := client.NewKeyringFromBackend(*clientCtx, clientCtx.Keyring.Backend())
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 kb, nil
return keyring.NewAutoCLIKeyring(kb)
}

View File

@ -25,19 +25,19 @@ require (
github.com/golang/mock v1.6.0
github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.4
google.golang.org/grpc v1.58.1
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0
gotest.tools/v3 v3.5.1
pgregory.net/rapid v1.1.0
)
require (
cloud.google.com/go v0.110.6 // indirect
cloud.google.com/go v0.110.7 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.1 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834 // indirect
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141 // indirect
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/x/circuit v0.0.0-20230925151519-64e0e8980834 // indirect
filippo.io/edwards25519 v1.0.0 // indirect
@ -140,7 +140,7 @@ require (
github.com/mtibben/percent v0.2.1 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
@ -178,9 +178,9 @@ require (
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

View File

@ -32,8 +32,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU=
cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA=
cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q=
cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw=
cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY=
cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI=
@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/api v0.7.1 h1:PNQ1xN8+/0hj/sSD0ANqjkgfXFys+bZ5L8Hg7uzoUTU=
cosmossdk.io/api v0.7.1/go.mod h1:ure9edhcROIHsngavM6mBLilMGFnfjhV/AaYhEMUkdo=
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834 h1:08rY7bypF6jSE8XGJ9i5iiEO20gExOziLnI2NbKIxWo=
cosmossdk.io/client/v2 v2.0.0-20230925151519-64e0e8980834/go.mod h1:6kpnEjoEwZIFZkxMPy+/8tKJggRy2OQ6X1LzrrVu8nM=
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141 h1:ovyUcvPX740eqC7bnGZpw4yn5GS2bNZ5jacRqiDwqU8=
cosmossdk.io/client/v2 v2.0.0-20231005120212-0062bf2e7141/go.mod h1:0ycdqzdjVeUdKqgBbaxqSsc1C18GJc3uEF+uphv/MPg=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=
@ -867,8 +867,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b h1:vab8deKC4QoIfm9fJM59iuNz1ELGsuLoYYpiF+pHiG8=
@ -1606,12 +1606,12 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw
google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM=
google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1653,8 +1653,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=

View File

@ -9,6 +9,7 @@ import (
protov2 "google.golang.org/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)
@ -95,13 +96,7 @@ type TxDecoder func(txBytes []byte) (Tx, error)
type TxEncoder func(tx Tx) ([]byte, error)
// MsgTypeURL returns the TypeURL of a `sdk.Msg`.
func MsgTypeURL(msg proto.Message) string {
if m, ok := msg.(protov2.Message); ok {
return "/" + string(m.ProtoReflect().Descriptor().FullName())
}
return "/" + proto.MessageName(msg)
}
var MsgTypeURL = codectypes.MsgTypeURL
// GetMsgFromTypeURL returns a `sdk.Msg` message type from a type URL
func GetMsgFromTypeURL(cdc codec.Codec, input string) (Msg, error) {

View File

@ -16,7 +16,7 @@ type SigVerifiableTx interface {
}
// Tx defines a transaction interface that supports all standard message, signature
// fee, memo, tips, and auxiliary interfaces.
// fee, memo and auxiliary interfaces.
type Tx interface {
SigVerifiableTx

View File

@ -15,12 +15,6 @@ func NewMsgSend(fromAddr, toAddr sdk.AccAddress, amount sdk.Coins) *MsgSend {
return &MsgSend{FromAddress: fromAddr.String(), ToAddress: toAddr.String(), Amount: amount}
}
// GetSigners Implements Msg.
func (msg MsgSend) GetSigners() []sdk.AccAddress {
fromAddress, _ := sdk.AccAddressFromBech32(msg.FromAddress)
return []sdk.AccAddress{fromAddress}
}
// NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg.
func NewMsgMultiSend(in Input, out []Output) *MsgMultiSend {
return &MsgMultiSend{Inputs: []Input{in}, Outputs: out}