Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(client/v2): sync client/v2 with main (backport #22493, #22817) #22820

Merged
merged 4 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/v2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,22 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes

* [#17709](https://github.com/cosmos/cosmos-sdk/pull/17709) Address codecs have been removed from `autocli.AppOptions` and `flag.Builder`. Instead client/v2 uses the address codecs present in the context (introduced in [#17503](https://github.com/cosmos/cosmos-sdk/pull/17503)).
* [#22493](https://github.com/cosmos/cosmos-sdk/pull/22493) Refactored `client/v2` package to remove v1 context dependencies, while introducing new packages for client configuration, context management, and formatted output with improved transaction handling and flag support.

### Bug Fixes

* [#21853](https://github.com/cosmos/cosmos-sdk/pull/21853) Fix `*big.Int` unmarshalling in txs.
* [#22576](https://github.com/cosmos/cosmos-sdk/pull/22576) Fix duplicate command addition in `autocli` when custom enhanced command has a different name than module name
* [#22817](https://github.com/cosmos/cosmos-sdk/pull/22817) Add DecCoin support in autocli flag builder.

## [v2.0.0-beta.5] - 2024-09-18

### Improvements

* [#21712](https://github.com/cosmos/cosmos-sdk/pull/21712) Marshal `type` field as proto message url in queries instead of amino name.

## [v2.0.0-beta.4] - 2024-07-16

### Bug Fixes

* [#20964](https://github.com/cosmos/cosmos-sdk/pull/20964) Fix `GetNodeHomeDirectory` helper in `client/v2/helpers` to respect the `(PREFIX)_HOME` environment variable.
Expand Down
34 changes: 21 additions & 13 deletions client/v2/autocli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@ package autocli
import (
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/protobuf/reflect/protoregistry"

autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
"cosmossdk.io/client/v2/autocli/flag"
"cosmossdk.io/core/address"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/x/tx/signing"

"github.com/cosmos/cosmos-sdk/client"
sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)

// AppOptions are input options for an autocli enabled app. These options can be built via depinject based on an app config.
Expand All @@ -38,8 +39,15 @@ 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 address.Codec // AddressCodec is used to encode/decode account addresses.
ValidatorAddressCodec address.ValidatorAddressCodec // ValidatorAddressCodec is used to encode/decode validator addresses.
ConsensusAddressCodec address.ConsensusAddressCodec // ConsensusAddressCodec is used to encode/decode consensus addresses.

// Cdc is the codec used for binary encoding/decoding of messages.
Cdc codec.Codec

// TxConfigOpts contains options for configuring transaction handling.
TxConfigOpts authtx.ConfigOptions

skipValidation bool
}
Expand All @@ -63,19 +71,19 @@ func (appOptions AppOptions) EnhanceRootCommand(rootCmd *cobra.Command) error {
builder := &Builder{
Builder: flag.Builder{
TypeResolver: protoregistry.GlobalTypes,
FileResolver: appOptions.ClientCtx.InterfaceRegistry,
AddressCodec: appOptions.ClientCtx.AddressCodec,
ValidatorAddressCodec: appOptions.ClientCtx.ValidatorAddressCodec,
ConsensusAddressCodec: appOptions.ClientCtx.ConsensusAddressCodec,
},
GetClientConn: func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
return client.GetClientQueryContext(cmd)
FileResolver: appOptions.Cdc.InterfaceRegistry(),
AddressCodec: appOptions.AddressCodec,
ValidatorAddressCodec: appOptions.ValidatorAddressCodec,
ConsensusAddressCodec: appOptions.ConsensusAddressCodec,
},
GetClientConn: getQueryClientConn(appOptions.Cdc),
AddQueryConnFlags: func(c *cobra.Command) {
sdkflags.AddQueryFlagsToCmd(c)
sdkflags.AddKeyringFlags(c.Flags())
},
AddTxConnFlags: sdkflags.AddTxFlagsToCmd,
AddTxConnFlags: sdkflags.AddTxFlagsToCmd,
Cdc: appOptions.Cdc,
EnabledSignModes: appOptions.TxConfigOpts.EnabledSignModes,
}

return appOptions.EnhanceRootCommandWithBuilder(rootCmd, builder)
Expand Down Expand Up @@ -170,9 +178,9 @@ func NewAppOptionsFromConfig(

return AppOptions{
Modules: cfg.Modules,
ClientCtx: client.Context{InterfaceRegistry: interfaceRegistry},
ModuleOptions: moduleOptions,
skipValidation: true,
Cdc: codec.NewProtoCodec(interfaceRegistry),
}, nil
}

Expand Down
6 changes: 6 additions & 0 deletions client/v2/autocli/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"google.golang.org/grpc"

"cosmossdk.io/client/v2/autocli/flag"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)

// Builder manages options for building CLI commands.
Expand All @@ -19,6 +22,9 @@ type Builder struct {
// AddQueryConnFlags and AddTxConnFlags are functions that add flags to query and transaction commands
AddQueryConnFlags func(*cobra.Command)
AddTxConnFlags func(*cobra.Command)

Cdc codec.Codec
EnabledSignModes []signing.SignMode
}

// ValidateAndComplete the builder fields.
Expand Down
157 changes: 139 additions & 18 deletions client/v2/autocli/common.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
package autocli

import (
"context"
"crypto/tls"
"fmt"
"strings"
"strconv"

"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
grpcinsecure "google.golang.org/grpc/credentials/insecure"
"google.golang.org/protobuf/reflect/protoreflect"
"sigs.k8s.io/yaml"

autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
apitxsigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/client/v2/autocli/config"
"cosmossdk.io/client/v2/autocli/keyring"
"cosmossdk.io/client/v2/broadcast/comet"
clientcontext "cosmossdk.io/client/v2/context"
"cosmossdk.io/client/v2/internal/flags"
"cosmossdk.io/client/v2/internal/print"
"cosmossdk.io/client/v2/internal/util"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)

type cmdType int
Expand Down Expand Up @@ -62,8 +73,13 @@
}
cmd.Args = binder.CobraArgs

cmd.PreRunE = b.preRunE()

cmd.RunE = func(cmd *cobra.Command, args []string) error {
ctx = cmd.Context()
ctx, err = b.getContext(cmd)
if err != nil {
return err
}

input, err := binder.BuildMessage(args)
if err != nil {
Expand Down Expand Up @@ -237,27 +253,132 @@

// outOrStdoutFormat formats the output based on the output flag and writes it to the command's output stream.
func (b *Builder) outOrStdoutFormat(cmd *cobra.Command, out []byte) error {
clientCtx := client.Context{}
if v := cmd.Context().Value(client.ClientContextKey); v != nil {
clientCtx = *(v.(*client.Context))
p, err := print.NewPrinter(cmd)
if err != nil {
return err
}
return p.PrintBytes(out)
}

// getContext creates and returns a new context.Context with an autocli.Context value.
// It initializes a printer and, if necessary, a keyring based on command flags.
func (b *Builder) getContext(cmd *cobra.Command) (context.Context, error) {
// if the command uses the keyring this must be set
var (
k keyring.Keyring
err error
)
if cmd.Flags().Lookup(flags.FlagKeyringDir) != nil && cmd.Flags().Lookup(flags.FlagKeyringBackend) != nil {
k, err = keyring.NewKeyringFromFlags(cmd.Flags(), b.AddressCodec, cmd.InOrStdin(), b.Cdc)
if err != nil {
return nil, err
}
} else {
k = keyring.NoKeyring{}
}
flagSet := cmd.Flags()
if clientCtx.OutputFormat == "" || flagSet.Changed(flags.FlagOutput) {
output, _ := flagSet.GetString(flags.FlagOutput)
clientCtx = clientCtx.WithOutputFormat(output)

clientCtx := clientcontext.Context{
Flags: cmd.Flags(),
AddressCodec: b.AddressCodec,
ValidatorAddressCodec: b.ValidatorAddressCodec,
ConsensusAddressCodec: b.ConsensusAddressCodec,
Cdc: b.Cdc,
Keyring: k,
EnabledSignModes: signModesToApiSignModes(b.EnabledSignModes),
}

var err error
outputType := clientCtx.OutputFormat
// if the output type is text, convert the json to yaml
// if output type is json or nil, default to json
if outputType == flags.OutputFormatText {
out, err = yaml.JSONToYAML(out)
return clientcontext.SetInContext(cmd.Context(), clientCtx), nil
}

// preRunE returns a function that sets flags from the configuration before running a command.
// It is used as a PreRunE hook for cobra commands to ensure flags are properly initialized
// from the configuration before command execution.
func (b *Builder) preRunE() func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
err := b.setFlagsFromConfig(cmd)
if err != nil {
return err
}

return nil
}
}

// setFlagsFromConfig sets command flags from the provided configuration.
// It only sets flags that haven't been explicitly changed by the user.
func (b *Builder) setFlagsFromConfig(cmd *cobra.Command) error {
conf, err := config.CreateClientConfigFromFlags(cmd.Flags())
if err != nil {
return err
}

flagsToSet := map[string]string{
flags.FlagChainID: conf.ChainID,
flags.FlagKeyringBackend: conf.KeyringBackend,
flags.FlagFrom: conf.KeyringDefaultKeyName,
flags.FlagOutput: conf.Output,
flags.FlagNode: conf.Node,
flags.FlagBroadcastMode: conf.BroadcastMode,
flags.FlagGrpcAddress: conf.GRPC.Address,
flags.FlagGrpcInsecure: strconv.FormatBool(conf.GRPC.Insecure),
}

for flagName, value := range flagsToSet {
if flag := cmd.Flags().Lookup(flagName); flag != nil && !cmd.Flags().Changed(flagName) {
if err := cmd.Flags().Set(flagName, value); err != nil {
return err
}
}
}

Check warning

Code scanning / CodeQL

Iteration over map Warning

Iteration over map may be a possible source of non-determinism

cmd.Println(strings.TrimSpace(string(out)))
return nil
}

// getQueryClientConn returns a function that creates a gRPC client connection based on command flags.
// It handles the creation of secure or insecure connections and falls back to a CometBFT broadcaster
// if no gRPC address is specified.
func getQueryClientConn(cdc codec.Codec) func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
return func(cmd *cobra.Command) (grpc.ClientConnInterface, error) {
var err error
creds := grpcinsecure.NewCredentials()

insecure := true
if cmd.Flags().Lookup(flags.FlagGrpcInsecure) != nil {
insecure, err = cmd.Flags().GetBool(flags.FlagGrpcInsecure)
if err != nil {
return nil, err
}
}
if !insecure {
creds = credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})
}

var addr string
if cmd.Flags().Lookup(flags.FlagGrpcAddress) != nil {
addr, err = cmd.Flags().GetString(flags.FlagGrpcAddress)
if err != nil {
return nil, err
}
}
if addr == "" {
// if grpc-addr has not been set, use the default clientConn
// TODO: default is comet
node, err := cmd.Flags().GetString(flags.FlagNode)
if err != nil {
return nil, err
}
return comet.NewCometBFTBroadcaster(node, comet.BroadcastSync, cdc)
}

return grpc.NewClient(addr, []grpc.DialOption{grpc.WithTransportCredentials(creds)}...)
}
}

// signModesToApiSignModes converts a slice of signing.SignMode to a slice of apitxsigning.SignMode.
func signModesToApiSignModes(modes []signing.SignMode) []apitxsigning.SignMode {
r := make([]apitxsigning.SignMode, len(modes))
for i, m := range modes {
r[i] = apitxsigning.SignMode(m)
}
return r
}
17 changes: 16 additions & 1 deletion client/v2/autocli/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ type fixture struct {
conn *testClientConn
b *Builder
clientCtx client.Context

home string
chainID string
kBackend string
}

func initFixture(t *testing.T) *fixture {
Expand Down Expand Up @@ -85,17 +89,28 @@ func initFixture(t *testing.T) *fixture {
return conn, nil
},
AddQueryConnFlags: flags.AddQueryFlagsToCmd,
AddTxConnFlags: flags.AddTxFlagsToCmd,
AddTxConnFlags: addTxAndGlobalFlagsToCmd,
Cdc: encodingConfig.Codec,
}
assert.NilError(t, b.ValidateAndComplete())

return &fixture{
conn: conn,
b: b,
clientCtx: clientCtx,

home: home,
chainID: "autocli-test",
kBackend: sdkkeyring.BackendMemory,
}
}

func addTxAndGlobalFlagsToCmd(cmd *cobra.Command) {
f := cmd.Flags()
f.String("home", "", "home directory")
flags.AddTxFlagsToCmd(cmd)
}

func runCmd(fixture *fixture, command func(moduleName string, f *fixture) (*cobra.Command, error), args ...string) (*bytes.Buffer, error) {
out := &bytes.Buffer{}
cmd, err := command("test", fixture)
Expand Down
Loading
Loading