Skip to content

Commit

Permalink
Merge PR #6618: backport 0.39.0 (launchpad): cherry pick #5839
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Jul 6, 2020
1 parent ca08830 commit a15ca8e
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 41 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ pruning setting `syncable` used `KeepEvery:100`.
0.38.5, as doing so may cause data loss and data corruption.
* Otherwise, consider syncing the node from scratch with 0.38.5.

### API Breaking Changes

* (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.

### Improvements

* (deps) Bump Tendermint version to [v0.33.5](https://github.com/tendermint/tendermint/releases/tag/v0.33.5)
Expand Down
12 changes: 10 additions & 2 deletions baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.MustMarshalBinaryLengthPrefixed(gInfo.GasUsed),
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}

case "version":
Expand Down
9 changes: 6 additions & 3 deletions baseapp/baseapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -958,10 +958,13 @@ func TestSimulateTx(t *testing.T) {
queryResult := app.Query(query)
require.True(t, queryResult.IsOK(), queryResult.Log)

var res uint64
err = codec.Cdc.UnmarshalBinaryLengthPrefixed(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()
}
Expand Down
9 changes: 8 additions & 1 deletion types/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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

Expand Down
35 changes: 17 additions & 18 deletions x/auth/client/utils/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,26 +120,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.
Expand Down Expand Up @@ -261,29 +261,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.UnmarshalBinaryLengthPrefixed(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.
Expand Down
51 changes: 34 additions & 17 deletions x/auth/client/utils/tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -23,23 +23,34 @@ var (

func TestParseQueryResponse(t *testing.T) {
cdc := makeCodec()
sdkResBytes := cdc.MustMarshalBinaryLengthPrefixed(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) {
cdc := makeCodec()
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")
}
simRes := sdk.SimulationResponse{
GasInfo: sdk.GasInfo{GasUsed: gasUsed, GasWanted: gasUsed},
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
}
return cdc.MustMarshalBinaryLengthPrefixed(gasUsed), 0, nil

return cdc.MustMarshalBinaryBare(simRes), 0, nil
}
}

Expand All @@ -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)
}
})
}
}
Expand Down

0 comments on commit a15ca8e

Please sign in to comment.