Merge PR #5839: baseapp: add sdk.Result to simulation response
This commit is contained in:
commit
2828f1cadc
|
@ -70,6 +70,8 @@ to now accept a `codec.JSONMarshaler` for modular serialization of genesis state
|
|||
* (crypto/keys) [\#5735](https://github.com/cosmos/cosmos-sdk/pull/5735) Keyring's Update() function is now no-op.
|
||||
* (types/rest) [\#5779](https://github.com/cosmos/cosmos-sdk/pull/5779) Drop unused Parse{Int64OrReturnBadRequest,QueryParamBool}() functions.
|
||||
* (keys) [\#5820](https://github.com/cosmos/cosmos-sdk/pull/5820/) Removed method CloseDB from Keybase interface.
|
||||
* (baseapp) [\#5837](https://github.com/cosmos/cosmos-sdk/issues/5837) Transaction simulation now returns a `SimulationResponse` which contains the `GasInfo` and
|
||||
`Result` from the execution.
|
||||
|
||||
### Features
|
||||
|
||||
|
|
|
@ -326,12 +326,20 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res
|
|||
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to decode tx"))
|
||||
}
|
||||
|
||||
gInfo, _, _ := app.Simulate(txBytes, tx)
|
||||
gInfo, res, err := app.Simulate(txBytes, tx)
|
||||
if err != nil {
|
||||
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
|
||||
}
|
||||
|
||||
simRes := sdk.SimulationResponse{
|
||||
GasInfo: gInfo,
|
||||
Result: res,
|
||||
}
|
||||
|
||||
return abci.ResponseQuery{
|
||||
Codespace: sdkerrors.RootCodespace,
|
||||
Height: req.Height,
|
||||
Value: codec.Cdc.MustMarshalBinaryBare(gInfo.GasUsed),
|
||||
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
|
||||
}
|
||||
|
||||
case "version":
|
||||
|
|
|
@ -935,10 +935,13 @@ func TestSimulateTx(t *testing.T) {
|
|||
queryResult := app.Query(query)
|
||||
require.True(t, queryResult.IsOK(), queryResult.Log)
|
||||
|
||||
var res uint64
|
||||
err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &res)
|
||||
var simRes sdk.SimulationResponse
|
||||
err = codec.Cdc.UnmarshalBinaryBare(queryResult.Value, &simRes)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, gasConsumed, res)
|
||||
require.Equal(t, gInfo, simRes.GasInfo)
|
||||
require.Equal(t, result.Log, simRes.Result.Log)
|
||||
require.Equal(t, result.Events, simRes.Result.Events)
|
||||
require.True(t, bytes.Equal(result.Data, simRes.Result.Data))
|
||||
app.EndBlock(abci.RequestEndBlock{})
|
||||
app.Commit()
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ type GasInfo struct {
|
|||
// GasWanted is the maximum units of work we allow this tx to perform.
|
||||
GasWanted uint64
|
||||
|
||||
// GasUsed is the amount of gas actually consumed. NOTE: unimplemented
|
||||
// GasUsed is the amount of gas actually consumed.
|
||||
GasUsed uint64
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,13 @@ type Result struct {
|
|||
Events Events
|
||||
}
|
||||
|
||||
// SimulationResponse defines the response generated when a transaction is successfully
|
||||
// simulated by the Baseapp.
|
||||
type SimulationResponse struct {
|
||||
GasInfo
|
||||
Result *Result
|
||||
}
|
||||
|
||||
// ABCIMessageLogs represents a slice of ABCIMessageLog.
|
||||
type ABCIMessageLogs []ABCIMessageLog
|
||||
|
||||
|
|
|
@ -129,26 +129,26 @@ func EnrichWithGas(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs [
|
|||
}
|
||||
|
||||
// CalculateGas simulates the execution of a transaction and returns
|
||||
// both the estimate obtained by the query and the adjusted amount.
|
||||
// the simulation response obtained by the query and the adjusted gas amount.
|
||||
func CalculateGas(
|
||||
queryFunc func(string, []byte) ([]byte, int64, error), cdc *codec.Codec,
|
||||
txBytes []byte, adjustment float64,
|
||||
) (estimate, adjusted uint64, err error) {
|
||||
) (sdk.SimulationResponse, uint64, error) {
|
||||
|
||||
// run a simulation (via /app/simulate query) to
|
||||
// estimate gas and update TxBuilder accordingly
|
||||
rawRes, _, err := queryFunc("/app/simulate", txBytes)
|
||||
if err != nil {
|
||||
return estimate, adjusted, err
|
||||
return sdk.SimulationResponse{}, 0, err
|
||||
}
|
||||
|
||||
estimate, err = parseQueryResponse(cdc, rawRes)
|
||||
simRes, err := parseQueryResponse(cdc, rawRes)
|
||||
if err != nil {
|
||||
return
|
||||
return sdk.SimulationResponse{}, 0, err
|
||||
}
|
||||
|
||||
adjusted = adjustGasEstimate(estimate, adjustment)
|
||||
return estimate, adjusted, nil
|
||||
adjusted := adjustGasEstimate(simRes.GasUsed, adjustment)
|
||||
return simRes, adjusted, nil
|
||||
}
|
||||
|
||||
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
|
||||
|
@ -271,29 +271,28 @@ func GetTxEncoder(cdc *codec.Codec) (encoder sdk.TxEncoder) {
|
|||
return encoder
|
||||
}
|
||||
|
||||
// nolint
|
||||
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
|
||||
func simulateMsgs(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (estimated, adjusted uint64, err error) {
|
||||
// simulateMsgs simulates the transaction and returns the simulation response and
|
||||
// the adjusted gas value.
|
||||
func simulateMsgs(txBldr authtypes.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (sdk.SimulationResponse, uint64, error) {
|
||||
txBytes, err := txBldr.BuildTxForSim(msgs)
|
||||
if err != nil {
|
||||
return
|
||||
return sdk.SimulationResponse{}, 0, err
|
||||
}
|
||||
|
||||
estimated, adjusted, err = CalculateGas(cliCtx.QueryWithData, cliCtx.Codec, txBytes, txBldr.GasAdjustment())
|
||||
return
|
||||
return CalculateGas(cliCtx.QueryWithData, cliCtx.Codec, txBytes, txBldr.GasAdjustment())
|
||||
}
|
||||
|
||||
func adjustGasEstimate(estimate uint64, adjustment float64) uint64 {
|
||||
return uint64(adjustment * float64(estimate))
|
||||
}
|
||||
|
||||
func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (uint64, error) {
|
||||
var gasUsed uint64
|
||||
if err := cdc.UnmarshalBinaryBare(rawRes, &gasUsed); err != nil {
|
||||
return 0, err
|
||||
func parseQueryResponse(cdc *codec.Codec, rawRes []byte) (sdk.SimulationResponse, error) {
|
||||
var simRes sdk.SimulationResponse
|
||||
if err := cdc.UnmarshalBinaryBare(rawRes, &simRes); err != nil {
|
||||
return sdk.SimulationResponse{}, err
|
||||
}
|
||||
|
||||
return gasUsed, nil
|
||||
return simRes, nil
|
||||
}
|
||||
|
||||
// PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx.
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
@ -23,13 +23,19 @@ var (
|
|||
|
||||
func TestParseQueryResponse(t *testing.T) {
|
||||
cdc := makeCodec()
|
||||
sdkResBytes := cdc.MustMarshalBinaryBare(uint64(10))
|
||||
gas, err := parseQueryResponse(cdc, sdkResBytes)
|
||||
assert.Equal(t, gas, uint64(10))
|
||||
assert.Nil(t, err)
|
||||
gas, err = parseQueryResponse(cdc, []byte("fuzzy"))
|
||||
assert.Equal(t, gas, uint64(0))
|
||||
assert.Error(t, err)
|
||||
simRes := sdk.SimulationResponse{
|
||||
GasInfo: sdk.GasInfo{GasUsed: 10, GasWanted: 20},
|
||||
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
|
||||
}
|
||||
|
||||
bz := cdc.MustMarshalBinaryBare(simRes)
|
||||
res, err := parseQueryResponse(cdc, bz)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, int(res.GasInfo.GasUsed))
|
||||
require.NotNil(t, res.Result)
|
||||
|
||||
res, err = parseQueryResponse(cdc, []byte("fuzzy"))
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestCalculateGas(t *testing.T) {
|
||||
|
@ -37,9 +43,14 @@ func TestCalculateGas(t *testing.T) {
|
|||
makeQueryFunc := func(gasUsed uint64, wantErr bool) func(string, []byte) ([]byte, int64, error) {
|
||||
return func(string, []byte) ([]byte, int64, error) {
|
||||
if wantErr {
|
||||
return nil, 0, errors.New("")
|
||||
return nil, 0, errors.New("query failed")
|
||||
}
|
||||
return cdc.MustMarshalBinaryBare(gasUsed), 0, nil
|
||||
simRes := sdk.SimulationResponse{
|
||||
GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed},
|
||||
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
|
||||
}
|
||||
|
||||
return cdc.MustMarshalBinaryBare(simRes), 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,20 +65,26 @@ func TestCalculateGas(t *testing.T) {
|
|||
args args
|
||||
wantEstimate uint64
|
||||
wantAdjusted uint64
|
||||
wantErr bool
|
||||
expPass bool
|
||||
}{
|
||||
{"error", args{0, true, 1.2}, 0, 0, true},
|
||||
{"adjusted gas", args{10, false, 1.2}, 10, 12, false},
|
||||
{"error", args{0, true, 1.2}, 0, 0, false},
|
||||
{"adjusted gas", args{10, false, 1.2}, 10, 12, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
queryFunc := makeQueryFunc(tt.args.queryFuncGasUsed, tt.args.queryFuncWantErr)
|
||||
gotEstimate, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment)
|
||||
assert.Equal(t, err != nil, tt.wantErr)
|
||||
assert.Equal(t, gotEstimate, tt.wantEstimate)
|
||||
assert.Equal(t, gotAdjusted, tt.wantAdjusted)
|
||||
simRes, gotAdjusted, err := CalculateGas(queryFunc, cdc, []byte(""), tt.args.adjustment)
|
||||
if tt.expPass {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, simRes.GasInfo.GasUsed, tt.wantEstimate)
|
||||
require.Equal(t, gotAdjusted, tt.wantAdjusted)
|
||||
require.NotNil(t, simRes.Result)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
require.Nil(t, simRes.Result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue