Skip to content

Commit

Permalink
feat: add decorator to wrap panic messages with the transaction that …
Browse files Browse the repository at this point in the history
…caused them (#2559)

Closes: #2557

This will allow us to understand when a panic happens, which transaction
caused it.

As an example here is a mock panic:

```
mock panic
caused by transaction:
*types.MsgSend{from_address:"celestia15v4r83er48zfrm7u6uuqs3lytwxc63c34ltdgn" to_address:"celestia1t5m2f2m000twkmsgaa777rty36wd254292am6c" amount:<denom:"utia" amount:"10" > }
```

(cherry picked from commit a3d2453)
  • Loading branch information
cmwaters authored and mergify[bot] committed Sep 25, 2023
1 parent c33a188 commit 877558f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
4 changes: 3 additions & 1 deletion app/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ func NewAnteHandler(
channelKeeper *ibckeeper.Keeper,
) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
// Wraps the panic with the string format of the transaction
NewHandlePanicDecorator(),
// Set up the context with a gas meter.
// Contract: must be called first.
// Must be called before gas consumption occurs in any other decorator.
ante.NewSetUpContextDecorator(),
// Ensure the tx does not contain any extension options.
ante.NewExtensionOptionsDecorator(nil),
Expand Down
32 changes: 32 additions & 0 deletions app/ante/panic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package ante

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
)

// HandlePanicDecorator that catches panics and wraps them in the transaction that caused the panic
type HandlePanicDecorator struct{}

func NewHandlePanicDecorator() HandlePanicDecorator {
return HandlePanicDecorator{}
}

func (d HandlePanicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
defer func() {
if r := recover(); r != nil {
panic(fmt.Sprint(r, FormatTx(tx)))
}
}()

return next(ctx, tx, simulate)
}

func FormatTx(tx sdk.Tx) string {
output := "\ncaused by transaction:\n"
for _, msg := range tx.GetMsgs() {
output += fmt.Sprintf("%T{%s}\n", msg, msg)
}
return output
}
37 changes: 37 additions & 0 deletions app/ante/panic_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ante_test

import (
"fmt"
"testing"

"github.com/celestiaorg/celestia-app/app"
"github.com/celestiaorg/celestia-app/app/ante"
"github.com/celestiaorg/celestia-app/app/encoding"
"github.com/celestiaorg/celestia-app/test/util/testnode"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/stretchr/testify/require"
)

func TestPanicHandlerDecorator(t *testing.T) {
decorator := ante.NewHandlePanicDecorator()
anteHandler := sdk.ChainAnteDecorators(decorator, mockPanicDecorator{})
ctx := sdk.Context{}
encCfg := encoding.MakeConfig(app.ModuleEncodingRegisters...)
builder := encCfg.TxConfig.NewTxBuilder()
err := builder.SetMsgs(banktypes.NewMsgSend(testnode.RandomAddress().(sdk.AccAddress), testnode.RandomAddress().(sdk.AccAddress), sdk.NewCoins(sdk.NewInt64Coin(app.BondDenom, 10))))

Check failure on line 22 in app/ante/panic_test.go

View workflow job for this annotation

GitHub Actions / test / test

undefined: testnode.RandomAddress

Check failure on line 22 in app/ante/panic_test.go

View workflow job for this annotation

GitHub Actions / test / test-coverage

undefined: testnode.RandomAddress

Check failure on line 22 in app/ante/panic_test.go

View workflow job for this annotation

GitHub Actions / test / test-race

undefined: testnode.RandomAddress
require.NoError(t, err)
tx := builder.GetTx()
defer func() {
r := recover()
require.NotNil(t, r)
require.Equal(t, fmt.Sprint("mock panic", ante.FormatTx(tx)), r)
}()
_, _ = anteHandler(ctx, tx, false)
}

type mockPanicDecorator struct{}

func (d mockPanicDecorator) AnteHandle(_ sdk.Context, _ sdk.Tx, _ bool, _ sdk.AnteHandler) (newCtx sdk.Context, err error) {
panic("mock panic")
}

0 comments on commit 877558f

Please sign in to comment.