-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(client/v2): factory and txBuilder #20623
Open
JulianToledano
wants to merge
41
commits into
main
Choose a base branch
from
julian/v2-tx-builder
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 38 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
d4d2320
first approach
JulianToledano 2a777df
TxBuilder implemented
JulianToledano ffe66ac
add: txBuilder tests
JulianToledano 3cbcdcb
txconfig
JulianToledano 2ff6edd
factory works
JulianToledano 5fec5af
update: Decoder interface,
JulianToledano 6eb3c98
update: factory
JulianToledano deb9fa3
Merge branch 'main' into julian/v2-tx-builder
JulianToledano f3071a4
add: factory tests
JulianToledano a62bc64
Merge branch 'main' into julian/v2-tx-builder
JulianToledano b9bcaa6
del: most sdk dependency
JulianToledano 1270a87
fix: dry-run and sign
JulianToledano 2e4895f
update: simplify accountconfig setter
JulianToledano 51ffeb2
fix: dry-run offline
JulianToledano 189e6b3
add: godoc
JulianToledano 4fadeff
lint
JulianToledano d49ce6f
Merge branch 'main' into julian/v2-tx-builder
JulianToledano c2b2539
add: SignaturesMarshal
JulianToledano 1a29aa8
lint
JulianToledano 5854380
remove todo
JulianToledano 4094945
fix: go-mod-tidy-all
JulianToledano 9ee9940
update: coderrabbit suggestions
JulianToledano cd55292
fix: signingTxData encoding
JulianToledano 3dcc970
add: DecodedTx wrapper
JulianToledano 4b55c93
update: encoder decoder
JulianToledano 3db0bab
lint :)
JulianToledano 87677d7
add: readme with diagrams
JulianToledano d360670
lint
JulianToledano 5a8aba9
update: buildSignedTx
JulianToledano 1e3e29f
Merge branch 'main' into julian/v2-tx-builder
JulianToledano 7acdd15
update: use timeoutTimestamp,
JulianToledano a0dc147
update: prepare is now only used in constructor
JulianToledano 78bb01e
update: remove generateOnly from params
JulianToledano 1c76296
update: remove offchain from params
JulianToledano 4c8ee9b
update: remove offline from params
JulianToledano d849302
del: remove default gas
JulianToledano 7ffed78
lint
JulianToledano 738605d
Merge branch 'main' into julian/v2-tx-builder
JulianToledano 4a51df0
avoid flags2
JulianToledano 9153602
lint-happy
JulianToledano 9547499
tidy
JulianToledano File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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" | ||
authtypes "cosmossdk.io/x/auth/types" | ||
|
||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
sdk "github.com/cosmos/cosmos-sdk/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 | ||
} | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// 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 | ||
} | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 | ||
} | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package grpc | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
gogogrpc "github.com/cosmos/gogoproto/grpc" | ||
"google.golang.org/grpc" | ||
) | ||
|
||
var _ gogogrpc.ClientConn = ClientConn{} | ||
|
||
type ClientConn struct{} | ||
|
||
func (c ClientConn) Invoke(ctx context.Context, method string, args, reply interface{}, opts ...grpc.CallOption) error { | ||
panic("implement me") | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
func (c ClientConn) NewStream(ctx context.Context, desc *grpc.StreamDesc, method string, opts ...grpc.CallOption) (grpc.ClientStream, error) { | ||
return nil, fmt.Errorf("streaming rpc not supported") | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
JulianToledano marked this conversation as resolved.
Show resolved
Hide resolved
|
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.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure but isn't
address.Codec
available insideContext
?