From d5357cc435ad35d558dcf3c131523149cf4f3813 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 18 Jan 2024 16:45:14 +0100 Subject: [PATCH] feat: support fixed gas for vote and prevote transactions (#337) * feat: support fixed gas for vote and prevote transactions * update config * changelog --- CHANGELOG.md | 6 ++++++ README.md | 8 ++++++-- cmd/price-feeder.go | 3 ++- config/config.go | 19 ++++++++++++++----- oracle/client/client.go | 23 +++++++++++++++-------- oracle/oracle.go | 15 ++++++++------- price-feeder.example.toml | 7 +++++-- 7 files changed, 56 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5878d9b9..c6a554dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +## v2.4.0 + +- [337](https://github.com/ojo-network/price-feeder/pull/337) feat: support fixed gas for vote and prevote transactions. + +## Old + ### Improvements - [48](https://github.com/ojo-network/price-feeder/pull/48) Update goreleaser to have release process for umee price-feeder - [55](https://github.com/ojo-network/price-feeder/pull/55) Update DockerFile to work in umee's e2e test diff --git a/README.md b/README.md index 1019d5f1..a51c1e66 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,14 @@ Chain rules for checking the free oracle transactions are: - must be only prevote or vote - gas is limited to [`MaxMsgGasUsage`](https://github.com/ojo-network/ojo/blob/main/ante/fee.go#L13) constant. -So, if you don't want to pay for gas, TX must be below `MaxMsgGasUsage`. If you set too much gas (which is what is happening when when you set `gas_adjustment` to 2), then the tx will allocate 2x gas, and hence will go above the free quota, so you would need to attach fee to pay for that gas. +So, if you don't want to pay for gas, TX must be below `MaxMsgGasUsage`. If you set too much gas (which is what is happening when you use high `gas_adjustment`, eg more than 2), then the tx will allocate 2x gas, and hence will go above the free quota, so you would need to attach fee to pay for that gas. The easiest is to just set constant gas. We recommend 10k below the `MaxMsgGasUsage`. -Note that either `gas_adjustment` or `gas` can be used. Both can not be set. +In the PF config file you can set either: + +* `gas_adjustment` +* or `gas_prevote` and `gas_vote` - fixed amount of gas used for `MsgAggregateExchangeRatePrevote` and `MsgAggregateExchangeRateVote` transactions respectively. + ## Configuration ### `telemetry` diff --git a/cmd/price-feeder.go b/cmd/price-feeder.go index 4a1e9b9f..a522be42 100644 --- a/cmd/price-feeder.go +++ b/cmd/price-feeder.go @@ -150,7 +150,8 @@ func priceFeederCmdHandler(cmd *cobra.Command, args []string) error { cfg.Account.Validator, cfg.RPC.GRPCEndpoint, cfg.GasAdjustment, - cfg.Gas, + cfg.GasPrevote, + cfg.GasVote, ) if err != nil { return err diff --git a/config/config.go b/config/config.go index 725d539c..3431171e 100644 --- a/config/config.go +++ b/config/config.go @@ -3,6 +3,7 @@ package config import ( "errors" "fmt" + "strings" "time" "github.com/cosmos/cosmos-sdk/telemetry" @@ -47,7 +48,8 @@ type ( RPC RPC `mapstructure:"rpc" validate:"required,gt=0,dive,required"` Telemetry telemetry.Config `mapstructure:"telemetry"` GasAdjustment float64 `mapstructure:"gas_adjustment"` - Gas uint64 `mapstructure:"gas"` + GasVote uint64 `mapstructure:"gas_vote"` + GasPrevote uint64 `mapstructure:"gas_prevote"` ProviderTimeout string `mapstructure:"provider_timeout"` ProviderMinOverride bool `mapstructure:"provider_min_override"` ProviderEndpoints []provider.Endpoint `mapstructure:"provider_endpoints" validate:"dive"` @@ -169,11 +171,18 @@ func (c Config) validateDeviations() error { } func (c Config) validateGas() error { - if c.Gas <= 0 && c.GasAdjustment <= 0 { - return fmt.Errorf("gas or gas adjustment must be set") + var errs []string + if (c.GasPrevote > 0) != (c.GasVote > 0) { + errs = append(errs, "if gas_prevote is set, then gas_vote must be set as well; similarly, if gas_vote is set, then gas_prevote must be set as well") } - if c.GasAdjustment > 0 && c.Gas > 0 { - return fmt.Errorf("gas and gas adjustment may not both be set") + if c.GasVote <= 0 && c.GasAdjustment <= 0 { + errs = append(errs, "either gas_vote and gas_prevote must be set or gas_adjustment must be set") + } + if c.GasAdjustment > 0 && c.GasVote > 0 { + errs = append(errs, "gas and gas adjustment may not both be set") + } + if len(errs) > 0 { + return errors.New(strings.Join(errs, ". ")) } return nil } diff --git a/oracle/client/client.go b/oracle/client/client.go index cfcba9e8..4240691d 100644 --- a/oracle/client/client.go +++ b/oracle/client/client.go @@ -43,7 +43,8 @@ type ( Encoding testutil.TestEncodingConfig GasPrices string GasAdjustment float64 - Gas uint64 + GasPrevote uint64 + GasVote uint64 GRPCEndpoint string KeyringPassphrase string ChainHeight *ChainHeight @@ -68,7 +69,8 @@ func NewOracleClient( validatorAddrString string, grpcEndpoint string, gasAdjustment float64, - gas uint64, + gasPrevote uint64, + gasVote uint64, ) (OracleClient, error) { oracleAddr, err := sdk.AccAddressFromBech32(oracleAddrString) if err != nil { @@ -89,7 +91,8 @@ func NewOracleClient( ValidatorAddrString: validatorAddrString, Encoding: umeeapp.MakeEncodingConfig(), GasAdjustment: gasAdjustment, - Gas: gas, + GasPrevote: gasPrevote, + GasVote: gasVote, GRPCEndpoint: grpcEndpoint, } @@ -138,7 +141,7 @@ func (r *passReader) Read(p []byte) (n int, err error) { // BroadcastTx attempts to broadcast a signed transaction. If it fails, a few re-attempts // will be made until the transaction succeeds or ultimately times out or fails. // Ref: https://github.com/terra-money/oracle-feeder/blob/baef2a4a02f57a2ffeaa207932b2e03d7fb0fb25/feeder/src/vote.ts#L230 -func (oc OracleClient) BroadcastTx(nextBlockHeight, timeoutHeight int64, msgs ...sdk.Msg) error { +func (oc OracleClient) BroadcastTx(nextBlockHeight, timeoutHeight int64, isPrevote bool, msgs sdk.Msg) error { maxBlockHeight := nextBlockHeight + timeoutHeight lastCheckHeight := nextBlockHeight - 1 @@ -147,7 +150,7 @@ func (oc OracleClient) BroadcastTx(nextBlockHeight, timeoutHeight int64, msgs .. return err } - factory, err := oc.CreateTxFactory() + factory, err := oc.CreateTxFactory(isPrevote) if err != nil { return err } @@ -166,7 +169,7 @@ func (oc OracleClient) BroadcastTx(nextBlockHeight, timeoutHeight int64, msgs .. // set last check height to latest block height lastCheckHeight = latestBlockHeight - resp, err := BroadcastTx(clientCtx, factory, msgs...) + resp, err := BroadcastTx(clientCtx, factory, msgs) if resp != nil && resp.Code != 0 { telemetry.IncrCounter(1, "failure", "tx", "code") err = fmt.Errorf("invalid response code from tx: %d", resp.Code) @@ -266,7 +269,7 @@ func (oc OracleClient) CreateClientContext() (client.Context, error) { // CreateTxFactory creates an SDK Factory instance used for transaction // generation, signing and broadcasting. -func (oc OracleClient) CreateTxFactory() (tx.Factory, error) { +func (oc OracleClient) CreateTxFactory(isPrevote bool) (tx.Factory, error) { clientCtx, err := oc.CreateClientContext() if err != nil { return tx.Factory{}, err @@ -283,11 +286,15 @@ func (oc OracleClient) CreateTxFactory() (tx.Factory, error) { WithSignMode(signing.SignMode_SIGN_MODE_DIRECT). WithSimulateAndExecute(true), nil } + gas := oc.GasVote + if isPrevote { + gas = oc.GasVote + } return tx.Factory{}. WithAccountRetriever(clientCtx.AccountRetriever). WithChainID(oc.ChainID). WithTxConfig(clientCtx.TxConfig). - WithGas(oc.Gas). + WithGas(gas). WithGasPrices(oc.GasPrices). WithKeybase(clientCtx.Keyring). WithSignMode(signing.SignMode_SIGN_MODE_DIRECT). diff --git a/oracle/oracle.go b/oracle/oracle.go index 9ccfc439..367646b7 100644 --- a/oracle/oracle.go +++ b/oracle/oracle.go @@ -557,24 +557,24 @@ func (o *Oracle) tick(ctx context.Context) error { exchangeRatesStr := GenerateExchangeRatesString(o.prices) hash := oracletypes.GetAggregateVoteHash(salt, exchangeRatesStr, valAddr) - preVoteMsg := &oracletypes.MsgAggregateExchangeRatePrevote{ - Hash: hash.String(), // hash of prices from the oracle - Feeder: o.oracleClient.OracleAddrString, - Validator: valAddr.String(), - } - isPrevoteOnlyTx := o.previousPrevote == nil + if isPrevoteOnlyTx { // This timeout could be as small as oracleVotePeriod-indexInVotePeriod, // but we give it some extra time just in case. // // Ref : https://github.com/terra-money/oracle-feeder/blob/baef2a4a02f57a2ffeaa207932b2e03d7fb0fb25/feeder/src/vote.ts#L222 + preVoteMsg := &oracletypes.MsgAggregateExchangeRatePrevote{ + Hash: hash.String(), // hash of prices from the oracle + Feeder: o.oracleClient.OracleAddrString, + Validator: valAddr.String(), + } o.logger.Info(). Str("hash", hash.String()). Str("validator", preVoteMsg.Validator). Str("feeder", preVoteMsg.Feeder). Msg("broadcasting pre-vote") - if err := o.oracleClient.BroadcastTx(nextBlockHeight, oracleVotePeriod*2, preVoteMsg); err != nil { + if err := o.oracleClient.BroadcastTx(nextBlockHeight, oracleVotePeriod*2, isPrevoteOnlyTx, preVoteMsg); err != nil { return err } @@ -606,6 +606,7 @@ func (o *Oracle) tick(ctx context.Context) error { if err := o.oracleClient.BroadcastTx( nextBlockHeight, oracleVotePeriod-indexInVotePeriod, + isPrevoteOnlyTx, voteMsg, ); err != nil { return err diff --git a/price-feeder.example.toml b/price-feeder.example.toml index 7ac9f089..e2af4584 100644 --- a/price-feeder.example.toml +++ b/price-feeder.example.toml @@ -1,8 +1,11 @@ config_dir = "umee-provider-config" - -gas_adjustment = 1.9 provider_timeout = "1000000s" +gas_prevote = 55000 +gas_vote = 160000 +# instead of fixed gas settings, gas adjustment can be used: +# gas_adjustment = 1.9 + [server] listen_addr = "0.0.0.0:7171" read_timeout = "20s"