From 96a7311cfc6ad7b4dad05e947ec1b34ba1181712 Mon Sep 17 00:00:00 2001 From: Geoff Lee Date: Thu, 11 Nov 2021 18:08:34 +0900 Subject: [PATCH] fee suggestion for construction/metadata --- server/config/config.go | 20 +++++++++++----- server/rosetta/client_online.go | 19 +++++++++++++++ server/rosetta/config.go | 22 +++++++++++++++++ .../lib/internal/service/construction.go | 19 ++++++++++++++- server/start.go | 24 +++++++++++++------ 5 files changed, 90 insertions(+), 14 deletions(-) diff --git a/server/config/config.go b/server/config/config.go index f5a395dce8e0..0a705f2f3fc0 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -125,6 +125,12 @@ type RosettaConfig struct { // Offline defines if the server must be run in offline mode Offline bool `mapstructure:"offline"` + + // SuggestGas defines gas limit when calculate fee + SuggestGas int `mapstructure:"suggest-gas"` + + // DefaultSuggestDenom defines the defult denom for fee suggestion + DefaultSuggestDenom string `mapstructure:"default-suggest-denom"` } // GRPCConfig defines configuration for the gRPC server. @@ -292,12 +298,14 @@ 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"), + SuggestGas: v.GetInt("rosetta.suggest-gas"), + DefaultSuggestDenom: v.GetString("rosetta.default-suggest-denom"), }, GRPC: GRPCConfig{ Enable: v.GetBool("grpc.enable"), diff --git a/server/rosetta/client_online.go b/server/rosetta/client_online.go index dc46e187e8cc..fdc811c3ec9d 100644 --- a/server/rosetta/client_online.go +++ b/server/rosetta/client_online.go @@ -395,6 +395,25 @@ func (c *Client) ConstructionMetadataFromOptions(ctx context.Context, options ma return nil, err } + if constructionOptions.GasLimit <= 0 { + // set to default + constructionOptions.GasLimit = uint64(c.config.SuggestGas) + } + if constructionOptions.GasPrice == "" { + // set to default + denom := c.config.DefaultSuggestDenom + constructionOptions.GasPrice = c.config.SuggestPrices.AmountOf(denom).String() + denom + } else { + 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 { diff --git a/server/rosetta/config.go b/server/rosetta/config.go index dac86e25de93..748bce7f61b3 100644 --- a/server/rosetta/config.go +++ b/server/rosetta/config.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" ) // configuration defaults constants @@ -30,6 +31,8 @@ const ( DefaultNetwork = "network" // DefaultOffline defines the default offline value DefaultOffline = false + // DefaultSuggestGas defines the default gas limit for fee suggestion + DefaultSuggestGas = 20_000 ) // configuration flags @@ -65,6 +68,12 @@ type Config struct { Retries int // Offline defines if the server must be run in offline mode Offline bool + // SuggestGas defines the gas limit for fee suggestion + SuggestGas int + // DefaultSuggestDenom defines the default denom for fee suggestion + DefaultSuggestDenom 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 @@ -102,6 +111,19 @@ func (c *Config) validate() error { if c.Offline { return fmt.Errorf("offline mode is not supported for stargate implementation due to how sigv2 works") } + if c.SuggestGas <= 0 { + c.SuggestGas = DefaultSuggestGas + } + found := false + for i := 0; i < c.SuggestPrices.Len(); i++ { + if c.SuggestPrices.GetDenomByIndex(i) == c.DefaultSuggestDenom { + 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 if c.GRPCEndpoint == "" { diff --git a/server/rosetta/lib/internal/service/construction.go b/server/rosetta/lib/internal/service/construction.go index 4be6e9461241..113fdd04b06a 100644 --- a/server/rosetta/lib/internal/service/construction.go +++ b/server/rosetta/lib/internal/service/construction.go @@ -9,6 +9,7 @@ import ( "github.com/coinbase/rosetta-sdk-go/types" "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors" + sdk "github.com/cosmos/cosmos-sdk/types" ) // ConstructionCombine Combine creates a network-specific transaction from an unsigned transaction @@ -69,8 +70,24 @@ func (on OnlineNetwork) ConstructionMetadata(ctx context.Context, request *types return nil, errors.ToRosetta(err) } + price, err := sdk.ParseDecCoin(metadata["gas_price"].(string)) + if err != nil { + return nil, errors.ToRosetta(err) + } + gas := sdk.NewIntFromUint64(uint64(metadata["gas_limit"].(float64))) + + suggestedFee := types.Amount{ + Value: price.Amount.MulInt64(gas.Int64()).String(), + Currency: &(types.Currency{ + Symbol: price.Denom, + Decimals: 0, + }), + /*metadata*/ + } + return &types.ConstructionMetadataResponse{ - Metadata: metadata, + Metadata: metadata, + SuggestedFee: []*types.Amount{&suggestedFee}, }, nil } diff --git a/server/start.go b/server/start.go index 9bd6c5ef39f9..c4822bd8950b 100644 --- a/server/start.go +++ b/server/start.go @@ -29,6 +29,7 @@ import ( crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server" "github.com/cosmos/cosmos-sdk/server/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdktypes "github.com/cosmos/cosmos-sdk/types" ) // Tendermint full-node start flags @@ -340,14 +341,23 @@ func startInProcess(ctx *Context, clientCtx client.Context, appCreator types.App offlineMode = true } + minGasPrices, err := sdktypes.ParseDecCoins(config.MinGasPrices) + if err != nil { + ctx.Logger.Error("failed to parse minimum-gas-prices: ", err) + return err + } + conf := &rosetta.Config{ - Blockchain: config.Rosetta.Blockchain, - Network: config.Rosetta.Network, - TendermintRPC: ctx.Config.RPC.ListenAddress, - GRPCEndpoint: config.GRPC.Address, - Addr: config.Rosetta.Address, - Retries: config.Rosetta.Retries, - Offline: offlineMode, + Blockchain: config.Rosetta.Blockchain, + Network: config.Rosetta.Network, + TendermintRPC: ctx.Config.RPC.ListenAddress, + GRPCEndpoint: config.GRPC.Address, + Addr: config.Rosetta.Address, + Retries: config.Rosetta.Retries, + Offline: offlineMode, + SuggestGas: config.Rosetta.SuggestGas, + DefaultSuggestDenom: config.Rosetta.DefaultSuggestDenom, + SuggestPrices: minGasPrices.Sort(), } conf.WithCodec(clientCtx.InterfaceRegistry, clientCtx.Codec.(*codec.ProtoCodec))