-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Co-authored-by: Julián Toledano <JulianToledano@users.noreply.github.com>
- Loading branch information
1 parent
878e306
commit c74f7e8
Showing
25 changed files
with
4,411 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package account | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strconv" | ||
|
||
gogogrpc "github.com/cosmos/gogoproto/grpc" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/metadata" | ||
"google.golang.org/grpc/status" | ||
|
||
"cosmossdk.io/core/address" | ||
|
||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
) | ||
|
||
// GRPCBlockHeightHeader represents the gRPC header for block height. | ||
const GRPCBlockHeightHeader = "x-cosmos-block-height" | ||
|
||
var _ AccountRetriever = accountRetriever{} | ||
|
||
// Account provides a read-only abstraction over the auth module's AccountI. | ||
type Account interface { | ||
GetAddress() sdk.AccAddress | ||
GetPubKey() cryptotypes.PubKey // can return nil. | ||
GetAccountNumber() uint64 | ||
GetSequence() uint64 | ||
} | ||
|
||
// AccountRetriever defines methods required to retrieve account details necessary for transaction signing. | ||
type AccountRetriever interface { | ||
GetAccount(context.Context, []byte) (Account, error) | ||
GetAccountWithHeight(context.Context, []byte) (Account, int64, error) | ||
EnsureExists(context.Context, []byte) error | ||
GetAccountNumberSequence(context.Context, []byte) (accNum, accSeq uint64, err error) | ||
} | ||
|
||
type accountRetriever struct { | ||
ac address.Codec | ||
conn gogogrpc.ClientConn | ||
registry codectypes.InterfaceRegistry | ||
} | ||
|
||
// NewAccountRetriever creates a new instance of accountRetriever. | ||
func NewAccountRetriever(ac address.Codec, conn gogogrpc.ClientConn, registry codectypes.InterfaceRegistry) *accountRetriever { | ||
return &accountRetriever{ | ||
ac: ac, | ||
conn: conn, | ||
registry: registry, | ||
} | ||
} | ||
|
||
// GetAccount retrieves an account using its address. | ||
func (a accountRetriever) GetAccount(ctx context.Context, addr []byte) (Account, error) { | ||
acc, _, err := a.GetAccountWithHeight(ctx, addr) | ||
return acc, err | ||
} | ||
|
||
// GetAccountWithHeight retrieves an account and its associated block height using the account's address. | ||
func (a accountRetriever) GetAccountWithHeight(ctx context.Context, addr []byte) (Account, int64, error) { | ||
var header metadata.MD | ||
qc := authtypes.NewQueryClient(a.conn) | ||
|
||
addrStr, err := a.ac.BytesToString(addr) | ||
if err != nil { | ||
return nil, 0, err | ||
} | ||
|
||
res, err := qc.Account(ctx, &authtypes.QueryAccountRequest{Address: addrStr}, grpc.Header(&header)) | ||
if err != nil { | ||
return nil, 0, err | ||
} | ||
|
||
blockHeight := header.Get(GRPCBlockHeightHeader) | ||
if len(blockHeight) != 1 { | ||
return nil, 0, fmt.Errorf("unexpected '%s' header length; got %d, expected 1", GRPCBlockHeightHeader, len(blockHeight)) | ||
} | ||
|
||
nBlockHeight, err := strconv.Atoi(blockHeight[0]) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("failed to parse block height: %w", err) | ||
} | ||
|
||
var acc Account | ||
if err := a.registry.UnpackAny(res.Account, &acc); err != nil { | ||
return nil, 0, err | ||
} | ||
|
||
return acc, int64(nBlockHeight), nil | ||
} | ||
|
||
// EnsureExists checks if an account exists using its address. | ||
func (a accountRetriever) EnsureExists(ctx context.Context, addr []byte) error { | ||
if _, err := a.GetAccount(ctx, addr); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// GetAccountNumberSequence retrieves the account number and sequence for an account using its address. | ||
func (a accountRetriever) GetAccountNumberSequence(ctx context.Context, addr []byte) (accNum, accSeq uint64, err error) { | ||
acc, err := a.GetAccount(ctx, addr) | ||
if err != nil { | ||
if status.Code(err) == codes.NotFound { | ||
return 0, 0, nil | ||
} | ||
return 0, 0, err | ||
} | ||
|
||
return acc.GetAccountNumber(), acc.GetSequence(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package coins | ||
|
||
import ( | ||
"errors" | ||
|
||
base "cosmossdk.io/api/cosmos/base/v1beta1" | ||
"cosmossdk.io/math" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
) | ||
|
||
var ( | ||
_ withAmount = &base.Coin{} | ||
_ withAmount = &base.DecCoin{} | ||
) | ||
|
||
type withAmount interface { | ||
GetAmount() string | ||
} | ||
|
||
// IsZero check if given coins are zero. | ||
func IsZero[T withAmount](coins []T) (bool, error) { | ||
for _, coin := range coins { | ||
amount, ok := math.NewIntFromString(coin.GetAmount()) | ||
if !ok { | ||
return false, errors.New("invalid coin amount") | ||
} | ||
if !amount.IsZero() { | ||
return false, nil | ||
} | ||
} | ||
return true, nil | ||
} | ||
|
||
func ParseDecCoins(coins string) ([]*base.DecCoin, error) { | ||
parsedGasPrices, err := sdk.ParseDecCoins(coins) // TODO: do it here to avoid sdk dependency | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
finalGasPrices := make([]*base.DecCoin, len(parsedGasPrices)) | ||
for i, coin := range parsedGasPrices { | ||
finalGasPrices[i] = &base.DecCoin{ | ||
Denom: coin.Denom, | ||
Amount: coin.Amount.String(), | ||
} | ||
} | ||
return finalGasPrices, nil | ||
} | ||
|
||
func ParseCoinsNormalized(coins string) ([]*base.Coin, error) { | ||
parsedFees, err := sdk.ParseCoinsNormalized(coins) // TODO: do it here to avoid sdk dependency | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
finalFees := make([]*base.Coin, len(parsedFees)) | ||
for i, coin := range parsedFees { | ||
finalFees[i] = &base.Coin{ | ||
Denom: coin.Denom, | ||
Amount: coin.Amount.String(), | ||
} | ||
} | ||
|
||
return finalFees, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package coins | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
base "cosmossdk.io/api/cosmos/base/v1beta1" | ||
) | ||
|
||
func TestCoinIsZero(t *testing.T) { | ||
type testCase[T withAmount] struct { | ||
name string | ||
coins []T | ||
isZero bool | ||
} | ||
tests := []testCase[*base.Coin]{ | ||
{ | ||
name: "not zero coin", | ||
coins: []*base.Coin{ | ||
{ | ||
Denom: "stake", | ||
Amount: "100", | ||
}, | ||
}, | ||
isZero: false, | ||
}, | ||
{ | ||
name: "zero coin", | ||
coins: []*base.Coin{ | ||
{ | ||
Denom: "stake", | ||
Amount: "0", | ||
}, | ||
}, | ||
isZero: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := IsZero(tt.coins) | ||
require.NoError(t, err) | ||
require.Equal(t, got, tt.isZero) | ||
}) | ||
} | ||
} | ||
|
||
func TestDecCoinIsZero(t *testing.T) { | ||
type testCase[T withAmount] struct { | ||
name string | ||
coins []T | ||
isZero bool | ||
} | ||
tests := []testCase[*base.DecCoin]{ | ||
{ | ||
name: "not zero coin", | ||
coins: []*base.DecCoin{ | ||
{ | ||
Denom: "stake", | ||
Amount: "100", | ||
}, | ||
}, | ||
isZero: false, | ||
}, | ||
{ | ||
name: "zero coin", | ||
coins: []*base.DecCoin{ | ||
{ | ||
Denom: "stake", | ||
Amount: "0", | ||
}, | ||
}, | ||
isZero: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := IsZero(tt.coins) | ||
require.NoError(t, err) | ||
require.Equal(t, got, tt.isZero) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.