From f36f749818e1f2d08cddbe52cc9c3a62a2b8c202 Mon Sep 17 00:00:00 2001 From: Alessio Treglia Date: Fri, 24 Aug 2018 09:48:02 +0100 Subject: [PATCH] Incorporating @ValarDragon's comments --- client/utils/utils.go | 45 +++++++++++++++++++++-------------- x/bank/client/rest/sendtx.go | 17 +++++++++++-- x/gov/client/rest/util.go | 17 +++++++++++-- x/ibc/client/rest/transfer.go | 18 +++++++++++--- x/slashing/client/rest/tx.go | 17 +++++++++++-- x/stake/client/rest/tx.go | 17 +++++++++++-- 6 files changed, 102 insertions(+), 29 deletions(-) diff --git a/client/utils/utils.go b/client/utils/utils.go index 9f06dda1d7..da49ff5e03 100644 --- a/client/utils/utils.go +++ b/client/utils/utils.go @@ -9,6 +9,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context" amino "github.com/tendermint/go-amino" + "github.com/tendermint/tendermint/libs/common" ) // DefaultGasAdjustment is applied to gas estimates to avoid tx @@ -58,7 +59,7 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return err } - txCtx, err = enrichCtxWithGasIfGasAuto(txCtx, cliCtx, cliCtx.FromAddressName, passphrase, msgs) + txCtx, err = enrichCtxWithGasIfGasAuto(txCtx, cliCtx, passphrase, msgs) if err != nil { return err } @@ -72,35 +73,43 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) return cliCtx.EnsureBroadcastTx(txBytes) } -func enrichCtxWithGasIfGasAuto(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) { +func enrichCtxWithGasIfGasAuto(txCtx authctx.TxContext, cliCtx context.CLIContext, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) { if cliCtx.Gas == 0 { - return EnrichTxContextWithGas(txCtx, cliCtx, name, passphrase, msgs) + txBytes, err := BuildAndSignTxWithZeroGas(txCtx, cliCtx.FromAddressName, passphrase, msgs) + if err != nil { + return txCtx, err + } + estimate, adjusted, err := CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, err + } + fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted) + return txCtx.WithGas(adjusted), nil } return txCtx, nil } -// EnrichTxContextWithGas simulates the execution of a transaction to -// then populate the relevant TxContext.Gas field with the estimate -// obtained by the query. -func EnrichTxContextWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) { - txCtxSimulation := txCtx.WithGas(0) - txBytes, err := txCtxSimulation.BuildAndSign(name, passphrase, msgs) - if err != nil { - return txCtx, err - } +// BuildAndSignTxWithZeroGas builds transactions with GasWanted set to 0. +func BuildAndSignTxWithZeroGas(txCtx authctx.TxContext, name, passphrase string, msgs []sdk.Msg) ([]byte, error) { + return txCtx.WithGas(0).BuildAndSign(name, passphrase, msgs) +} + +// CalculateGas simulates the execution of a transaction and returns +// both the estimate obtained by the query and the adjusted amount. +func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *amino.Codec, txBytes []byte, adjustment float64) (estimate, adjusted int64, err error) { // run a simulation (via /app/simulate query) to // estimate gas and update TxContext accordingly - rawRes, err := cliCtx.Query("/app/simulate", txBytes) + rawRes, err := queryFunc("/app/simulate", txBytes) if err != nil { - return txCtx, err + return } - estimate, err := parseQueryResponse(cliCtx.Codec, rawRes) + estimate, err = parseQueryResponse(cdc, rawRes) if err != nil { - return txCtx, err + return } - adjusted := adjustGasEstimate(estimate, cliCtx.GasAdjustment) + adjusted = adjustGasEstimate(estimate, adjustment) fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted) - return txCtx.WithGas(adjusted), nil + return } func adjustGasEstimate(estimate int64, adjustment float64) int64 { diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index d27be38b57..14bff9a49b 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -86,11 +86,12 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo } if m.Gas == 0 { - txCtx, err = utils.EnrichTxContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + newCtx, httperr, err := enrichContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, msg) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(&w, httperr, err.Error()) return } + txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) @@ -114,3 +115,15 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo w.Write(output) } } + +func enrichContextWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, password string, msg sdk.Msg) (authctx.TxContext, int, error) { + txBytes, err := utils.BuildAndSignTxWithZeroGas(txCtx, name, password, []sdk.Msg{msg}) + if err != nil { + return txCtx, http.StatusInternalServerError, err + } + _, adjusted, err := utils.CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, http.StatusUnauthorized, err + } + return txCtx.WithGas(adjusted), http.StatusOK, nil +} diff --git a/x/gov/client/rest/util.go b/x/gov/client/rest/util.go index c6b360dc80..e204028310 100644 --- a/x/gov/client/rest/util.go +++ b/x/gov/client/rest/util.go @@ -77,11 +77,12 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base } if baseReq.Gas == 0 { - txCtx, err = utils.EnrichTxContextWithGas(txCtx, cliCtx, baseReq.Name, baseReq.Password, []sdk.Msg{msg}) + newCtx, httperr, err := enrichContextWithGas(txCtx, cliCtx, baseReq.Name, baseReq.Password, msg) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(&w, httperr, err.Error()) return } + txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg}) if err != nil { @@ -115,3 +116,15 @@ func parseInt64OrReturnBadRequest(s string, w http.ResponseWriter) (n int64, ok } return n, true } + +func enrichContextWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, password string, msg sdk.Msg) (authctx.TxContext, int, error) { + txBytes, err := utils.BuildAndSignTxWithZeroGas(txCtx, name, password, []sdk.Msg{msg}) + if err != nil { + return txCtx, http.StatusInternalServerError, err + } + _, adjusted, err := utils.CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, http.StatusUnauthorized, err + } + return txCtx.WithGas(adjusted), http.StatusOK, nil +} diff --git a/x/ibc/client/rest/transfer.go b/x/ibc/client/rest/transfer.go index 8c12a4b826..cf0f24b312 100644 --- a/x/ibc/client/rest/transfer.go +++ b/x/ibc/client/rest/transfer.go @@ -77,12 +77,12 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C } if m.Gas == 0 { - txCtx, err = utils.EnrichTxContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + newCtx, httperr, err := enrichContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, msg) if err != nil { - w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(err.Error())) + utils.WriteErrorResponse(&w, httperr, err.Error()) return } + txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) @@ -106,3 +106,15 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C w.Write(output) } } + +func enrichContextWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, password string, msg sdk.Msg) (authctx.TxContext, int, error) { + txBytes, err := utils.BuildAndSignTxWithZeroGas(txCtx, name, password, []sdk.Msg{msg}) + if err != nil { + return txCtx, http.StatusInternalServerError, err + } + _, adjusted, err := utils.CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, http.StatusUnauthorized, err + } + return txCtx.WithGas(adjusted), http.StatusOK, nil +} diff --git a/x/slashing/client/rest/tx.go b/x/slashing/client/rest/tx.go index 956e7a5712..414b05cfda 100644 --- a/x/slashing/client/rest/tx.go +++ b/x/slashing/client/rest/tx.go @@ -78,11 +78,12 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI msg := slashing.NewMsgUnjail(validatorAddr) if m.Gas == 0 { - txCtx, err = utils.EnrichTxContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + newCtx, httperr, err := enrichContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, msg) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(&w, httperr, err.Error()) return } + txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) @@ -106,3 +107,15 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI w.Write(output) } } + +func enrichContextWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, password string, msg sdk.Msg) (authctx.TxContext, int, error) { + txBytes, err := utils.BuildAndSignTxWithZeroGas(txCtx, name, password, []sdk.Msg{msg}) + if err != nil { + return txCtx, http.StatusInternalServerError, err + } + _, adjusted, err := utils.CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, http.StatusUnauthorized, err + } + return txCtx.WithGas(adjusted), http.StatusOK, nil +} diff --git a/x/stake/client/rest/tx.go b/x/stake/client/rest/tx.go index e049212d8b..729f578957 100644 --- a/x/stake/client/rest/tx.go +++ b/x/stake/client/rest/tx.go @@ -276,11 +276,12 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex m.Sequence++ if m.Gas == 0 { - txCtx, err = utils.EnrichTxContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg}) + newCtx, httperr, err := enrichContextWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, msg) if err != nil { - utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error()) + utils.WriteErrorResponse(&w, httperr, err.Error()) return } + txCtx = newCtx } txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg}) @@ -315,3 +316,15 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex w.Write(output) } } + +func enrichContextWithGas(txCtx authcliCtx.TxContext, cliCtx context.CLIContext, name, password string, msg sdk.Msg) (authcliCtx.TxContext, int, error) { + txBytes, err := utils.BuildAndSignTxWithZeroGas(txCtx, name, password, []sdk.Msg{msg}) + if err != nil { + return txCtx, http.StatusInternalServerError, err + } + _, adjusted, err := utils.CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment) + if err != nil { + return txCtx, http.StatusUnauthorized, err + } + return txCtx.WithGas(adjusted), http.StatusOK, nil +}