From 92c0e16d63ccad859705a8aa1052484b81c4b735 Mon Sep 17 00:00:00 2001
From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com>
Date: Wed, 10 May 2023 11:36:08 +0000
Subject: [PATCH] fix: fetch account number/sequence when not in offline mode
 (backport #16075) (#16081)

Co-authored-by: Julien Robert <julien@rbrt.fr>
---
 CHANGELOG.md                |  1 +
 client/account_retriever.go |  6 ++++--
 client/tx/factory.go        | 20 +++++++++++++++-----
 client/tx/factory_test.go   | 34 ++++++++++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 7 deletions(-)
 create mode 100644 client/tx/factory_test.go

diff --git a/CHANGELOG.md b/CHANGELOG.md
index bf3c871b02fa..c7b9f696a343 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
 
 ### Improvements
 
+* (client) [#16075](https://github.com/cosmos/cosmos-sdk/pull/16075) Partly revert [#15953](https://github.com/cosmos/cosmos-sdk/issues/15953) and `factory.Prepare` now does nothing in offline mode.
 * (server) [#15984](https://github.com/cosmos/cosmos-sdk/pull/15984) Use `cosmossdk.io/log` package for logging instead of CometBFT logger. NOTE: v0.45 and v0.46 were not using CometBFT logger either. This keeps the same underlying logger (zerolog) as in v0.45.x+ and v0.46.x+ but now properly supporting filtered logging.
 * (gov) [#15979](https://github.com/cosmos/cosmos-sdk/pull/15979) Improve gov error message when failing to convert v1 proposal to v1beta1.
 
diff --git a/client/account_retriever.go b/client/account_retriever.go
index 24de5423e2ea..ff5be9bc8589 100644
--- a/client/account_retriever.go
+++ b/client/account_retriever.go
@@ -28,7 +28,9 @@ var _ AccountRetriever = (*MockAccountRetriever)(nil)
 // MockAccountRetriever defines a no-op basic AccountRetriever that can be used
 // in mocked contexts. Tests or context that need more sophisticated testing
 // state should implement their own mock AccountRetriever.
-type MockAccountRetriever struct{}
+type MockAccountRetriever struct {
+	ReturnAccNum, ReturnAccSeq uint64
+}
 
 func (mar MockAccountRetriever) GetAccount(_ Context, _ sdk.AccAddress) (Account, error) {
 	return nil, nil
@@ -43,5 +45,5 @@ func (mar MockAccountRetriever) EnsureExists(_ Context, _ sdk.AccAddress) error
 }
 
 func (mar MockAccountRetriever) GetAccountNumberSequence(_ Context, _ sdk.AccAddress) (uint64, uint64, error) {
-	return 0, 0, nil
+	return mar.ReturnAccNum, mar.ReturnAccSeq, nil
 }
diff --git a/client/tx/factory.go b/client/tx/factory.go
index e9482bc854ad..99195f2c2170 100644
--- a/client/tx/factory.go
+++ b/client/tx/factory.go
@@ -430,9 +430,14 @@ func (f Factory) getSimPK() (cryptotypes.PubKey, error) {
 
 // Prepare ensures the account defined by ctx.GetFromAddress() exists and
 // if the account number and/or the account sequence number are zero (not set),
-// they will be queried for and set on the provided Factory. A new Factory with
-// the updated fields will be returned.
+// they will be queried for and set on the provided Factory.
+// A new Factory with the updated fields will be returned.
+// Note: When in offline mode, the Prepare does nothing and returns the original factory.
 func (f Factory) Prepare(clientCtx client.Context) (Factory, error) {
+	if clientCtx.Offline {
+		return f, nil
+	}
+
 	fc := f
 	from := clientCtx.GetFromAddress()
 
@@ -441,14 +446,19 @@ 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
 		}
 
-		fc = fc.WithAccountNumber(num)
-		fc = fc.WithSequence(seq)
+		if initNum == 0 {
+			fc = fc.WithAccountNumber(num)
+		}
+
+		if initSeq == 0 {
+			fc = fc.WithSequence(seq)
+		}
 	}
 
 	return fc, nil
diff --git a/client/tx/factory_test.go b/client/tx/factory_test.go
new file mode 100644
index 000000000000..7a8c4cc2dd46
--- /dev/null
+++ b/client/tx/factory_test.go
@@ -0,0 +1,34 @@
+package tx_test
+
+import (
+	"testing"
+
+	"github.com/cosmos/cosmos-sdk/client"
+	"github.com/cosmos/cosmos-sdk/client/tx"
+	"github.com/stretchr/testify/require"
+)
+
+func TestFactoryPrepate(t *testing.T) {
+	t.Parallel()
+
+	factory := tx.Factory{}
+	clientCtx := client.Context{}
+
+	output, err := factory.Prepare(clientCtx.WithOffline(true))
+	require.NoError(t, err)
+	require.Equal(t, output, factory)
+
+	factory = tx.Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1}).WithAccountNumber(5)
+	output, err = factory.Prepare(clientCtx.WithFrom("foo"))
+	require.NoError(t, err)
+	require.NotEqual(t, output, factory)
+	require.Equal(t, output.AccountNumber(), uint64(5))
+	require.Equal(t, output.Sequence(), uint64(1))
+
+	factory = tx.Factory{}.WithAccountRetriever(client.MockAccountRetriever{ReturnAccNum: 10, ReturnAccSeq: 1})
+	output, err = factory.Prepare(clientCtx.WithFrom("foo"))
+	require.NoError(t, err)
+	require.NotEqual(t, output, factory)
+	require.Equal(t, output.AccountNumber(), uint64(10))
+	require.Equal(t, output.Sequence(), uint64(1))
+}