diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c34e128af19..a8e25815ed76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### Improvements +* (baseapp) [\#10631](https://github.com/cosmos/cosmos-sdk/pull/10631) Emit ante events even for the failed txs. + ## [v0.44.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.44.4) - 2021-11-25 ### Improvements diff --git a/baseapp/abci.go b/baseapp/abci.go index 3464a5d43688..b5a21f33058c 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -240,9 +240,9 @@ func (app *BaseApp) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx { panic(fmt.Sprintf("unknown RequestCheckTx type: %s", req.Type)) } - gInfo, result, err := app.runTx(mode, req.Tx) + gInfo, result, anteEvents, err := app.runTx(mode, req.Tx) if err != nil { - return sdkerrors.ResponseCheckTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) + return sdkerrors.ResponseCheckTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) } return abci.ResponseCheckTx{ @@ -272,10 +272,10 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx telemetry.SetGauge(float32(gInfo.GasWanted), "tx", "gas", "wanted") }() - gInfo, result, err := app.runTx(runTxModeDeliver, req.Tx) + gInfo, result, anteEvents, err := app.runTx(runTxModeDeliver, req.Tx) if err != nil { resultStr = "failed" - return sdkerrors.ResponseDeliverTx(err, gInfo.GasWanted, gInfo.GasUsed, app.trace) + return sdkerrors.ResponseDeliverTxWithEvents(err, gInfo.GasWanted, gInfo.GasUsed, anteEvents, app.trace) } return abci.ResponseDeliverTx{ diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index ba5ec2696e72..b36d06702990 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -572,7 +572,7 @@ func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context // Note, gas execution info is always returned. A reference to a Result is // returned if the tx does not run out of gas and if all the messages are valid // and execute successfully. An error is returned otherwise. -func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, err error) { +func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, result *sdk.Result, anteEvents []abci.Event, err error) { // NOTE: GasWanted should be returned by the AnteHandler. GasUsed is // determined by the GasMeter. We need access to the context to get the gas // meter so we initialize upfront. @@ -584,7 +584,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // only run the tx if there is block gas remaining if mode == runTxModeDeliver && ctx.BlockGasMeter().IsOutOfGas() { gInfo = sdk.GasInfo{GasUsed: ctx.BlockGasMeter().GasConsumed()} - return gInfo, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") + return gInfo, nil, nil, sdkerrors.Wrap(sdkerrors.ErrOutOfGas, "no block gas left to run tx") } var startingGas uint64 @@ -620,15 +620,14 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re tx, err := app.txDecoder(txBytes) if err != nil { - return sdk.GasInfo{}, nil, err + return sdk.GasInfo{}, nil, nil, err } msgs := tx.GetMsgs() if err := validateBasicTxMsgs(msgs); err != nil { - return sdk.GasInfo{}, nil, err + return sdk.GasInfo{}, nil, nil, err } - var events sdk.Events if app.anteHandler != nil { var ( anteCtx sdk.Context @@ -656,16 +655,17 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re ctx = newCtx.WithMultiStore(ms) } - events = ctx.EventManager().Events() + events := ctx.EventManager().Events() // GasMeter expected to be set in AnteHandler gasWanted = ctx.GasMeter().Limit() if err != nil { - return gInfo, nil, err + return gInfo, nil, nil, err } msCache.Write() + anteEvents = events.ToABCIEvents() } // Create a new Context based off of the existing Context with a MultiStore branch @@ -680,13 +680,13 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re if err == nil && mode == runTxModeDeliver { msCache.Write() - if len(events) > 0 { + if len(anteEvents) > 0 { // append the events in the order of occurrence - result.Events = append(events.ToABCIEvents(), result.Events...) + result.Events = append(anteEvents, result.Events...) } } - return gInfo, result, err + return gInfo, result, anteEvents, err } // runMsgs iterates through a list of messages and executes them with the provided diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index ff307b105ff0..df891e136936 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -1543,7 +1543,8 @@ func TestBaseAppAnteHandler(t *testing.T) { require.NoError(t, err) res = app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) - require.Empty(t, res.Events) + // should emit ante event + require.NotEmpty(t, res.Events) require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) ctx = app.getState(runTxModeDeliver).ctx diff --git a/baseapp/test_helpers.go b/baseapp/test_helpers.go index 407ebd9a7cd9..bcc2f6981fbc 100644 --- a/baseapp/test_helpers.go +++ b/baseapp/test_helpers.go @@ -15,11 +15,13 @@ func (app *BaseApp) Check(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk if err != nil { return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - return app.runTx(runTxModeCheck, bz) + gasInfo, result, _, err := app.runTx(runTxModeCheck, bz) + return gasInfo, result, err } func (app *BaseApp) Simulate(txBytes []byte) (sdk.GasInfo, *sdk.Result, error) { - return app.runTx(runTxModeSimulate, txBytes) + gasInfo, result, _, err := app.runTx(runTxModeSimulate, txBytes) + return gasInfo, result, err } func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *sdk.Result, error) { @@ -28,7 +30,8 @@ func (app *BaseApp) Deliver(txEncoder sdk.TxEncoder, tx sdk.Tx) (sdk.GasInfo, *s if err != nil { return sdk.GasInfo{}, nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "%s", err) } - return app.runTx(runTxModeDeliver, bz) + gasInfo, result, _, err := app.runTx(runTxModeDeliver, bz) + return gasInfo, result, err } // Context with current {check, deliver}State of the app used by tests. diff --git a/types/errors/abci.go b/types/errors/abci.go index df85f6bc89df..0e0abdd1db59 100644 --- a/types/errors/abci.go +++ b/types/errors/abci.go @@ -52,6 +52,20 @@ func ResponseCheckTx(err error, gw, gu uint64, debug bool) abci.ResponseCheckTx } } +// ResponseCheckTxWithEvents returns an ABCI ResponseCheckTx object with fields filled in +// from the given error, gas values and events. +func ResponseCheckTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) abci.ResponseCheckTx { + space, code, log := ABCIInfo(err, debug) + return abci.ResponseCheckTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + Events: events, + } +} + // ResponseDeliverTx returns an ABCI ResponseDeliverTx object with fields filled in // from the given error and gas values. func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDeliverTx { @@ -65,6 +79,20 @@ func ResponseDeliverTx(err error, gw, gu uint64, debug bool) abci.ResponseDelive } } +// ResponseDeliverTxWithEvents returns an ABCI ResponseDeliverTx object with fields filled in +// from the given error, gas values and events. +func ResponseDeliverTxWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) abci.ResponseDeliverTx { + space, code, log := ABCIInfo(err, debug) + return abci.ResponseDeliverTx{ + Codespace: space, + Code: code, + Log: log, + GasWanted: int64(gw), + GasUsed: int64(gu), + Events: events, + } +} + // QueryResult returns a ResponseQuery from an error. It will try to parse ABCI // info from the error. func QueryResult(err error) abci.ResponseQuery {