Skip to content
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 implementation #1888

Merged
merged 23 commits into from
Apr 6, 2023
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
## Features

- [1867](https://github.com/umee-network/umee/pull/1867) Allow `/denom` option on registered tokens query to get only a single token by `base_denom`.
- [1888](https://github.com/umee-network/umee/pull/1888) Created `/sdkclient` and `/client` (umee client) packages to easy the E2E tests and external tools. Essentially, you can import that client and broadcast transactions easily.

## [v4.1.0](https://github.com/umee-network/umee/releases/tag/v4.1.0) - 2023-02-15

Expand Down
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -288,7 +289,7 @@ func New(
skipUpgradeHeights map[int64]bool,
homePath string,
invCheckPeriod uint,
encodingConfig appparams.EncodingConfig,
encodingConfig sdkparams.EncodingConfig,
appOpts servertypes.AppOptions,
wasmEnabledProposals []wasm.ProposalType,
wasmOpts []wasm.Option,
Expand Down
4 changes: 2 additions & 2 deletions app/encoding.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package app

import (
sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/std"

"github.com/umee-network/umee/v4/app/params"
)

// MakeEncodingConfig returns the application's encoding configuration with all
// types and interfaces registered.
func MakeEncodingConfig() params.EncodingConfig {
func MakeEncodingConfig() sdkparams.EncodingConfig {
encodingConfig := params.MakeEncodingConfig()
std.RegisterLegacyAminoCodec(encodingConfig.Amino)
std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
Expand Down
16 changes: 0 additions & 16 deletions app/params/encoding.go

This file was deleted.

18 changes: 3 additions & 15 deletions app/params/proto.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
package params

import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/simapp/params"
)

// MakeEncodingConfig creates an EncodingConfig for Amino-based tests.
func MakeEncodingConfig() EncodingConfig {
amino := codec.NewLegacyAmino()
interfaceRegistry := types.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)

return EncodingConfig{
InterfaceRegistry: interfaceRegistry,
Codec: marshaler,
TxConfig: txCfg,
Amino: amino,
}
func MakeEncodingConfig() params.EncodingConfig {
return params.MakeTestEncodingConfig()
}
36 changes: 36 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package client
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"

sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/umee-network/umee/v4/sdkclient"
)

type Client struct {
sdkclient.Client
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
}

// Initializes a cosmos sdk client context and transaction factory for
// signing and broadcasting transactions
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
func NewClient(
chainID,
tmrpcEndpoint,
grpcEndpoint,
accountName,
accountMnemonic string,
gasAdjustment float64,
ecfg sdkparams.EncodingConfig,
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
) (Client, error) {
c, err := sdkclient.NewClient(chainID, tmrpcEndpoint, grpcEndpoint, accountName, accountMnemonic, gasAdjustment, ecfg)
if err != nil {
return Client{}, err
}
return Client{
Client: c,
}, nil
}

func (c *Client) NewQCtx() (context.Context, context.CancelFunc) {
return c.Query.NewCtx()
}
43 changes: 43 additions & 0 deletions client/oracle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package client

import (
sdk "github.com/cosmos/cosmos-sdk/types"

oracletypes "github.com/umee-network/umee/v4/x/oracle/types"
)

func (c *Client) OracleQueryClient() oracletypes.QueryClient {
return oracletypes.NewQueryClient(c.Query.GrpcConn)
}

func (c *Client) QueryOracleParams() (oracletypes.Params, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

queryResponse, err := c.OracleQueryClient().Params(ctx, &oracletypes.QueryParams{})
return queryResponse.Params, err

Check warning

Code scanning / CodeQL

Missing error check

[queryResponse](1) may be nil at this dereference because [err](2) may not have been checked.
}

func (c *Client) QueryExchangeRates() ([]sdk.DecCoin, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

queryResponse, err := c.OracleQueryClient().ExchangeRates(ctx, &oracletypes.QueryExchangeRates{})
return queryResponse.ExchangeRates, err

Check warning

Code scanning / CodeQL

Missing error check

[queryResponse](1) may be nil at this dereference because [err](2) may not have been checked.
}

func (c *Client) QueryMedians() ([]oracletypes.Price, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

resp, err := c.OracleQueryClient().Medians(ctx, &oracletypes.QueryMedians{})
return resp.Medians, err

Check warning

Code scanning / CodeQL

Missing error check

[resp](1) may be nil at this dereference because [err](2) may not have been checked.
}

func (c *Client) QueryMedianDeviations() ([]oracletypes.Price, error) {
ctx, cancel := c.NewQCtx()
defer cancel()

queryResponse, err := c.OracleQueryClient().MedianDeviations(ctx, &oracletypes.QueryMedianDeviations{})
return queryResponse.MedianDeviations, err

Check warning

Code scanning / CodeQL

Missing error check

[queryResponse](1) may be nil at this dereference because [err](2) may not have been checked.
}
3 changes: 2 additions & 1 deletion cmd/umeed/cmd/app_creator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/snapshots"
snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types"
"github.com/cosmos/cosmos-sdk/store"
Expand All @@ -29,7 +30,7 @@ import (
)

type appCreator struct {
encCfg appparams.EncodingConfig
encCfg sdkparams.EncodingConfig
moduleManager module.BasicManager
}

Expand Down
3 changes: 2 additions & 1 deletion cmd/umeed/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/server"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
Expand All @@ -29,7 +30,7 @@ import (
)

// NewRootCmd returns the root command handler for the Umee daemon.
func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) {
func NewRootCmd() (*cobra.Command, sdkparams.EncodingConfig) {
encodingConfig := umeeapp.MakeEncodingConfig()
moduleManager := umeeapp.ModuleBasics

Expand Down
4 changes: 2 additions & 2 deletions price-feeder/oracle/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
Expand All @@ -22,7 +23,6 @@ import (
rpchttp "github.com/tendermint/tendermint/rpc/client/http"
tmjsonclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
umeeapp "github.com/umee-network/umee/v4/app"
umeeparams "github.com/umee-network/umee/v4/app/params"
)

type (
Expand All @@ -39,7 +39,7 @@ type (
OracleAddrString string
ValidatorAddr sdk.ValAddress
ValidatorAddrString string
Encoding umeeparams.EncodingConfig
Encoding sdkparams.EncodingConfig
GasPrices string
GasAdjustment float64
GRPCEndpoint string
Expand Down
111 changes: 111 additions & 0 deletions sdkclient/chain_height.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package sdkclient

import (
"context"
"errors"
"sync"

"github.com/rs/zerolog"
tmrpcclient "github.com/tendermint/tendermint/rpc/client"
tmctypes "github.com/tendermint/tendermint/rpc/core/types"
tmtypes "github.com/tendermint/tendermint/types"
)

var (
errParseEventDataNewBlockHeader = errors.New("error parsing EventDataNewBlockHeader")
queryEventNewBlockHeader = tmtypes.QueryForEvent(tmtypes.EventNewBlockHeader)
)

// ChainHeightListener is used to cache the chain height of the
// current node which is being updated each time the
// node sends an event of EventNewBlockHeader.
// It starts a goroutine to subscribe to blockchain new block event and update the cached height.
type ChainHeightListener struct {
Logger zerolog.Logger

mtx sync.RWMutex
errGetChainHeight error
lastChainHeight int64
HeightChanged chan (int64)
}

// NewChainHeight returns a new ChainHeight struct that
// starts a new goroutine subscribed to EventNewBlockHeader.
func NewChainHeightListener(
ctx context.Context,
rpcClient tmrpcclient.Client,
logger zerolog.Logger,
) (*ChainHeightListener, error) {
if !rpcClient.IsRunning() {
if err := rpcClient.Start(); err != nil {
return nil, err
}
}

newBlockHeaderSubscription, err := rpcClient.Subscribe(
ctx, tmtypes.EventNewBlockHeader, queryEventNewBlockHeader.String())
if err != nil {
return nil, err
}
chainHeight := &ChainHeightListener{
Logger: logger.With().Str("app_client", "chain_height").Logger(),
HeightChanged: make(chan int64),
}

go chainHeight.subscribe(ctx, rpcClient, newBlockHeaderSubscription)

Check notice

Code scanning / CodeQL

Spawning a Go routine

Spawning a Go routine may be a possible source of non-determinism

return chainHeight, nil
}

// setChainHeight receives the data to be updated thread safe.
func (chainHeight *ChainHeightListener) setChainHeight(blockHeight int64, err error) {
chainHeight.mtx.Lock()
defer chainHeight.mtx.Unlock()

if chainHeight.lastChainHeight != blockHeight {
select {
case chainHeight.HeightChanged <- blockHeight:
default:
}
}
chainHeight.lastChainHeight = blockHeight
chainHeight.errGetChainHeight = err
}

// subscribe listens to new blocks being made
// and updates the chain height.
func (chainHeight *ChainHeightListener) subscribe(
ctx context.Context,
eventsClient tmrpcclient.EventsClient,
newBlockHeaderSubscription <-chan tmctypes.ResultEvent,
) {
for {
select {
case <-ctx.Done():
err := eventsClient.Unsubscribe(ctx, tmtypes.EventNewBlockHeader, queryEventNewBlockHeader.String())
if err != nil {
chainHeight.Logger.Err(err)
chainHeight.setChainHeight(chainHeight.lastChainHeight, err)
}
chainHeight.Logger.Info().Msg("closing the ChainHeight subscription")
return

case resultEvent := <-newBlockHeaderSubscription:
eventDataNewBlockHeader, ok := resultEvent.Data.(tmtypes.EventDataNewBlockHeader)
if !ok {
chainHeight.Logger.Err(errParseEventDataNewBlockHeader)
chainHeight.setChainHeight(chainHeight.lastChainHeight, errParseEventDataNewBlockHeader)
continue
}
chainHeight.setChainHeight(eventDataNewBlockHeader.Header.Height, nil)
}
}
}

// GetHeight returns the last chain height available.
func (chainHeight *ChainHeightListener) GetHeight() (int64, error) {
chainHeight.mtx.RLock()
defer chainHeight.mtx.RUnlock()

return chainHeight.lastChainHeight, chainHeight.errGetChainHeight
}
49 changes: 49 additions & 0 deletions sdkclient/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package sdkclient

import (
"context"
"time"

sdkparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/rs/zerolog"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/umee-network/umee/v4/sdkclient/query"
"github.com/umee-network/umee/v4/sdkclient/tx"
)

// OjoClient is a helper for initializing a keychain, a cosmos-sdk client context,
robert-zaremba marked this conversation as resolved.
Show resolved Hide resolved
// and sending transactions/queries to a specific Umee node
type Client struct {
Query *query.Client
Tx *tx.Client
}

func NewClient(
chainID,
tmrpcEndpoint,
grpcEndpoint,
accountName,
accountMnemonic string,
gasAdjustment float64,
ecfg sdkparams.EncodingConfig,
) (uc Client, err error) {
uc = Client{}
uc.Query, err = query.NewClient(grpcEndpoint, 15*time.Second)
if err != nil {
return Client{}, err
}
uc.Tx, err = tx.NewClient(chainID, tmrpcEndpoint, accountName, accountMnemonic, gasAdjustment, ecfg)
return uc, err
}

func (c Client) NewChainHeightListener(ctx context.Context, logger zerolog.Logger) (*ChainHeightListener, error) {
return NewChainHeightListener(ctx, c.Tx.ClientContext.Client, logger)
}

func (c Client) QueryTimeout() time.Duration {
return c.Query.QueryTimeout
}

func (c Client) TmClient() rpcclient.Client {
return c.Tx.ClientContext.Client
}
Loading