Skip to content

Commit

Permalink
feat: enhance rosetta support (#11609)
Browse files Browse the repository at this point in the history
* fee suggestion for construction/metadata

* rename module

* change default gas_limit for fee suggestion

* add rosetta items in template

* type fix for default-suggest-denom

* add default values

* add suggestion-related config

* force set to success for balance operations

* enable offline mode

* Revert "rename module"

This reverts commit ea433e7.

* increase defaultNodeTimeout for rosetta for huge genesis

* use DefaultGasLimit as DefaultSuggestGas

* use default gas limit as default gas suggest for rosetta

* add enable-default-fee-suggest for rosetta

* update config template

* prevent bad gateway due to huge genesis

* Apply suggestions from code review

Co-authored-by: Aleksandr Bezobchuk <[email protected]>
Co-authored-by: Anil Kumar Kammari <[email protected]>

* add price flag for rosetta standalone

* fix rosetta data/block when block identifier is unset

* add checking mismatched index/hash

* bump rosetta-sdk-go to v0.7.7

* bump dependency

* add changelog

* Apply suggestions from code review

* Apply suggestions from code review

* make gas_prices and gas_limit optional

* Apply suggestions from code review

* add changelog

* revive overwritten by cherrypick

* revive overwritten by cherry-pick

* rename local variable

* rename variables and configs

* Apply suggestions from code review

Co-authored-by: Aleksandr Bezobchuk <[email protected]>

* break validation into two if cases

* fix config toml template

Co-authored-by: yys <[email protected]>
Co-authored-by: Aleksandr Bezobchuk <[email protected]>
Co-authored-by: Anil Kumar Kammari <[email protected]>
  • Loading branch information
4 people authored May 2, 2022
1 parent 53003e1 commit 38a1132
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 49 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#10962](https://github.com/cosmos/cosmos-sdk/pull/10962) ADR-040: Add state migration from iavl (v1Store) to smt (v2Store)
* (types) [\#10948](https://github.com/cosmos/cosmos-sdk/issues/10948) Add `app-db-backend` to the `app.toml` config to replace the compile-time `types.DBbackend` variable.
* (authz)[\#11060](https://github.com/cosmos/cosmos-sdk/pull/11060) Support grant with no expire time.
* (rosetta) [\#11590](https://github.com/cosmos/cosmos-sdk/pull/11590) Add fee suggestion for rosetta and enable offline mode. Also force set events about Fees to Success to pass reconciliation test.

### API Breaking Changes

Expand Down Expand Up @@ -266,6 +267,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (cli) [\#11337](https://github.com/cosmos/cosmos-sdk/pull/11337) Fixes `show-adress` cli cmd
* (crypto) [\#11298](https://github.com/cosmos/cosmos-sdk/pull/11298) Fix cgo secp signature verification and update libscep256k1 library.
* (x/authz) [\#11512](https://github.com/cosmos/cosmos-sdk/pull/11512) Fix response of a panic to error, when subtracting balances.
* (rosetta) [\#11590](https://github.com/cosmos/cosmos-sdk/pull/11590) `/block` returns an error with nil pointer when a request has both of index and hash and increase timeout for huge genesis.
* (x/feegrant) [\#11813](https://github.com/cosmos/cosmos-sdk/pull/11813) Fix pagination total count in `AllowancesByGranter` query.

### State Machine Breaking
Expand Down
40 changes: 28 additions & 12 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/spf13/viper"

clientflags "github.com/cosmos/cosmos-sdk/client/flags"
pruningtypes "github.com/cosmos/cosmos-sdk/pruning/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -131,6 +132,15 @@ type RosettaConfig struct {

// Offline defines if the server must be run in offline mode
Offline bool `mapstructure:"offline"`

// EnableFeeSuggestion defines if the server should suggest fee by default
EnableFeeSuggestion bool `mapstructure:"enable-fee-suggestion"`

// GasToSuggest defines gas limit when calculating the fee
GasToSuggest int `mapstructure:"gas-to-suggest"`

// DenomToSuggest defines the defult denom for fee suggestion
DenomToSuggest string `mapstructure:"denom-to-suggest"`
}

// GRPCConfig defines configuration for the gRPC server.
Expand Down Expand Up @@ -236,12 +246,15 @@ func DefaultConfig() *Config {
Address: DefaultGRPCAddress,
},
Rosetta: RosettaConfig{
Enable: false,
Address: ":8080",
Blockchain: "app",
Network: "network",
Retries: 3,
Offline: false,
Enable: false,
Address: ":8080",
Blockchain: "app",
Network: "network",
Retries: 3,
Offline: false,
EnableFeeSuggestion: false,
GasToSuggest: clientflags.DefaultGasLimit,
DenomToSuggest: "uatom",
},
GRPCWeb: GRPCWebConfig{
Enable: true,
Expand Down Expand Up @@ -299,12 +312,15 @@ func GetConfig(v *viper.Viper) Config {
EnableUnsafeCORS: v.GetBool("api.enabled-unsafe-cors"),
},
Rosetta: RosettaConfig{
Enable: v.GetBool("rosetta.enable"),
Address: v.GetString("rosetta.address"),
Blockchain: v.GetString("rosetta.blockchain"),
Network: v.GetString("rosetta.network"),
Retries: v.GetInt("rosetta.retries"),
Offline: v.GetBool("rosetta.offline"),
Enable: v.GetBool("rosetta.enable"),
Address: v.GetString("rosetta.address"),
Blockchain: v.GetString("rosetta.blockchain"),
Network: v.GetString("rosetta.network"),
Retries: v.GetInt("rosetta.retries"),
Offline: v.GetBool("rosetta.offline"),
EnableFeeSuggestion: v.GetBool("rosetta.enable-fee-suggestion"),
GasToSuggest: v.GetInt("rosetta.gas-to-suggest"),
DenomToSuggest: v.GetString("rosetta.denom-to-suggest"),
},
GRPC: GRPCConfig{
Enable: v.GetBool("grpc.enable"),
Expand Down
12 changes: 12 additions & 0 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,18 @@ retries = {{ .Rosetta.Retries }}
# Offline defines if Rosetta server should run in offline mode.
offline = {{ .Rosetta.Offline }}
# EnableDefaultSuggestedFee defines if the server should suggest fee by default.
# If 'construction/medata' is called without gas limit and gas price,
# suggested fee based on gas-to-suggest and denom-to-suggest will be given.
enable-fee-suggestion = {{ .Rosetta.EnableFeeSuggestion }}
# GasToSuggest defines gas limit when calculating the fee
gas-to-suggest = {{ .Rosetta.GasToSuggest }}
# DenomToSuggest defines the defult denom for fee suggestion.
# Price must be in minimum-gas-prices.
denom-to-suggest = "{{ .Rosetta.DenomToSuggest }}"
###############################################################################
### gRPC Configuration ###
###############################################################################
Expand Down
45 changes: 40 additions & 5 deletions server/rosetta/client_online.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,32 @@ import (
"strconv"
"time"

rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
"github.com/cosmos/cosmos-sdk/version"

abcitypes "github.com/tendermint/tendermint/abci/types"
tmrpc "github.com/tendermint/tendermint/rpc/client"

rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
"google.golang.org/grpc/metadata"

"github.com/tendermint/tendermint/rpc/client/http"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"

crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"

sdk "github.com/cosmos/cosmos-sdk/types"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/version"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
auth "github.com/cosmos/cosmos-sdk/x/auth/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"

tmrpc "github.com/tendermint/tendermint/rpc/client"
)

// interface assertion
var _ crgtypes.Client = (*Client)(nil)

const defaultNodeTimeout = 15 * time.Second
const defaultNodeTimeout = time.Minute

// Client implements a single network client to interact with cosmos based chains
type Client struct {
Expand Down Expand Up @@ -121,6 +126,14 @@ func (c *Client) Ready() error {
if err != nil {
return err
}

// to prevent timeout of reading genesis block
var height int64 = -1
_, err = c.BlockByHeight(ctx, &height)
if err != nil {
return err
}

_, err = c.bank.TotalSupply(ctx, &bank.QueryTotalSupplyRequest{})
if err != nil {
return err
Expand Down Expand Up @@ -395,6 +408,28 @@ func (c *Client) ConstructionMetadataFromOptions(ctx context.Context, options ma
return nil, err
}

// if default fees suggestion is enabled and gas limit or price is unset, use default
if c.config.EnableFeeSuggestion {
if constructionOptions.GasLimit <= 0 {
constructionOptions.GasLimit = uint64(c.config.GasToSuggest)
}
if constructionOptions.GasPrice == "" {
denom := c.config.DenomToSuggest
constructionOptions.GasPrice = c.config.SuggestPrices.AmountOf(denom).String() + denom
}
}

if constructionOptions.GasLimit > 0 && constructionOptions.GasPrice != "" {
gasPrice, err := sdk.ParseDecCoin(constructionOptions.GasPrice)
if err != nil {
return nil, err
}
// check gasPrice is in the list
if !c.config.SuggestPrices.AmountOf(gasPrice.Denom).IsPositive() {
return nil, crgerrs.ErrBadArgument
}
}

signersData := make([]*SignerData, len(constructionOptions.ExpectedSigners))

for i, signer := range constructionOptions.ExpectedSigners {
Expand Down
91 changes: 75 additions & 16 deletions server/rosetta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import (

crg "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"

clientflags "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// configuration defaults constants
Expand All @@ -30,17 +32,27 @@ const (
DefaultNetwork = "network"
// DefaultOffline defines the default offline value
DefaultOffline = false
// DefaultEnableFeeSuggestion indicates to use fee suggestion if `construction/metadata` is called without gas limit and price
DefaultEnableFeeSuggestion = false
// DenomToSuggest defines the default denom for fee suggestion
DenomToSuggest = "uatom"
// DefaultPrices defines the default list of prices to suggest
DefaultPrices = "0.0uatom"
)

// configuration flags
const (
FlagBlockchain = "blockchain"
FlagNetwork = "network"
FlagTendermintEndpoint = "tendermint"
FlagGRPCEndpoint = "grpc"
FlagAddr = "addr"
FlagRetries = "retries"
FlagOffline = "offline"
FlagBlockchain = "blockchain"
FlagNetwork = "network"
FlagTendermintEndpoint = "tendermint"
FlagGRPCEndpoint = "grpc"
FlagAddr = "addr"
FlagRetries = "retries"
FlagOffline = "offline"
FlagEnableFeeSuggestion = "enable-fee-suggestion"
FlagGasToSuggest = "gas-to-suggest"
FlagDenomToSuggest = "denom-to-suggest"
FlagPricesToSuggest = "prices-to-suggest"
)

// Config defines the configuration of the rosetta server
Expand All @@ -65,6 +77,14 @@ type Config struct {
Retries int
// Offline defines if the server must be run in offline mode
Offline bool
// EnableFeeSuggestion indicates to use fee suggestion when `construction/metadata` is called without gas limit and price
EnableFeeSuggestion bool
// GasToSuggest defines the gas limit for fee suggestion
GasToSuggest int
// DenomToSuggest defines the default denom for fee suggestion
DenomToSuggest string
// SuggestPrices defines the gas prices for fee suggestion
SuggestPrices sdk.DecCoins
// Codec overrides the default data and construction api client codecs
Codec *codec.ProtoCodec
// InterfaceRegistry overrides the default data and construction api interface registry
Expand Down Expand Up @@ -99,8 +119,18 @@ func (c *Config) validate() error {
if c.Network == "" {
return fmt.Errorf("network not provided")
}
if c.Offline {
return fmt.Errorf("offline mode is not supported for stargate implementation due to how sigv2 works")
if c.GasToSuggest <= 0 {
c.GasToSuggest = clientflags.DefaultGasLimit
}
found := false
for i := 0; i < c.SuggestPrices.Len(); i++ {
if c.SuggestPrices.GetDenomByIndex(i) == c.DenomToSuggest {
found = true
break
}
}
if !found {
return fmt.Errorf("default suggest denom is not found in minimum-gas-prices")
}

// these are optional but it must be online
Expand Down Expand Up @@ -153,14 +183,39 @@ func FromFlags(flags *pflag.FlagSet) (*Config, error) {
if err != nil {
return nil, err
}
enableDefaultFeeSuggestion, err := flags.GetBool(FlagEnableFeeSuggestion)
if err != nil {
return nil, err
}
suggestGas, err := flags.GetInt(FlagGasToSuggest)
if err != nil {
return nil, err
}
suggestDenom, err := flags.GetString(FlagDenomToSuggest)
if err != nil {
return nil, err
}
suggestPrices, err := flags.GetString(FlagPricesToSuggest)
if err != nil {
return nil, err
}
prices, err := sdk.ParseDecCoins(suggestPrices)
if err != nil {
return nil, err
}

conf := &Config{
Blockchain: blockchain,
Network: network,
TendermintRPC: tendermintRPC,
GRPCEndpoint: gRPCEndpoint,
Addr: addr,
Retries: retries,
Offline: offline,
Blockchain: blockchain,
Network: network,
TendermintRPC: tendermintRPC,
GRPCEndpoint: gRPCEndpoint,
Addr: addr,
Retries: retries,
Offline: offline,
EnableFeeSuggestion: enableDefaultFeeSuggestion,
GasToSuggest: suggestGas,
DenomToSuggest: suggestDenom,
SuggestPrices: prices,
}
err = conf.validate()
if err != nil {
Expand Down Expand Up @@ -201,4 +256,8 @@ func SetFlags(flags *pflag.FlagSet) {
flags.String(FlagAddr, DefaultAddr, "the address rosetta will bind to")
flags.Int(FlagRetries, DefaultRetries, "the number of retries that will be done before quitting")
flags.Bool(FlagOffline, DefaultOffline, "run rosetta only with construction API")
flags.Bool(FlagEnableFeeSuggestion, DefaultEnableFeeSuggestion, "enable default fee suggestion")
flags.Int(FlagGasToSuggest, clientflags.DefaultGasLimit, "default gas for fee suggestion")
flags.String(FlagDenomToSuggest, DenomToSuggest, "default denom for fee suggestion")
flags.String(FlagPricesToSuggest, DefaultPrices, "default prices for fee suggestion")
}
2 changes: 1 addition & 1 deletion server/rosetta/converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func (c converter) Tx(rawTx tmtypes.Tx, txResult *abci.ResponseDeliverTx) (*rose
var balanceOps []*rosettatypes.Operation
// tx result might be nil, in case we're querying an unconfirmed tx from the mempool
if txResult != nil {
balanceOps = c.BalanceOps(status, txResult.Events)
balanceOps = c.BalanceOps(StatusTxSuccess, txResult.Events) // force set to success because no events for failed tx
}

// now normalize indexes
Expand Down
41 changes: 39 additions & 2 deletions server/rosetta/lib/internal/service/construction.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import (
"context"
"crypto/sha256"
"encoding/hex"
"strconv"
"strings"

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

"github.com/coinbase/rosetta-sdk-go/types"

"github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
Expand Down Expand Up @@ -69,9 +72,43 @@ func (on OnlineNetwork) ConstructionMetadata(ctx context.Context, request *types
return nil, errors.ToRosetta(err)
}

return &types.ConstructionMetadataResponse{
response := &types.ConstructionMetadataResponse{
Metadata: metadata,
}, nil
}

if metadata["gas_price"] != nil && metadata["gas_limit"] != nil {
gasPrice, ok := metadata["gas_price"].(string)
if !ok {
return nil, errors.ToRosetta(errors.WrapError(errors.ErrBadArgument, "invalid gas_price"))
}
if gasPrice == "" { // gas_price is unset. skip fee suggestion
return response, nil
}
price, err := sdk.ParseDecCoin(gasPrice)
if err != nil {
return nil, errors.ToRosetta(err)
}

gasLimit, ok := metadata["gas_limit"].(float64)
if !ok {
return nil, errors.ToRosetta(errors.WrapError(errors.ErrBadArgument, "invalid gas_limit"))
}
if gasLimit == 0 { // gas_limit is unset. skip fee suggestion
return response, nil
}
gas := sdk.NewIntFromUint64(uint64(gasLimit))

suggestedFee := types.Amount{
Value: strconv.FormatInt(price.Amount.MulInt64(gas.Int64()).Ceil().TruncateInt64(), 10),
Currency: &(types.Currency{
Symbol: price.Denom,
Decimals: 0,
}),
}
response.SuggestedFee = []*types.Amount{&suggestedFee}
}

return response, nil
}

// ConstructionParse Parse is called on both unsigned and signed transactions to understand the
Expand Down
Loading

0 comments on commit 38a1132

Please sign in to comment.