Kava gRPC Client (#1784)

* add grpc client

* add e2e tests for grpc client

* add grpc client readme

* doc update

* fix more doc issues

* remove util namespace & move grpc client to chain

* rename GrpcClient to Grpc

* add 3rd party query clients

* fix invalid url in readme

* update e2e tests to use grpc client (#1787)
This commit is contained in:
Draco 2023-12-13 12:17:37 -05:00 committed by GitHub
parent c63fab1317
commit ffd306ef52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 552 additions and 117 deletions

View File

@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (community) [#1704] Add module params
- (community) [#1706] Add disable inflation upgrade
- (community) [#1745] Enable params update via governance with `MsgUpdateParams`
- (client) [#1784] Add Kava gRPC client
### Bug Fixes
@ -72,6 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [v0.24.1]
### Features
- (metrics) [#1668] Adds non-state breaking x/metrics module for custom telemetry.
- (metrics) [#1669] Add performance timing metrics to all Begin/EndBlockers
- (community) [#1751] Add `AnnualizedRewards` query endpoint
@ -315,6 +317,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
- [#257](https://github.com/Kava-Labs/kava/pulls/257) Include scripts to run
large-scale simulations remotely using aws-batch
[#1784]: https://github.com/Kava-Labs/kava/pull/1784
[#1776]: https://github.com/Kava-Labs/kava/pull/1776
[#1770]: https://github.com/Kava-Labs/kava/pull/1770
[#1755]: https://github.com/Kava-Labs/kava/pull/1755

74
client/grpc/README.md Normal file
View File

@ -0,0 +1,74 @@
# Kava gRPC Client
The Kava gRPC client is a tool for making gRPC queries on a Kava chain.
## Features
- Easy-to-use gRPC client for the Kava chain.
- Access all query clients for Cosmos and Kava modules using `client.Query` (e.g., `client.Query.Bank.Balance`).
- Utilize utility functions for common queries (e.g., `client.BaseAccount(str)`).
## Usage
### Creating a new client
```go
package main
import (
kavaGrpc "github.com/kava-labs/kava/client/grpc"
)
grpcUrl := "https://grpc.kava.io:443"
client, err := kavaGrpc.NewClient(grpcUrl)
if err != nil {
panic(err)
}
```
### Making grpc queries
Query clients for both Cosmos and Kava modules are available via `client.Query`.
Example: Query Cosmos module `x/bank` for address balance
```go
import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
rsp, err := client.Query.Bank.Balance(context.Background(), &banktypes.QueryBalanceRequest{
Address: "kava19rjk5qmmwywnzfccwzyn02jywgpwjqf60afj92",
Denom: "ukava",
})
```
Example: Query Kava module `x/evmutil` for params
```go
import (
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
)
rsp, err := client.Query.Evmutil.Params(
context.Background(), &evmutiltypes.QueryParamsRequest{},
)
```
#### Query Utilities
Utility functions for common queries are available directly on the client.
Example: Util query to get a base account
```go
kavaAcc := "kava19rjk5qmmwywnzfccwzyn02jywgpwjqf60afj92"
rsp, err := client.BaseAccount(kavaAcc)
if err != nil {
panic(err)
}
fmt.Printf("account sequence for %s: %d\n", kavaAcc, rsp.Sequence)
```
## Query Tests
To test queries, a Kava node is required. Therefore, the e2e tests for the gRPC client queries can be found in the `tests/e2e` directory. Tests for new utility queries should be added as e2e tests under the `test/e2e` directory.

50
client/grpc/client.go Normal file
View File

@ -0,0 +1,50 @@
package grpc
import (
"errors"
"github.com/kava-labs/kava/client/grpc/query"
"github.com/kava-labs/kava/client/grpc/util"
)
// KavaGrpcClient enables the usage of kava grpc query clients and query utils
type KavaGrpcClient struct {
config KavaGrpcClientConfig
// Query clients for cosmos and kava modules
Query *query.QueryClient
// Utils for common queries (ie fetch an unpacked BaseAccount)
*util.Util
}
// KavaGrpcClientConfig is a configuration struct for a KavaGrpcClient
type KavaGrpcClientConfig struct {
// note: add future config options here
}
// NewClient creates a new KavaGrpcClient via a grpc url
func NewClient(grpcUrl string) (*KavaGrpcClient, error) {
return NewClientWithConfig(grpcUrl, NewDefaultConfig())
}
// NewClientWithConfig creates a new KavaGrpcClient via a grpc url and config
func NewClientWithConfig(grpcUrl string, config KavaGrpcClientConfig) (*KavaGrpcClient, error) {
if grpcUrl == "" {
return nil, errors.New("grpc url cannot be empty")
}
query, error := query.NewQueryClient(grpcUrl)
if error != nil {
return nil, error
}
client := &KavaGrpcClient{
Query: query,
Util: util.NewUtil(query),
config: config,
}
return client, nil
}
func NewDefaultConfig() KavaGrpcClientConfig {
return KavaGrpcClientConfig{}
}

View File

@ -0,0 +1,15 @@
package grpc_test
import (
"testing"
"github.com/kava-labs/kava/client/grpc"
"github.com/stretchr/testify/require"
)
func TestNewClient_InvalidEndpoint(t *testing.T) {
_, err := grpc.NewClient("invalid-url")
require.ErrorContains(t, err, "unknown grpc url scheme")
_, err = grpc.NewClient("")
require.ErrorContains(t, err, "grpc url cannot be empty")
}

View File

@ -1,25 +1,21 @@
package util
package query
import (
"context"
"crypto/tls"
"fmt"
"net/url"
"strconv"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
)
// NewGrpcConnection parses a GRPC endpoint and creates a connection to it
func NewGrpcConnection(endpoint string) (*grpc.ClientConn, error) {
// newGrpcConnection parses a GRPC endpoint and creates a connection to it
func newGrpcConnection(ctx context.Context, endpoint string) (*grpc.ClientConn, error) {
grpcUrl, err := url.Parse(endpoint)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to parse grpc connection \"%s\": %v", endpoint, err)
}
var creds credentials.TransportCredentials
@ -33,15 +29,10 @@ func NewGrpcConnection(endpoint string) (*grpc.ClientConn, error) {
}
secureOpt := grpc.WithTransportCredentials(creds)
grpcConn, err := grpc.Dial(grpcUrl.Host, secureOpt)
grpcConn, err := grpc.DialContext(ctx, grpcUrl.Host, secureOpt)
if err != nil {
return nil, err
}
return grpcConn, nil
}
func CtxAtHeight(height int64) context.Context {
heightStr := strconv.FormatInt(height, 10)
return metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, heightStr)
}

7
client/grpc/query/doc.go Normal file
View File

@ -0,0 +1,7 @@
/*
The query package includes Cosmos and Kava gRPC query clients.
To ensure that the `QueryClient` stays updated, add new module query clients
to the `QueryClient` whenever new modules with grpc queries are added to the Kava app.
*/
package query

132
client/grpc/query/query.go Normal file
View File

@ -0,0 +1,132 @@
package query
import (
"context"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
authz "github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
disttypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
govv1beta1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
paramstypes "github.com/cosmos/cosmos-sdk/x/params/types/proposal"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
ibctransfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
ibcclienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
feemarkettypes "github.com/evmos/ethermint/x/feemarket/types"
auctiontypes "github.com/kava-labs/kava/x/auction/types"
bep3types "github.com/kava-labs/kava/x/bep3/types"
cdptypes "github.com/kava-labs/kava/x/cdp/types"
committeetypes "github.com/kava-labs/kava/x/committee/types"
communitytypes "github.com/kava-labs/kava/x/community/types"
earntypes "github.com/kava-labs/kava/x/earn/types"
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
hardtypes "github.com/kava-labs/kava/x/hard/types"
incentivetypes "github.com/kava-labs/kava/x/incentive/types"
issuancetypes "github.com/kava-labs/kava/x/issuance/types"
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
liquidtypes "github.com/kava-labs/kava/x/liquid/types"
pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
savingstypes "github.com/kava-labs/kava/x/savings/types"
swaptypes "github.com/kava-labs/kava/x/swap/types"
)
// QueryClient is a wrapper with all Cosmos and Kava grpc query clients
type QueryClient struct {
// cosmos-sdk query clients
Tm tmservice.ServiceClient
Tx txtypes.ServiceClient
Auth authtypes.QueryClient
Authz authz.QueryClient
Bank banktypes.QueryClient
Distribution disttypes.QueryClient
Evidence evidencetypes.QueryClient
Gov govv1types.QueryClient
GovBeta govv1beta1types.QueryClient
Mint minttypes.QueryClient
Params paramstypes.QueryClient
Slashing slashingtypes.QueryClient
Staking stakingtypes.QueryClient
Upgrade upgradetypes.QueryClient
// 3rd party query clients
Evm evmtypes.QueryClient
Feemarket feemarkettypes.QueryClient
IbcClient ibcclienttypes.QueryClient
IbcTransfer ibctransfertypes.QueryClient
// kava module query clients
Auction auctiontypes.QueryClient
Bep3 bep3types.QueryClient
Cdp cdptypes.QueryClient
Committee committeetypes.QueryClient
Community communitytypes.QueryClient
Earn earntypes.QueryClient
Evmutil evmutiltypes.QueryClient
Hard hardtypes.QueryClient
Incentive incentivetypes.QueryClient
Issuance issuancetypes.QueryClient
Kavadist kavadisttypes.QueryClient
Liquid liquidtypes.QueryClient
Pricefeed pricefeedtypes.QueryClient
Savings savingstypes.QueryClient
Swap swaptypes.QueryClient
}
// NewQueryClient creates a new QueryClient and initializes all the module query clients
func NewQueryClient(grpcEndpoint string) (*QueryClient, error) {
conn, err := newGrpcConnection(context.Background(), grpcEndpoint)
if err != nil {
return &QueryClient{}, err
}
client := &QueryClient{
Tm: tmservice.NewServiceClient(conn),
Tx: txtypes.NewServiceClient(conn),
Auth: authtypes.NewQueryClient(conn),
Authz: authz.NewQueryClient(conn),
Bank: banktypes.NewQueryClient(conn),
Distribution: disttypes.NewQueryClient(conn),
Evidence: evidencetypes.NewQueryClient(conn),
Gov: govv1types.NewQueryClient(conn),
GovBeta: govv1beta1types.NewQueryClient(conn),
Mint: minttypes.NewQueryClient(conn),
Params: paramstypes.NewQueryClient(conn),
Slashing: slashingtypes.NewQueryClient(conn),
Staking: stakingtypes.NewQueryClient(conn),
Upgrade: upgradetypes.NewQueryClient(conn),
Evm: evmtypes.NewQueryClient(conn),
Feemarket: feemarkettypes.NewQueryClient(conn),
IbcClient: ibcclienttypes.NewQueryClient(conn),
IbcTransfer: ibctransfertypes.NewQueryClient(conn),
Auction: auctiontypes.NewQueryClient(conn),
Bep3: bep3types.NewQueryClient(conn),
Cdp: cdptypes.NewQueryClient(conn),
Committee: committeetypes.NewQueryClient(conn),
Community: communitytypes.NewQueryClient(conn),
Earn: earntypes.NewQueryClient(conn),
Evmutil: evmutiltypes.NewQueryClient(conn),
Hard: hardtypes.NewQueryClient(conn),
Incentive: incentivetypes.NewQueryClient(conn),
Issuance: issuancetypes.NewQueryClient(conn),
Kavadist: kavadisttypes.NewQueryClient(conn),
Liquid: liquidtypes.NewQueryClient(conn),
Pricefeed: pricefeedtypes.NewQueryClient(conn),
Savings: savingstypes.NewQueryClient(conn),
Swap: swaptypes.NewQueryClient(conn),
}
return client, nil
}

View File

@ -0,0 +1,73 @@
package query_test
import (
"testing"
"github.com/kava-labs/kava/client/grpc/query"
"github.com/stretchr/testify/require"
)
func TestNewQueryClient_InvalidGprc(t *testing.T) {
t.Run("valid connection", func(t *testing.T) {
conn, err := query.NewQueryClient("http://localhost:1234")
require.NoError(t, err)
require.NotNil(t, conn)
})
t.Run("non-empty url", func(t *testing.T) {
_, err := query.NewQueryClient("")
require.ErrorContains(t, err, "unknown grpc url scheme")
})
t.Run("invalid url scheme", func(t *testing.T) {
_, err := query.NewQueryClient("ftp://localhost:1234")
require.ErrorContains(t, err, "unknown grpc url scheme")
})
}
func TestNewQueryClient_ValidClient(t *testing.T) {
t.Run("all clients are created", func(t *testing.T) {
client, err := query.NewQueryClient("http://localhost:1234")
require.NoError(t, err)
require.NotNil(t, client)
// validate cosmos clients
require.NotNil(t, client.Tm)
require.NotNil(t, client.Tx)
require.NotNil(t, client.Auth)
require.NotNil(t, client.Authz)
require.NotNil(t, client.Bank)
require.NotNil(t, client.Distribution)
require.NotNil(t, client.Evidence)
require.NotNil(t, client.Gov)
require.NotNil(t, client.GovBeta)
require.NotNil(t, client.Mint)
require.NotNil(t, client.Params)
require.NotNil(t, client.Slashing)
require.NotNil(t, client.Staking)
require.NotNil(t, client.Upgrade)
// validate 3rd party clients
require.NotNil(t, client.Evm)
require.NotNil(t, client.Feemarket)
require.NotNil(t, client.IbcClient)
require.NotNil(t, client.IbcTransfer)
// validate kava clients
require.NotNil(t, client.Auction)
require.NotNil(t, client.Bep3)
require.NotNil(t, client.Cdp)
require.NotNil(t, client.Committee)
require.NotNil(t, client.Community)
require.NotNil(t, client.Earn)
require.NotNil(t, client.Evmutil)
require.NotNil(t, client.Hard)
require.NotNil(t, client.Incentive)
require.NotNil(t, client.Issuance)
require.NotNil(t, client.Kavadist)
require.NotNil(t, client.Liquid)
require.NotNil(t, client.Pricefeed)
require.NotNil(t, client.Savings)
require.NotNil(t, client.Swap)
})
}

View File

@ -0,0 +1,41 @@
package util
import (
"context"
"fmt"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// Account fetches an account via an address and returns the unpacked account
func (u *Util) Account(addr string) (authtypes.AccountI, error) {
res, err := u.query.Auth.Account(context.Background(), &authtypes.QueryAccountRequest{
Address: addr,
})
if err != nil {
return nil, fmt.Errorf("failed to fetch account: %w", err)
}
var acc authtypes.AccountI
err = u.encodingConfig.Marshaler.UnpackAny(res.Account, &acc)
if err != nil {
return nil, fmt.Errorf("failed to unpack account: %w", err)
}
return acc, nil
}
// BaseAccount fetches a base account via an address or returns an error if
// the account is not a base account
func (u *Util) BaseAccount(addr string) (authtypes.BaseAccount, error) {
acc, err := u.Account(addr)
if err != nil {
return authtypes.BaseAccount{}, err
}
bAcc, ok := acc.(*authtypes.BaseAccount)
if !ok {
return authtypes.BaseAccount{}, fmt.Errorf("%s is not a base account", addr)
}
return *bAcc, nil
}

8
client/grpc/util/doc.go Normal file
View File

@ -0,0 +1,8 @@
/*
The util package contains utility functions for the Kava gRPC client.
For example, `account.go` includes account-related query helpers.
In this file, utilities such as `client.Util.BaseAccount(addr)` is exposed to
query an account and return an unpacked `BaseAccount` instance.
*/
package util

32
client/grpc/util/util.go Normal file
View File

@ -0,0 +1,32 @@
package util
import (
"context"
"strconv"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"google.golang.org/grpc/metadata"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/app/params"
query "github.com/kava-labs/kava/client/grpc/query"
)
// Util contains utility functions for the Kava gRPC client
type Util struct {
query *query.QueryClient
encodingConfig params.EncodingConfig
}
// NewUtil creates a new Util instance
func NewUtil(query *query.QueryClient) *Util {
return &Util{
query: query,
encodingConfig: app.MakeEncodingConfig(),
}
}
func (u *Util) CtxAtHeight(height int64) context.Context {
heightStr := strconv.FormatInt(height, 10)
return metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, heightStr)
}

View File

@ -1,4 +1,4 @@
package client
package cmd
import (
"bufio"
@ -18,9 +18,9 @@ import (
var ethFlag = "eth"
// KeyCommands registers a sub-tree of commands to interact with
// keyCommands registers a sub-tree of commands to interact with
// local private key storage.
func KeyCommands(defaultNodeHome string) *cobra.Command {
func keyCommands(defaultNodeHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "keys",
Short: "Manage your application's keys",

View File

@ -22,7 +22,6 @@ import (
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/app/params"
kavaclient "github.com/kava-labs/kava/client"
"github.com/kava-labs/kava/cmd/kava/opendb"
)
@ -123,6 +122,6 @@ func addSubCmds(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, de
rootCmd.AddCommand(
newQueryCmd(),
newTxCmd(),
kavaclient.KeyCommands(app.DefaultNodeHome),
keyCommands(app.DefaultNodeHome),
)
}

View File

@ -41,7 +41,7 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_NonAuthority() {
res := kavaAcc.SignAndBroadcastKavaTx(req)
// ASSERT
_, err := util.WaitForSdkTxCommit(suite.Kava.Tx, res.Result.TxHash, 6*time.Second)
_, err := util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.Result.TxHash, 6*time.Second)
suite.Require().Error(err)
suite.Require().ErrorContains(
err,
@ -52,13 +52,13 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_NonAuthority() {
func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
// ARRANGE
govParamsRes, err := suite.Kava.Gov.Params(context.Background(), &govv1.QueryParamsRequest{
govParamsRes, err := suite.Kava.Grpc.Query.Gov.Params(context.Background(), &govv1.QueryParamsRequest{
ParamsType: govv1.ParamDeposit,
})
suite.NoError(err)
// Check initial params
communityParamsResInitial, err := suite.Kava.Community.Params(
communityParamsResInitial, err := suite.Kava.Grpc.Query.Community.Params(
context.Background(),
&communitytypes.QueryParamsRequest{},
)
@ -77,7 +77,7 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
// genesis should be set in the past so it runs immediately.
suite.Require().Eventually(
func() bool {
params, err := suite.Kava.Community.Params(
params, err := suite.Kava.Grpc.Query.Community.Params(
context.Background(),
&communitytypes.QueryParamsRequest{},
)
@ -132,7 +132,7 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
suite.Require().NoError(res.Err)
// Wait for proposal to be submitted
txRes, err := util.WaitForSdkTxCommit(suite.Kava.Tx, res.Result.TxHash, 6*time.Second)
txRes, err := util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.Result.TxHash, 6*time.Second)
suite.Require().NoError(err)
// Parse tx response to get proposal id
@ -157,12 +157,12 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
voteRes := whale.SignAndBroadcastKavaTx(voteReq)
suite.Require().NoError(voteRes.Err)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, voteRes.Result.TxHash, 6*time.Second)
_, err = util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, voteRes.Result.TxHash, 6*time.Second)
suite.Require().NoError(err)
// 3. Wait until proposal passes
suite.Require().Eventually(func() bool {
proposalRes, err := suite.Kava.Gov.Proposal(context.Background(), &govv1.QueryProposalRequest{
proposalRes, err := suite.Kava.Grpc.Query.Gov.Proposal(context.Background(), &govv1.QueryProposalRequest{
ProposalId: govRes.ProposalId,
})
suite.NoError(err)
@ -171,7 +171,7 @@ func (suite *IntegrationTestSuite) TestCommunityUpdateParams_Authority() {
}, 60*time.Second, 1*time.Second)
// Check parameters are updated
communityParamsRes, err := suite.Kava.Community.Params(
communityParamsRes, err := suite.Kava.Grpc.Query.Community.Params(
context.Background(),
&communitytypes.QueryParamsRequest{},
)

View File

@ -24,7 +24,10 @@ func setupConvertToCoinTest(
) (denom string, initialFunds sdk.Coins, user *testutil.SigningAccount) {
// we expect a denom to be registered to the allowed denoms param
// and for the funded account to have a balance for that denom
params, err := suite.Kava.Evmutil.Params(context.Background(), &evmutiltypes.QueryParamsRequest{})
params, err := suite.Kava.Grpc.Query.Evmutil.Params(
context.Background(),
&evmutiltypes.QueryParamsRequest{},
)
suite.NoError(err)
suite.GreaterOrEqual(
len(params.Params.AllowedCosmosDenoms), 1,
@ -73,7 +76,7 @@ func (suite *IntegrationTestSuite) setupAccountWithCosmosCoinERC20Balance(
sdkBalance = sdkBalance.Sub(convertAmount)
// query for the deployed contract
deployedContracts, err := suite.Kava.Evmutil.DeployedCosmosCoinContracts(
deployedContracts, err := suite.Kava.Grpc.Query.Evmutil.DeployedCosmosCoinContracts(
context.Background(),
&evmutiltypes.QueryDeployedCosmosCoinContractsRequest{CosmosDenoms: []string{denom}},
)
@ -109,7 +112,7 @@ func (suite *IntegrationTestSuite) TestConvertCosmosCoinsToFromERC20() {
suite.NoError(res.Err)
// query for the deployed contract
deployedContracts, err := suite.Kava.Evmutil.DeployedCosmosCoinContracts(
deployedContracts, err := suite.Kava.Grpc.Query.Evmutil.DeployedCosmosCoinContracts(
context.Background(),
&evmutiltypes.QueryDeployedCosmosCoinContractsRequest{CosmosDenoms: []string{denom}},
)
@ -191,18 +194,18 @@ func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
suite.NoError(err)
// submit the eip712 message to the chain.
res, err := suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
res, err := suite.Kava.Grpc.Query.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
TxBytes: txBytes,
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
})
suite.NoError(err)
suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 12*time.Second)
_, err = util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.TxResponse.TxHash, 12*time.Second)
suite.Require().NoError(err)
// query for the deployed contract
deployedContracts, err := suite.Kava.Evmutil.DeployedCosmosCoinContracts(
deployedContracts, err := suite.Kava.Grpc.Query.Evmutil.DeployedCosmosCoinContracts(
context.Background(),
&evmutiltypes.QueryDeployedCosmosCoinContractsRequest{CosmosDenoms: []string{denom}},
)
@ -245,14 +248,14 @@ func (suite *IntegrationTestSuite) TestEIP712ConvertCosmosCoinsToFromERC20() {
suite.NoError(err)
// submit the eip712 message to the chain
res, err = suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
res, err = suite.Kava.Grpc.Query.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
TxBytes: txBytes,
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
})
suite.NoError(err)
suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second)
_, err = util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.TxResponse.TxHash, 6*time.Second)
suite.NoError(err)
// check erc20 balance

View File

@ -87,18 +87,18 @@ func (suite *IntegrationTestSuite) TestEip712BasicMessageAuthorization() {
suite.NoError(err)
// broadcast tx
res, err := suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
res, err := suite.Kava.Grpc.Query.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
TxBytes: txBytes,
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
})
suite.NoError(err)
suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second)
_, err = util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.TxResponse.TxHash, 6*time.Second)
suite.NoError(err)
// check that the message was processed & the kava is transferred.
balRes, err := suite.Kava.Bank.Balance(context.Background(), &banktypes.QueryBalanceRequest{
balRes, err := suite.Kava.Grpc.Query.Bank.Balance(context.Background(), &banktypes.QueryBalanceRequest{
Address: receiver.String(),
Denom: "ukava",
})
@ -154,14 +154,14 @@ func (suite *IntegrationTestSuite) TestEip712ConvertToCoinAndDepositToLend() {
suite.NoError(err)
// broadcast tx
res, err := suite.Kava.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
res, err := suite.Kava.Grpc.Query.Tx.BroadcastTx(context.Background(), &txtypes.BroadcastTxRequest{
TxBytes: txBytes,
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
})
suite.NoError(err)
suite.Equal(sdkerrors.SuccessABCICode, res.TxResponse.Code)
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, res.TxResponse.TxHash, 6*time.Second)
_, err = util.WaitForSdkTxCommit(suite.Kava.Grpc.Query.Tx, res.TxResponse.TxHash, 6*time.Second)
suite.Require().NoError(err)
// check that depositor no longer has erc20 balance
@ -169,7 +169,7 @@ func (suite *IntegrationTestSuite) TestEip712ConvertToCoinAndDepositToLend() {
suite.BigIntsEqual(big.NewInt(0), balance, "expected no erc20 balance")
// check that account has cdp
cdpRes, err := suite.Kava.Cdp.Cdp(context.Background(), &cdptypes.QueryCdpRequest{
cdpRes, err := suite.Kava.Grpc.Query.Cdp.Cdp(context.Background(), &cdptypes.QueryCdpRequest{
CollateralType: suite.DeployedErc20.CdpCollateralType,
Owner: depositor.SdkAddress.String(),
})

View File

@ -0,0 +1,39 @@
package e2e_test
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
)
func (suite *IntegrationTestSuite) TestGrpcClientQueryCosmosModule_Balance() {
// ARRANGE
// setup kava account
funds := ukava(1e5) // .1 KAVA
kavaAcc := suite.Kava.NewFundedAccount("balance-test", sdk.NewCoins(funds))
// ACT
rsp, err := suite.Kava.Grpc.Query.Bank.Balance(context.Background(), &banktypes.QueryBalanceRequest{
Address: kavaAcc.SdkAddress.String(),
Denom: funds.Denom,
})
// ASSERT
suite.Require().NoError(err)
suite.Require().Equal(funds.Amount, rsp.Balance.Amount)
}
func (suite *IntegrationTestSuite) TestGrpcClientQueryKavaModule_EvmParams() {
// ACT
rsp, err := suite.Kava.Grpc.Query.Evmutil.Params(
context.Background(), &evmutiltypes.QueryParamsRequest{},
)
// ASSERT
suite.Require().NoError(err)
suite.Require().GreaterOrEqual(len(rsp.Params.AllowedCosmosDenoms), 1)
suite.Require().GreaterOrEqual(len(rsp.Params.EnabledConversionPairs), 1)
}

View File

@ -0,0 +1,20 @@
package e2e_test
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
func (suite *IntegrationTestSuite) TestGrpcClientUtil_Account() {
// ARRANGE
// setup kava account
kavaAcc := suite.Kava.NewFundedAccount("account-test", sdk.NewCoins(ukava(1e5)))
// ACT
rsp, err := suite.Kava.Grpc.BaseAccount(kavaAcc.SdkAddress.String())
// ASSERT
suite.Require().NoError(err)
suite.Equal(kavaAcc.SdkAddress.String(), rsp.Address)
suite.Greater(rsp.AccountNumber, uint64(1))
suite.Equal(uint64(0), rsp.Sequence)
}

View File

@ -50,7 +50,7 @@ func (suite *IntegrationTestSuite) TestChainID() {
suite.Equal(expectedEvmNetworkId, evmNetworkId)
// SDK query
nodeInfo, err := suite.Kava.Tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
nodeInfo, err := suite.Kava.Grpc.Query.Tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
suite.NoError(err)
suite.Equal(suite.Kava.ChainID, nodeInfo.DefaultNodeInfo.Network)
}
@ -65,7 +65,7 @@ func (suite *IntegrationTestSuite) TestFundedAccount() {
suite.Equal(acc.EvmAddress.Hex(), util.SdkToEvmAddress(acc.SdkAddress).Hex())
// check balance via SDK query
res, err := suite.Kava.Bank.Balance(context.Background(), banktypes.NewQueryBalanceRequest(
res, err := suite.Kava.Grpc.Query.Bank.Balance(context.Background(), banktypes.NewQueryBalanceRequest(
acc.SdkAddress, "ukava",
))
suite.NoError(err)

View File

@ -13,6 +13,6 @@ func (suite *IntegrationTestSuite) TestUpgradeHandler() {
suite.True(true)
// Uncomment & use these contexts to compare chain state before & after the upgrade occurs.
// beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
// afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
// beforeUpgradeCtx := suite.Kava.Grpc.CtxAtHeight(suite.UpgradeHeight - 1)
// afterUpgradeCtx := suite.Kava.Grpc.CtxAtHeight(suite.UpgradeHeight)
}

View File

@ -6,9 +6,6 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
rpchttpclient "github.com/tendermint/tendermint/rpc/client/http"
"google.golang.org/grpc"
"github.com/kava-labs/kava/tests/util"
)
var (
@ -30,11 +27,6 @@ func (c ChainDetails) EvmClient() (*ethclient.Client, error) {
return ethclient.Dial(c.EvmRpcUrl)
}
// GrpcConn creates a new connection to the underlying Grpc url.
func (c ChainDetails) GrpcConn() (*grpc.ClientConn, error) {
return util.NewGrpcConnection(c.GrpcUrl)
}
// RpcConn creates a new connection to the underlying Rpc url.
func (c ChainDetails) RpcConn() (*rpchttpclient.HTTP, error) {
return rpchttpclient.New(c.RpcUrl, "/websocket")

View File

@ -6,6 +6,8 @@ import (
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/kava-labs/kava/client/grpc"
)
// LiveNodeRunnerConfig implements NodeRunner.
@ -49,20 +51,19 @@ func (r LiveNodeRunner) StartChains() Chains {
}
// determine chain id
grpc, err := kavaChain.GrpcConn()
client, err := grpc.NewClient(kavaChain.GrpcUrl)
if err != nil {
panic(fmt.Sprintf("failed to establish grpc conn to %s: %s", r.config.KavaGrpcUrl, err))
panic(fmt.Sprintf("failed to create kava grpc client: %s", err))
}
tm := tmservice.NewServiceClient(grpc)
nodeInfo, err := tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
nodeInfo, err := client.Query.Tm.GetNodeInfo(context.Background(), &tmservice.GetNodeInfoRequest{})
if err != nil {
panic(fmt.Sprintf("failed to fetch kava node info: %s", err))
}
kavaChain.ChainId = nodeInfo.DefaultNodeInfo.Network
// determine staking denom
staking := stakingtypes.NewQueryClient(grpc)
stakingParams, err := staking.Params(context.Background(), &stakingtypes.QueryParamsRequest{})
stakingParams, err := client.Query.Staking.Params(context.Background(), &stakingtypes.QueryParamsRequest{})
if err != nil {
panic(fmt.Sprintf("failed to fetch kava staking params: %s", err))
}

View File

@ -101,8 +101,8 @@ func (chain *Chain) AddNewSigningAccountFromPrivKey(
kavaSigner := util.NewKavaSigner(
chainId,
chain.EncodingConfig,
chain.Auth,
chain.Tx,
chain.Grpc.Query.Auth,
chain.Grpc.Query.Tx,
privKey,
100,
)

View File

@ -8,18 +8,11 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
govv1types "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
evmhd "github.com/evmos/ethermint/crypto/hd"
tmclient "github.com/tendermint/tendermint/rpc/client"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
@ -28,18 +21,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
evmtypes "github.com/evmos/ethermint/x/evm/types"
"github.com/kava-labs/kava/app"
kavaparams "github.com/kava-labs/kava/app/params"
"github.com/kava-labs/kava/client/grpc"
"github.com/kava-labs/kava/tests/e2e/runner"
"github.com/kava-labs/kava/tests/util"
cdptypes "github.com/kava-labs/kava/x/cdp/types"
committeetypes "github.com/kava-labs/kava/x/committee/types"
communitytypes "github.com/kava-labs/kava/x/community/types"
earntypes "github.com/kava-labs/kava/x/earn/types"
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
)
// Chain wraps query clients & accounts for a network
@ -57,24 +43,9 @@ type Chain struct {
EncodingConfig kavaparams.EncodingConfig
Auth authtypes.QueryClient
Bank banktypes.QueryClient
Cdp cdptypes.QueryClient
Committee committeetypes.QueryClient
Community communitytypes.QueryClient
Distribution distrtypes.QueryClient
Kavadist kavadisttypes.QueryClient
Earn earntypes.QueryClient
Evm evmtypes.QueryClient
Evmutil evmutiltypes.QueryClient
Gov govv1types.QueryClient
Mint minttypes.QueryClient
Staking stakingtypes.QueryClient
Tm tmservice.ServiceClient
Tx txtypes.ServiceClient
Upgrade upgradetypes.QueryClient
TmSignClient tmclient.SignClient
Grpc *grpc.KavaGrpcClient
}
// NewChain creates the query clients & signing account management for a chain run on a set of ports.
@ -104,10 +75,11 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
}
chain.Keyring = kr
grpcConn, err := details.GrpcConn()
client, err := grpc.NewClient(details.GrpcUrl)
if err != nil {
return chain, err
chain.t.Fatalf("failed to create kava grpc client: %s", err)
}
chain.Grpc = client
chain.EvmClient, err = details.EvmClient()
if err != nil {
@ -119,23 +91,6 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
return chain, err
}
chain.Auth = authtypes.NewQueryClient(grpcConn)
chain.Bank = banktypes.NewQueryClient(grpcConn)
chain.Cdp = cdptypes.NewQueryClient(grpcConn)
chain.Committee = committeetypes.NewQueryClient(grpcConn)
chain.Community = communitytypes.NewQueryClient(grpcConn)
chain.Distribution = distrtypes.NewQueryClient(grpcConn)
chain.Kavadist = kavadisttypes.NewQueryClient(grpcConn)
chain.Earn = earntypes.NewQueryClient(grpcConn)
chain.Evm = evmtypes.NewQueryClient(grpcConn)
chain.Evmutil = evmutiltypes.NewQueryClient(grpcConn)
chain.Gov = govv1types.NewQueryClient(grpcConn)
chain.Mint = minttypes.NewQueryClient(grpcConn)
chain.Staking = stakingtypes.NewQueryClient(grpcConn)
chain.Tm = tmservice.NewServiceClient(grpcConn)
chain.Tx = txtypes.NewServiceClient(grpcConn)
chain.Upgrade = upgradetypes.NewQueryClient(grpcConn)
// initialize accounts map
chain.accounts = make(map[string]*SigningAccount)
// setup the signing account for the initially funded account (used to fund all other accounts)
@ -217,7 +172,7 @@ func (chain *Chain) RegisterErc20(address common.Address) {
// QuerySdkForBalances gets the balance of a particular address on this Chain.
func (chain *Chain) QuerySdkForBalances(addr sdk.AccAddress) sdk.Coins {
res, err := chain.Bank.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{
res, err := chain.Grpc.Query.Bank.AllBalances(context.Background(), &banktypes.QueryAllBalancesRequest{
Address: addr.String(),
})
require.NoError(chain.t, err)

View File

@ -23,7 +23,7 @@ func (suite *E2eTestSuite) NewEip712TxBuilder(
) client.TxBuilder {
// get account details
var accDetails authtypes.AccountI
a, err := chain.Auth.Account(context.Background(), &authtypes.QueryAccountRequest{
a, err := chain.Grpc.Query.Auth.Account(context.Background(), &authtypes.QueryAccountRequest{
Address: acc.SdkAddress.String(),
})
suite.NoError(err)
@ -39,7 +39,7 @@ func (suite *E2eTestSuite) NewEip712TxBuilder(
suite.NoError(err)
ethChainId := pc.Uint64()
evmParams, err := chain.Evm.Params(context.Background(), &evmtypes.QueryParamsRequest{})
evmParams, err := chain.Grpc.Query.Evm.Params(context.Background(), &evmtypes.QueryParamsRequest{})
suite.NoError(err)
fee := legacytx.NewStdFee(gas, gasAmount)

View File

@ -28,7 +28,7 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
}
// expect the erc20 to be enabled for conversion to sdk.Coin
params, err := suite.Kava.Evmutil.Params(context.Background(), &evmutiltypes.QueryParamsRequest{})
params, err := suite.Kava.Grpc.Query.Evmutil.Params(context.Background(), &evmutiltypes.QueryParamsRequest{})
if err != nil {
panic(fmt.Sprintf("failed to fetch evmutil params during init: %s", err))
}
@ -46,7 +46,7 @@ func (suite *E2eTestSuite) InitKavaEvmData() {
suite.Kava.RegisterErc20(suite.DeployedErc20.Address)
// expect the erc20's cosmos denom to be a supported cdp collateral type
cdpParams, err := suite.Kava.Cdp.Params(context.Background(), &types.QueryParamsRequest{})
cdpParams, err := suite.Kava.Grpc.Query.Cdp.Params(context.Background(), &types.QueryParamsRequest{})
suite.Require().NoError(err)
found = false
for _, cp := range cdpParams.Params.CollateralParams {