diff --git a/CHANGELOG.md b/CHANGELOG.md index a416c5ca8a4d..08d1c6cde8a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (x/distribution) [#15462](https://github.com/cosmos/cosmos-sdk/pull/15462) Add delegator address to the event for withdrawing delegation rewards. * [#14609](https://github.com/cosmos/cosmos-sdk/pull/14609) Add `RetryForBlocks` method to use in tests that require waiting for a transaction to be included in a block. +### Bug Fixes + +* (cli) [#15123](https://github.com/cosmos/cosmos-sdk/pull/15123) Fix the CLI `offline` mode behavior to be really offline. The API of `clienttx.NewFactoryCLI` is updated to return an error. + ### Deprecated * (x/genutil) [#15316](https://github.com/cosmos/cosmos-sdk/pull/15316) Remove requirement on node & IP being included in a gentx. diff --git a/client/tx/factory.go b/client/tx/factory.go index 3d174c0e8946..e9482bc854ad 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 @@ -62,8 +62,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) @@ -103,7 +111,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 } @@ -433,19 +441,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 2463d1d4cfa5..059ce3a1b9a3 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/simapp/go.mod b/simapp/go.mod index d8db9d2df471..17264ea74ac5 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -14,6 +14,7 @@ require ( github.com/golang/mock v1.6.0 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.6.1 + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.14.0 github.com/stretchr/testify v1.8.2 google.golang.org/protobuf v1.29.1 @@ -131,7 +132,6 @@ require ( github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/spf13/afero v1.9.2 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect diff --git a/tests/e2e/auth/suite.go b/tests/e2e/auth/suite.go index 77d85795e9cd..e103f46052ae 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 6537ef243733..93f93be9dc34 100644 --- a/tests/e2e/tx/service_test.go +++ b/tests/e2e/tx/service_test.go @@ -93,6 +93,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 fcf5a2cb28c8..dd6ec56a980d 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 ea91580a7f47..b1fd2525c3cf 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -80,7 +80,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) } @@ -254,7 +257,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 30132ec14fd3..9b37937dc634 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 0ad65c71e35a..4e03b8200707 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -131,7 +131,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 73c195bf745a..4d5b31aaa13d 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -128,7 +128,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 b70b0b120700..d3592e91fc5e 100644 --- a/x/staking/client/cli/tx.go +++ b/x/staking/client/cli/tx.go @@ -64,8 +64,11 @@ func NewCreateValidatorCmd() *cobra.Command { return err } - txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). - WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) + if err != nil { + return err + } + txf, msg, err := newBuildCreateValidatorMsg(clientCtx, txf, cmd.Flags()) if err != nil { return err