From c71d19939baa377aff576cbf0b0eeee028c5ef2b Mon Sep 17 00:00:00 2001 From: Jayden Lee <41176085+tkxkd0159@users.noreply.github.com> Date: Thu, 23 Feb 2023 19:03:20 +0900 Subject: [PATCH] fix: change the behavior of offline mode correctly (#15123) ## Description Closes: #15109 Change to work only when `FlagAccountNumber` and `FlagSequence` are in offline mode. In other cases, use `AccountRetriever` to populate those values. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- CHANGELOG.md | 4 +++- client/tx/factory.go | 27 +++++++++++++++------------ client/tx/tx.go | 9 ++++++++- tests/e2e/auth/suite.go | 17 ++++++++++++++--- tests/e2e/tx/service_test.go | 3 +++ x/auth/client/cli/tips.go | 5 ++++- x/auth/client/cli/tx_multisign.go | 10 ++++++++-- x/auth/client/cli/tx_sign.go | 5 ++++- x/auth/client/cli/validate_sigs.go | 5 ++++- x/genutil/client/cli/gentx.go | 5 ++++- x/staking/client/cli/tx.go | 7 +++++-- 11 files changed, 72 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87a9e60b4d..12b9e20663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -264,7 +264,8 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf * (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) `MsgUndelegateResponse` now includes undelegated amount. `x/staking` module's `keeper.Undelegate` now returns 3 values (completionTime,undelegateAmount,error) instead of 2. * (x/feegrant) [14649](https://github.com/cosmos/cosmos-sdk/pull/14649) Extract Feegrant in its own go.mod and rename the package to `cosmossdk.io/x/feegrant`. * (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Return a human readable denomination for IBC vouchers when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest`. -* (crypto) [#15070](https://github.com/cosmos/cosmos-sdk/pull/15070) `GenerateFromPassword` and `Cost` from `bcrypt.go` now take a `uint32` instead of a `int` type. +* (crypto) [#15070](https://github.com/cosmos/cosmos-sdk/pull/15070) `GenerateFromPassword` and `Cost` from `bcrypt.go` now take a `uint32` instead of a `int` type. +* (client) [#15123](https://github.com/cosmos/cosmos-sdk/pull/15123) `NewFactoryCLI` now returns an error, in addition to the `Factory`. ### Client Breaking Changes @@ -315,6 +316,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf * (server) [#13778](https://github.com/cosmos/cosmos-sdk/pull/13778) Set Cosmos SDK default endpoints to localhost to avoid unknown exposure of endpoints. * (x/auth) [#13877](https://github.com/cosmos/cosmos-sdk/pull/13877) Handle missing account numbers during `InitGenesis`. * (cli) [#14509](https://github.com/cosmos/cosmos-sdk/pull/#14509) Added missing options to keyring-backend flag usage +* (cli) [#15123](https://github.com/cosmos/cosmos-sdk/pull/15123) Change the offline mode behavior that does not match the written in the description to behave as written ### Deprecated diff --git a/client/tx/factory.go b/client/tx/factory.go index cb2a7b0e27..d642991a44 100644 --- a/client/tx/factory.go +++ b/client/tx/factory.go @@ -47,7 +47,7 @@ type Factory struct { } // NewFactoryCLI creates a new Factory. -func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) Factory { +func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, error) { signModeStr := clientCtx.SignModeStr signMode := signing.SignMode_SIGN_MODE_UNSPECIFIED @@ -64,8 +64,16 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) Factory { signMode = signing.SignMode_SIGN_MODE_EIP_191 } - accNum, _ := flagSet.GetUint64(flags.FlagAccountNumber) - accSeq, _ := flagSet.GetUint64(flags.FlagSequence) + var accNum, accSeq uint64 + if clientCtx.Offline { + if flagSet.Changed(flags.FlagAccountNumber) && flagSet.Changed(flags.FlagSequence) { + accNum, _ = flagSet.GetUint64(flags.FlagAccountNumber) + accSeq, _ = flagSet.GetUint64(flags.FlagSequence) + } else { + return Factory{}, errors.New("account-number and sequence must be set in offline mode") + } + } + gasAdj, _ := flagSet.GetFloat64(flags.FlagGasAdjustment) memo, _ := flagSet.GetString(flags.FlagNote) timeoutHeight, _ := flagSet.GetUint64(flags.FlagTimeoutHeight) @@ -105,7 +113,7 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) Factory { f = f.WithPreprocessTxHook(clientCtx.PreprocessTxHook) - return f + return f, nil } func (f Factory) AccountNumber() uint64 { return f.accountNumber } @@ -435,19 +443,14 @@ func (f Factory) Prepare(clientCtx client.Context) (Factory, error) { } initNum, initSeq := fc.accountNumber, fc.sequence - if initNum == 0 || initSeq == 0 { + if initNum == 0 && initSeq == 0 { num, seq, err := fc.accountRetriever.GetAccountNumberSequence(clientCtx, from) if err != nil { return fc, err } - if initNum == 0 { - fc = fc.WithAccountNumber(num) - } - - if initSeq == 0 { - fc = fc.WithSequence(seq) - } + fc = fc.WithAccountNumber(num) + fc = fc.WithSequence(seq) } return fc, nil diff --git a/client/tx/tx.go b/client/tx/tx.go index 9311bbd290..0e4e9ac966 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -24,7 +24,10 @@ import ( // GenerateOrBroadcastTxCLI will either generate and print and unsigned transaction // or sign it and broadcast it returning an error upon failure. func GenerateOrBroadcastTxCLI(clientCtx client.Context, flagSet *pflag.FlagSet, msgs ...sdk.Msg) error { - txf := NewFactoryCLI(clientCtx, flagSet) + txf, err := NewFactoryCLI(clientCtx, flagSet) + if err != nil { + return err + } return GenerateOrBroadcastTxWithFactory(clientCtx, txf, msgs...) } @@ -69,6 +72,10 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { } if txf.SimulateAndExecute() || clientCtx.Simulate { + if clientCtx.Offline { + return errors.New("cannot estimate gas in offline mode") + } + _, adjusted, err := CalculateGas(clientCtx, txf, msgs...) if err != nil { return err diff --git a/tests/e2e/auth/suite.go b/tests/e2e/auth/suite.go index 68fa6ff59a..ddd3f47415 100644 --- a/tests/e2e/auth/suite.go +++ b/tests/e2e/auth/suite.go @@ -1213,9 +1213,20 @@ func (s *E2ETestSuite) TestCLIMultisign() { sign2File := testutil.WriteToNewTempFile(s.T(), account2Signature.String()) defer sign2File.Close() - // Does not work in offline mode. - _, err = authclitestutil.TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), "--offline", sign1File.Name(), sign2File.Name()) - s.Require().EqualError(err, fmt.Sprintf("couldn't verify signature for address %s", addr1)) + // Work in offline mode. + multisigAccNum, multisigSeq, err := val1.ClientCtx.AccountRetriever.GetAccountNumberSequence(val1.ClientCtx, addr) + s.Require().NoError(err) + _, err = authclitestutil.TxMultiSignExec( + val1.ClientCtx, + multisigRecord.Name, + multiGeneratedTxFile.Name(), + fmt.Sprintf("--%s", flags.FlagOffline), + fmt.Sprintf("--%s=%d", flags.FlagAccountNumber, multisigAccNum), + fmt.Sprintf("--%s=%d", flags.FlagSequence, multisigSeq), + sign1File.Name(), + sign2File.Name(), + ) + s.Require().NoError(err) val1.ClientCtx.Offline = false multiSigWith2Signatures, err := authclitestutil.TxMultiSignExec(val1.ClientCtx, multisigRecord.Name, multiGeneratedTxFile.Name(), sign1File.Name(), sign2File.Name()) diff --git a/tests/e2e/tx/service_test.go b/tests/e2e/tx/service_test.go index c7767ac089..533fedbd80 100644 --- a/tests/e2e/tx/service_test.go +++ b/tests/e2e/tx/service_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/suite" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/simapp" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" @@ -90,6 +91,8 @@ func (s *E2ETestSuite) SetupSuite() { sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(1)), ), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s", flags.FlagOffline), + fmt.Sprintf("--%s=0", flags.FlagAccountNumber), fmt.Sprintf("--%s=2", flags.FlagSequence), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastSync), fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), diff --git a/x/auth/client/cli/tips.go b/x/auth/client/cli/tips.go index ab4f8937f9..82904c6ab0 100644 --- a/x/auth/client/cli/tips.go +++ b/x/auth/client/cli/tips.go @@ -35,7 +35,10 @@ func GetAuxToFeeCommand() *cobra.Command { return fmt.Errorf("expected chain-id %s, got %s in aux signer data", clientCtx.ChainID, auxSignerData.SignDoc.ChainId) } - f := clienttx.NewFactoryCLI(clientCtx, cmd.Flags()) + f, err := clienttx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } txBuilder := clientCtx.TxConfig.NewTxBuilder() err = txBuilder.AddAuxSignerData(auxSignerData) diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index d5f271b3bd..58d9e52659 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -82,7 +82,10 @@ func makeMultiSignCmd() func(cmd *cobra.Command, args []string) (err error) { return } - txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED { txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) } @@ -257,7 +260,10 @@ func makeBatchMultisignCmd() func(cmd *cobra.Command, args []string) error { } txCfg := clientCtx.TxConfig - txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } if txFactory.SignMode() == signingtypes.SignMode_SIGN_MODE_UNSPECIFIED { txFactory = txFactory.WithSignMode(signingtypes.SignMode_SIGN_MODE_LEGACY_AMINO_JSON) } diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index 30132ec14f..9b37937dc6 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -71,7 +71,10 @@ func makeSignBatchCmd() func(cmd *cobra.Command, args []string) error { if err != nil { return err } - txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } txCfg := clientCtx.TxConfig printSignatureOnly, _ := cmd.Flags().GetBool(flagSigOnly) diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 784cac89d9..54bfaa0406 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -133,7 +133,10 @@ func readTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filenam return clientCtx, tx.Factory{}, nil, err } - txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return clientCtx, tx.Factory{}, nil, err + } return clientCtx, txFactory, stdTx, nil } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index c5809cd102..e73fce8a12 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -127,7 +127,10 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o return errors.Wrap(err, "failed to validate account in genesis") } - txFactory := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + txFactory, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } pub, err := key.GetAddress() if err != nil { diff --git a/x/staking/client/cli/tx.go b/x/staking/client/cli/tx.go index a88abb7350..9453c10aef 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -90,13 +90,16 @@ where we can get the pubkey using "%s tendermint show-validator" return err } + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + validator, err := parseAndValidateValidatorJSON(clientCtx.Codec, args[0]) if err != nil { return err } - txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). - WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags(), validator) if err != nil { return err