Skip to content
This repository has been archived by the owner on Jun 9, 2024. It is now read-only.

Commit

Permalink
chore(precompile): Protect precompile panics from halting chain (#1303)
Browse files Browse the repository at this point in the history
## Summary by CodeRabbit

- **Refactor**
	- Enhanced error recovery mechanism for better stability and reliability.
	- Improved error logging for easier troubleshooting and issue resolution.
  • Loading branch information
calbera committed Nov 9, 2023
1 parent 433f761 commit 98379d0
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 12 deletions.
2 changes: 1 addition & 1 deletion cosmos/x/evm/plugins/precompile/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func (p *plugin) Run(
defer p.enableReentrancy(sdb)

// recover from any WriteProtection or OutOfGas panic for the EVM to handle as a vm error
defer RecoveryHandler(&err)
defer RecoveryHandler(ctx, &err)

// use a precompile-specific gas meter for dynamic consumption
gm := storetypes.NewGasMeter(suppliedGas)
Expand Down
10 changes: 4 additions & 6 deletions cosmos/x/evm/plugins/precompile/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,10 @@ var _ = Describe("plugin", func() {
})

It("should catch panics and propagate", func() {
Expect(func() {
_, _, _ = p.Run(e, &mockPanicking{
err: errors.New("error"),
}, []byte{}, addr, new(big.Int), 30, false)
},
).To(Panic())
_, _, vmErr := p.Run(e, &mockPanicking{
err: errors.New("error"),
}, []byte{}, addr, new(big.Int), 30, false)
Expect(errors.Is(vmErr, vm.ErrExecutionReverted)).To(BeTrue())
})
})

Expand Down
17 changes: 12 additions & 5 deletions cosmos/x/evm/plugins/precompile/recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,29 +27,36 @@ import (

"github.com/berachain/polaris/eth/core/vm"
"github.com/berachain/polaris/lib/utils"

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

// RecoveryHandler is used to recover from any WriteProtection and gas consumption panics that
// occur during precompile execution; the handler modifies the given error to be returned to the
// caller. Any other type of panic is propogated up to the caller via panic.
func RecoveryHandler(err *error) {
func RecoveryHandler(ctx sdk.Context, vmErr *error) {
if panicked := recover(); panicked != nil {
// NOTE: this only propagates an error back to the EVM if the type of the given panic
// is ErrWriteProtection, Cosmos ErrorOutOfGas, Cosmos ErrorGasOverflow, or Cosmos
// ErrorNegativeGasConsumed.
switch {
case utils.Implements[error](panicked) &&
errors.Is(utils.MustGetAs[error](panicked), vm.ErrWriteProtection):
*err = vm.ErrWriteProtection
*vmErr = vm.ErrWriteProtection
case utils.Implements[storetypes.ErrorGasOverflow](panicked):
fallthrough
case utils.Implements[storetypes.ErrorOutOfGas](panicked):
fallthrough
case utils.Implements[storetypes.ErrorNegativeGasConsumed](panicked):
*err = vm.ErrOutOfGas
*vmErr = vm.ErrOutOfGas
case utils.Implements[error](panicked):
// any other type of panic value is returned as a vm error: execution reverted
// NOTE: precompile txs which panic will be included in the block as failed txs
ctx.Logger().Error("panic recovered in precompile execution", "err", panicked)
*vmErr = errors.Join(vm.ErrExecutionReverted, utils.MustGetAs[error](panicked))
default:
// any other type of panic value is ignored and passed up the call stack
panic(panicked)
ctx.Logger().Error("panic recovered in precompile execution", "panic", panicked)
*vmErr = vm.ErrExecutionReverted
}
}
}

0 comments on commit 98379d0

Please sign in to comment.