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

fix: --dry-run not working when using tx command #11558

Merged
merged 8 commits into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from 7 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#9533](https://github.com/cosmos/cosmos-sdk/pull/9533) Added a new gRPC method, `DenomOwners`, in `x/bank` to query for all account holders of a specific denomination.
* (bank) [\#9618](https://github.com/cosmos/cosmos-sdk/pull/9618) Update bank.Metadata: add URI and URIHash attributes.
* (store) [\#8664](https://github.com/cosmos/cosmos-sdk/pull/8664) Implementation of ADR-038 file StreamingService
* [\#9837](https://github.com/cosmos/cosmos-sdk/issues/9837) `--generate-only` flag will accept the keyname now.
* [\#9837](https://github.com/cosmos/cosmos-sdk/issues/9837) `--generate-only` flag can be used with a keyname from the keyring.
* [\#10326](https://github.com/cosmos/cosmos-sdk/pull/10326) `x/authz` add all grants by granter query.
* [\#10944](https://github.com/cosmos/cosmos-sdk/pull/10944) `x/authz` add all grants by grantee query
* [\#10348](https://github.com/cosmos/cosmos-sdk/pull/10348) Add `fee.{payer,granter}` and `tip` fields to StdSignDoc for signing tipped transactions.
Expand Down Expand Up @@ -204,6 +204,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* [\#11558](https://github.com/cosmos/cosmos-sdk/pull/11558) Fix `--dry-run` not working when using tx command.
* [\#11354](https://github.com/cosmos/cosmos-sdk/pull/11355) Added missing pagination flag for `bank q total` query.
* [\#11197](https://github.com/cosmos/cosmos-sdk/pull/11197) Signing with multisig now works with multisig address which is not in the keyring.
* (makefile) [\#11285](https://github.com/cosmos/cosmos-sdk/pull/11285) Fix lint-fix make target.
Expand Down
2 changes: 1 addition & 1 deletion client/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ func readTxCommandFlags(clientCtx Context, flagSet *pflag.FlagSet) (Context, err

if clientCtx.From == "" || flagSet.Changed(flags.FlagFrom) {
from, _ := flagSet.GetString(flags.FlagFrom)
fromAddr, fromName, keyType, err := GetFromFields(clientCtx.Keyring, from, clientCtx.GenerateOnly)
fromAddr, fromName, keyType, err := GetFromFields(clientCtx, clientCtx.Keyring, from)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I dont think there's a need to pass both clientCtx and clientCtx.Keyring, we might as well just pass clientCtx and get the keyring from that in GetFromFields.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. You can always call clientCtx.WithKeyring prior to calling it, but that's a good point. I'm indifferent here.

if err != nil {
return clientCtx, err
}
Expand Down
34 changes: 25 additions & 9 deletions client/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

import (
"bufio"
"fmt"
"io"
"os"

Expand Down Expand Up @@ -52,9 +53,9 @@ type Context struct {
FeePayer sdk.AccAddress
FeeGranter sdk.AccAddress
Viper *viper.Viper

// IsAux is true when the signer is an auxiliary signer (e.g. the tipper).
IsAux bool
IsAux bool

// TODO: Deprecated (remove).
LegacyAmino *codec.LegacyAmino
Expand Down Expand Up @@ -334,16 +335,31 @@ func (ctx Context) printOutput(out []byte) error {
return nil
}

// GetFromFields returns a from account address, account name and keyring type, given either
// an address or key name. If genOnly is true, only a valid Bech32 cosmos
// address is returned.
func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddress, string, keyring.KeyType, error) {
// GetFromFields returns a from account address, account name and keyring type, given either an address or key name.
// If clientCtx.Simulate is true the keystore is not accessed and a valid address must be provided
// If clientCtx.GenerateOnly is true the keystore is only accessed if a key name is provided
func GetFromFields(clientCtx Context, kr keyring.Keyring, from string) (sdk.AccAddress, string, keyring.KeyType, error) {
if from == "" {
return nil, "", 0, nil
}

addr, err := sdk.AccAddressFromBech32(from)
switch {
case clientCtx.Simulate:
if err != nil {
return nil, "", 0, fmt.Errorf("a valid bech32 address must be provided in simulation mode: %w", err)
}

return addr, "", 0, nil

case clientCtx.GenerateOnly:
if err == nil {
return addr, "", 0, nil
}
}

var k *keyring.Record
if addr, err := sdk.AccAddressFromBech32(from); err == nil {
if err == nil {
k, err = kr.KeyByAddress(addr)
if err != nil {
return nil, "", 0, err
Expand All @@ -355,7 +371,7 @@ func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddres
}
}

addr, err := k.GetAddress()
addr, err = k.GetAddress()
if err != nil {
return nil, "", 0, err
}
Expand All @@ -365,7 +381,7 @@ func GetFromFields(kr keyring.Keyring, from string, genOnly bool) (sdk.AccAddres

// NewKeyringFromBackend gets a Keyring object from a backend
func NewKeyringFromBackend(ctx Context, backend string) (keyring.Keyring, error) {
if ctx.GenerateOnly || ctx.Simulate {
if ctx.Simulate {
Copy link
Member Author

@julienrbrt julienrbrt Apr 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed because --generate-only should be able to read the key ring (for this feature #9838) so it should not be overwritten.
Moreover this was actually never true as NewKeyringFromBackend was called before that the generate flag was read by readTxCommandFlags:

backend = keyring.BackendMemory
}

Expand Down
106 changes: 106 additions & 0 deletions client/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"os"
"strings"
"testing"

"github.com/spf13/viper"
Expand All @@ -13,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
Expand Down Expand Up @@ -114,3 +116,107 @@ func TestCLIQueryConn(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "hello", res.Message)
}

func TestGetFromFields(t *testing.T) {
cfg := network.DefaultConfig()
path := hd.CreateHDPath(118, 0, 0).String()

testCases := []struct {
clientCtx client.Context
keyring func() keyring.Keyring
from string
expectedErr string
}{
{
keyring: func() keyring.Keyring {
kb := keyring.NewInMemory(cfg.Codec)

_, _, err := kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)

return kb
},
from: "alice",
},
{
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)

_, _, err = kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)

return kb
},
from: "alice",
},
{
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
expectedErr: "key with address cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5 not found: key not found",
},
{
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)
return kb
},
from: "alice",
expectedErr: "alice.info: key not found",
},
{
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
clientCtx: client.Context{}.WithSimulation(true),
},
{
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "alice",
clientCtx: client.Context{}.WithSimulation(true),
expectedErr: "a valid bech32 address must be provided in simulation mode",
},
{
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "cosmos139f7kncmglres2nf3h4hc4tade85ekfr8sulz5",
clientCtx: client.Context{}.WithGenerateOnly(true),
},
{
keyring: func() keyring.Keyring {
return keyring.NewInMemory(cfg.Codec)
},
from: "alice",
clientCtx: client.Context{}.WithGenerateOnly(true),
expectedErr: "alice.info: key not found",
},
{
keyring: func() keyring.Keyring {
kb, err := keyring.New(t.Name(), keyring.BackendTest, t.TempDir(), nil, cfg.Codec)
require.NoError(t, err)

_, _, err = kb.NewMnemonic("alice", keyring.English, path, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
require.NoError(t, err)

return kb
},
clientCtx: client.Context{}.WithGenerateOnly(true),
from: "alice",
},
}

for _, tc := range testCases {
_, _, _, err := client.GetFromFields(tc.clientCtx, tc.keyring(), tc.from)
if tc.expectedErr == "" {
require.NoError(t, err)
} else {
require.True(t, strings.HasPrefix(err.Error(), tc.expectedErr))
}
}
}
4 changes: 2 additions & 2 deletions client/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
cmd.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
cmd.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
cmd.Flags().StringP(FlagBroadcastMode, "b", BroadcastSync, "Transaction broadcasting mode (sync|async|block)")
cmd.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
cmd.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase is not accessible)")
cmd.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it (when enabled, the local Keybase is not accessible)")
cmd.Flags().Bool(FlagGenerateOnly, false, "Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)")
cmd.Flags().Bool(FlagOffline, false, "Offline mode (does not allow any online functionality)")
cmd.Flags().BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
cmd.Flags().String(FlagKeyringBackend, DefaultKeyringBackend, "Select keyring's backend (os|file|kwallet|pass|test|memory)")
Expand Down
2 changes: 1 addition & 1 deletion client/tx/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func (gr GasEstimateResponse) String() string {
// makeAuxSignerData generates an AuxSignerData from the client inputs.
func makeAuxSignerData(clientCtx client.Context, f Factory, msgs ...sdk.Msg) (tx.AuxSignerData, error) {
b := NewAuxTxBuilder()
fromAddress, name, _, err := client.GetFromFields(clientCtx.Keyring, clientCtx.From, false)
fromAddress, name, _, err := client.GetFromFields(clientCtx, clientCtx.Keyring, clientCtx.From)
if err != nil {
return tx.AuxSignerData{}, err
}
Expand Down
14 changes: 8 additions & 6 deletions x/auth/client/cli/tx_sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ account key. It implies --signature-only.
cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
cmd.Flags().Bool(flagSigOnly, true, "Print only the generated signature, then exit")
cmd.Flags().String(flags.FlagChainID, "", "network chain ID")
cmd.MarkFlagRequired(flags.FlagFrom)
flags.AddTxFlagsToCmd(cmd)

cmd.MarkFlagRequired(flags.FlagFrom)

return cmd
}

Expand Down Expand Up @@ -106,7 +107,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
}
if ms == "" {
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(txFactory.Keybase(), from, clientCtx.GenerateOnly)
_, fromName, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
Expand All @@ -115,7 +116,7 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error {
return err
}
} else {
multisigAddr, _, _, err := client.GetFromFields(txFactory.Keybase(), ms, clientCtx.GenerateOnly)
multisigAddr, _, _, err := client.GetFromFields(clientCtx, txFactory.Keybase(), ms)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
Expand Down Expand Up @@ -192,9 +193,10 @@ be generated via the 'multisign' command.
cmd.Flags().String(flags.FlagOutputDocument, "", "The document will be written to the given file instead of STDOUT")
cmd.Flags().String(flags.FlagChainID, "", "The network chain ID")
cmd.Flags().Bool(flagAmino, false, "Generate Amino encoded JSON suitable for submiting to the txs REST endpoint")
cmd.MarkFlagRequired(flags.FlagFrom)
flags.AddTxFlagsToCmd(cmd)

cmd.MarkFlagRequired(flags.FlagFrom)

return cmd
}

Expand Down Expand Up @@ -235,7 +237,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
return err
}
from, _ := cmd.Flags().GetString(flags.FlagFrom)
_, fromName, _, err := client.GetFromFields(txF.Keybase(), from, clientCtx.GenerateOnly)
_, fromName, _, err := client.GetFromFields(clientCtx, txF.Keybase(), from)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
Expand All @@ -245,7 +247,7 @@ func makeSignCmd() func(cmd *cobra.Command, args []string) error {
multisigAddr, err := sdk.AccAddressFromBech32(multisig)
if err != nil {
// Bech32 decode error, maybe it's a name, we try to fetch from keyring
multisigAddr, _, _, err = client.GetFromFields(txFactory.Keybase(), multisig, clientCtx.GenerateOnly)
multisigAddr, _, _, err = client.GetFromFields(clientCtx, txFactory.Keybase(), multisig)
if err != nil {
return fmt.Errorf("error getting account from keybase: %w", err)
}
Expand Down
6 changes: 4 additions & 2 deletions x/bank/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ func NewTxCmd() *cobra.Command {
func NewSendTxCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "send [from_key_or_address] [to_address] [amount]",
Short: `Send funds from one account to another. Note, the'--from' flag is
ignored as it is implied from [from_key_or_address].`,
Short: `Send funds from one account to another.
Note, the '--from' flag is ignored as it is implied from [from_key_or_address].
When using '--dry-run' a key name cannot be used, only a bech32 address.`,
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.Flags().Set(flags.FlagFrom, args[0])
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

toAddr, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion x/feegrant/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ func (s *IntegrationTestSuite) TestNewCmdFeeGrant() {
alreadyExistedGrantee := s.addedGrantee
clientCtx := val.ClientCtx

fromAddr, fromName, _, err := client.GetFromFields(clientCtx.Keyring, granter.String(), clientCtx.GenerateOnly)
fromAddr, fromName, _, err := client.GetFromFields(clientCtx, clientCtx.Keyring, granter.String())
s.Require().Equal(fromAddr, granter)
s.Require().NoError(err)

Expand Down