diff --git a/CHANGELOG.md b/CHANGELOG.md index 87a9e60b4d01..12b9e20663c8 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 cb2a7b0e271e..d642991a4426 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 9311bbd2908f..0e4e9ac96609 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 68fa6ff59a8f..ddd3f4741564 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 c7767ac089a9..533fedbd8075 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 ab4f8937f91c..82904c6ab064 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 d5f271b3bdb6..58d9e5265989 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 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 784cac89d912..54bfaa0406fb 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 c5809cd10268..e73fce8a125d 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 a88abb735080..9453c10aef1a 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