From 4c054a8565dd262dc3802309b6dd7d7cb0382946 Mon Sep 17 00:00:00 2001
From: Federico Kunze <federico.kunze94@gmail.com>
Date: Thu, 15 Oct 2020 11:16:20 +0200
Subject: [PATCH 1/3] client: add GetAccount and GetAccountWithHeight to
 AccountRetriever

---
 client/account_retriever.go                   | 23 ++++++-
 client/test_helpers.go                        | 67 +++++++++++++++++--
 .../adr-020-protobuf-transaction-encoding.md  |  2 +
 x/auth/types/account_retriever.go             |  9 ++-
 4 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/client/account_retriever.go b/client/account_retriever.go
index e7f9fbaea41d..2d8c3f903d8e 100644
--- a/client/account_retriever.go
+++ b/client/account_retriever.go
@@ -1,11 +1,28 @@
 package client
 
-import "github.com/cosmos/cosmos-sdk/types"
+import (
+	"github.com/tendermint/tendermint/crypto"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+// Account defines a read-only version of the auth module's AccountI.
+type Account interface {
+	GetAddress() sdk.AccAddress
+	GetPubKey() crypto.PubKey // can return nil.
+	GetAccountNumber() uint64
+	GetSequence() uint64
+
+	// Ensure that account implements stringer
+	String() string
+}
 
 // AccountRetriever defines the interfaces required by transactions to
 // ensure an account exists and to be able to query for account fields necessary
 // for signing.
 type AccountRetriever interface {
-	EnsureExists(clientCtx Context, addr types.AccAddress) error
-	GetAccountNumberSequence(clientCtx Context, addr types.AccAddress) (accNum uint64, accSeq uint64, err error)
+	GetAccount(clientCtx Context, addr sdk.AccAddress) (Account, error)
+	GetAccountWithHeight(clientCtx Context, addr sdk.AccAddress) (Account, int64, error)
+	EnsureExists(clientCtx Context, addr sdk.AccAddress) error
+	GetAccountNumberSequence(clientCtx Context, addr sdk.AccAddress) (accNum uint64, accSeq uint64, err error)
 }
diff --git a/client/test_helpers.go b/client/test_helpers.go
index 673519c5fac9..39a63565c3c9 100644
--- a/client/test_helpers.go
+++ b/client/test_helpers.go
@@ -3,19 +3,76 @@ package client
 import (
 	"fmt"
 
+	"github.com/tendermint/tendermint/crypto"
+
 	sdk "github.com/cosmos/cosmos-sdk/types"
 )
 
 // TestAccountRetriever is an AccountRetriever that can be used in unit tests
 type TestAccountRetriever struct {
-	Accounts map[string]struct {
-		Address sdk.AccAddress
-		Num     uint64
-		Seq     uint64
+	Accounts map[string]TestAccount
+}
+
+// TestAccount represents a client Account that can be used in unit tests
+type TestAccount struct {
+	Address sdk.AccAddress
+	Num     uint64
+	Seq     uint64
+}
+
+// GetAddress implements client Account.GetAddress
+func (t TestAccount) GetAddress() sdk.AccAddress {
+	return t.Address
+}
+
+// GetPubKey implements client Account.GetPubKey
+func (t TestAccount) GetPubKey() crypto.PubKey {
+	return nil
+}
+
+// GetAccountNumber implements client Account.GetAccountNumber
+func (t TestAccount) GetAccountNumber() uint64 {
+	return t.Num
+}
+
+// GetSequence implements client Account.GetSequence
+func (t TestAccount) GetSequence() uint64 {
+	return t.Seq
+}
+
+// String implements client Account.String
+func (t TestAccount) String() string {
+	return fmt.Sprintf(`address: %s
+pub_key: nil
+account_number: %d
+sequence: %d`, t.Address, t.Num, t.Seq,
+	)
+}
+
+var (
+	_ AccountRetriever = TestAccountRetriever{}
+	_ Account          = TestAccount{}
+)
+
+// GetAccount implements AccountRetriever.GetAccount
+func (t TestAccountRetriever) GetAccount(_ Context, addr sdk.AccAddress) (Account, error) {
+	acc, ok := t.Accounts[addr.String()]
+	if !ok {
+		return nil, fmt.Errorf("account %s not found", addr)
 	}
+
+	return acc, nil
 }
 
-var _ AccountRetriever = TestAccountRetriever{}
+// GetAccountWithHeight implements AccountRetriever.GetAccountWithHeight
+func (t TestAccountRetriever) GetAccountWithHeight(clientCtx Context, addr sdk.AccAddress) (Account, int64, error) {
+	acc, err := t.GetAccount(clientCtx, addr)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	return acc, 0, nil
+}
 
 // EnsureExists implements AccountRetriever.EnsureExists
 func (t TestAccountRetriever) EnsureExists(_ Context, addr sdk.AccAddress) error {
diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md
index 3d1eb531a376..45d12933236d 100644
--- a/docs/architecture/adr-020-protobuf-transaction-encoding.md
+++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md
@@ -315,6 +315,8 @@ and messages.
 
 ```go
 type AccountRetriever interface {
+  GetAccount(clientCtx Context, addr sdk.AccAddress) (client.Account, error)
+  GetAccountWithHeight(clientCtx Context, addr sdk.AccAddress) (client.Account, int64, error)
   EnsureExists(clientCtx client.Context, addr sdk.AccAddress) error
   GetAccountNumberSequence(clientCtx client.Context, addr sdk.AccAddress) (uint64, uint64, error)
 }
diff --git a/x/auth/types/account_retriever.go b/x/auth/types/account_retriever.go
index 2b8d24ac279c..f84c744188ff 100644
--- a/x/auth/types/account_retriever.go
+++ b/x/auth/types/account_retriever.go
@@ -13,13 +13,18 @@ import (
 	grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
 )
 
+var (
+	_ client.Account          = AccountI(nil)
+	_ client.AccountRetriever = AccountRetriever{}
+)
+
 // AccountRetriever defines the properties of a type that can be used to
 // retrieve accounts.
 type AccountRetriever struct{}
 
 // GetAccount queries for an account given an address and a block height. An
 // error is returned if the query or decoding fails.
-func (ar AccountRetriever) GetAccount(clientCtx client.Context, addr sdk.AccAddress) (AccountI, error) {
+func (ar AccountRetriever) GetAccount(clientCtx client.Context, addr sdk.AccAddress) (client.Account, error) {
 	account, _, err := ar.GetAccountWithHeight(clientCtx, addr)
 	return account, err
 }
@@ -28,7 +33,7 @@ func (ar AccountRetriever) GetAccount(clientCtx client.Context, addr sdk.AccAddr
 // height of the query with the account. An error is returned if the query
 // or decoding fails.
 //nolint:interfacer
-func (ar AccountRetriever) GetAccountWithHeight(clientCtx client.Context, addr sdk.AccAddress) (AccountI, int64, error) {
+func (ar AccountRetriever) GetAccountWithHeight(clientCtx client.Context, addr sdk.AccAddress) (client.Account, int64, error) {
 	var header metadata.MD
 
 	queryClient := NewQueryClient(clientCtx)

From 961515ea5ad2206470fe563a6db51e0dbdd0f80d Mon Sep 17 00:00:00 2001
From: Federico Kunze <federico.kunze94@gmail.com>
Date: Thu, 15 Oct 2020 11:21:02 +0200
Subject: [PATCH 2/3] update ADR

---
 docs/architecture/adr-020-protobuf-transaction-encoding.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/docs/architecture/adr-020-protobuf-transaction-encoding.md b/docs/architecture/adr-020-protobuf-transaction-encoding.md
index 45d12933236d..0e9a644a5918 100644
--- a/docs/architecture/adr-020-protobuf-transaction-encoding.md
+++ b/docs/architecture/adr-020-protobuf-transaction-encoding.md
@@ -11,6 +11,7 @@
 - 2020 August 07: Use ADR 027 for serializing `SignDoc`.
 - 2020 August 19: Move sequence field from `SignDoc` to `SignerInfo`.
 - 2020 September 25: Remove `PublicKey` type in favor of `secp256k1.PubKey`, `ed25519.PubKey` and `multisig.LegacyAminoPubKey`.
+- 2020 October 15: Add `GetAccount` and `GetAccountWithHeight` methods to the `AccountRetriever` interface.
 
 ## Status
 

From c60d518784a426a9d7be71e1b847be6831aa76be Mon Sep 17 00:00:00 2001
From: Federico Kunze <federico.kunze94@gmail.com>
Date: Thu, 15 Oct 2020 16:01:04 +0200
Subject: [PATCH 3/3] address comments from review

---
 client/account_retriever.go |  3 ---
 client/test_helpers.go      | 23 +++++++----------------
 2 files changed, 7 insertions(+), 19 deletions(-)

diff --git a/client/account_retriever.go b/client/account_retriever.go
index 2d8c3f903d8e..51c0a7fa9bcc 100644
--- a/client/account_retriever.go
+++ b/client/account_retriever.go
@@ -12,9 +12,6 @@ type Account interface {
 	GetPubKey() crypto.PubKey // can return nil.
 	GetAccountNumber() uint64
 	GetSequence() uint64
-
-	// Ensure that account implements stringer
-	String() string
 }
 
 // AccountRetriever defines the interfaces required by transactions to
diff --git a/client/test_helpers.go b/client/test_helpers.go
index 39a63565c3c9..1140298fda42 100644
--- a/client/test_helpers.go
+++ b/client/test_helpers.go
@@ -8,10 +8,10 @@ import (
 	sdk "github.com/cosmos/cosmos-sdk/types"
 )
 
-// TestAccountRetriever is an AccountRetriever that can be used in unit tests
-type TestAccountRetriever struct {
-	Accounts map[string]TestAccount
-}
+var (
+	_ AccountRetriever = TestAccountRetriever{}
+	_ Account          = TestAccount{}
+)
 
 // TestAccount represents a client Account that can be used in unit tests
 type TestAccount struct {
@@ -40,20 +40,11 @@ func (t TestAccount) GetSequence() uint64 {
 	return t.Seq
 }
 
-// String implements client Account.String
-func (t TestAccount) String() string {
-	return fmt.Sprintf(`address: %s
-pub_key: nil
-account_number: %d
-sequence: %d`, t.Address, t.Num, t.Seq,
-	)
+// TestAccountRetriever is an AccountRetriever that can be used in unit tests
+type TestAccountRetriever struct {
+	Accounts map[string]TestAccount
 }
 
-var (
-	_ AccountRetriever = TestAccountRetriever{}
-	_ Account          = TestAccount{}
-)
-
 // GetAccount implements AccountRetriever.GetAccount
 func (t TestAccountRetriever) GetAccount(_ Context, addr sdk.AccAddress) (Account, error) {
 	acc, ok := t.Accounts[addr.String()]