From 27d245713a4fde27514a0a8e0fe78d42a0a8f09f Mon Sep 17 00:00:00 2001 From: Aayush Date: Tue, 3 Mar 2026 10:36:38 -0500 Subject: [PATCH 1/2] fix(giga): add panic recovery --- app/app.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 81c07edf83..320d5b5153 100644 --- a/app/app.go +++ b/app/app.go @@ -1424,8 +1424,23 @@ func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTx continue } - // Execute EVM transaction through giga executor - result, execErr := app.executeEVMTxWithGigaExecutor(ctx, evmMsg, cache) + // Execute EVM transaction through giga executor with panic recovery + // (matches V2's recover behavior in legacyabci/deliver_tx.go) + var result *abci.ExecTxResult + var execErr error + func() { + defer func() { + if r := recover(); r != nil { + ctx.Logger().Error("panic in giga synchronous executor", "panic", r, "stack", string(debug.Stack())) + result = &abci.ExecTxResult{ + Code: sdkerrors.ErrPanic.ABCICode(), + Log: fmt.Sprintf("panic recovered: %v", r), + } + } + }() + result, execErr = app.executeEVMTxWithGigaExecutor(ctx, evmMsg, cache) + }() + if execErr != nil { // Check if this is a fail-fast error (Cosmos precompile interop detected) if gigautils.ShouldExecutionAbort(execErr) { From bbb938eb4db1efd5e15d510b868e6c767213b8d0 Mon Sep 17 00:00:00 2001 From: Aayush Date: Tue, 3 Mar 2026 10:45:40 -0500 Subject: [PATCH 2/2] fix(giga): OCC returns panics as error --- app/app.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/app/app.go b/app/app.go index 320d5b5153..60b8b617ff 100644 --- a/app/app.go +++ b/app/app.go @@ -1431,7 +1431,7 @@ func (app *App) ProcessTxsSynchronousGiga(ctx sdk.Context, txs [][]byte, typedTx func() { defer func() { if r := recover(); r != nil { - ctx.Logger().Error("panic in giga synchronous executor", "panic", r, "stack", string(debug.Stack())) + logger.Error("panic in giga synchronous executor", "panic", r, "stack", string(debug.Stack())) result = &abci.ExecTxResult{ Code: sdkerrors.ErrPanic.ABCICode(), Log: fmt.Sprintf("panic recovered: %v", r), @@ -1965,13 +1965,29 @@ func (app *App) executeEVMTxWithGigaExecutor(ctx sdk.Context, msg *evmtypes.MsgE // makeGigaDeliverTx returns an OCC-compatible deliverTx callback that captures the given // block cache, avoiding mutable state on App for cache lifecycle management. func (app *App) makeGigaDeliverTx(cache *gigaBlockCache) func(sdk.Context, abci.RequestDeliverTxV2, sdk.Tx, [32]byte) abci.ResponseDeliverTx { - return func(ctx sdk.Context, req abci.RequestDeliverTxV2, tx sdk.Tx, checksum [32]byte) abci.ResponseDeliverTx { + return func(ctx sdk.Context, req abci.RequestDeliverTxV2, tx sdk.Tx, checksum [32]byte) (resp abci.ResponseDeliverTx) { defer func() { if r := recover(); r != nil { - // OCC abort panics are expected - the scheduler uses them to detect conflicts - // and reschedule transactions. Don't log these as errors. - if _, isOCCAbort := r.(occ.Abort); !isOCCAbort { - logger.Error("benchmark panic in gigaDeliverTx", "panic", r, "stack", string(debug.Stack())) + // Handle panics as v2 does: ErrOCCAbort, ErrOutOfGas, or ErrPanic + if abort, isOCCAbort := r.(occ.Abort); isOCCAbort { + resp = abci.ResponseDeliverTx{ + Code: sdkerrors.ErrOCCAbort.ABCICode(), + Log: fmt.Sprintf("occ abort occurred with dependent index %d and error: %v", abort.DependentTxIdx, abort.Err), + } + return + } + if oogErr, isOOG := r.(sdk.ErrorOutOfGas); isOOG { + resp = abci.ResponseDeliverTx{ + Code: sdkerrors.ErrOutOfGas.ABCICode(), + Log: fmt.Sprintf("out of gas in location: %v", oogErr.Descriptor), + } + return + } + // For other panics (e.g., nil deref from malformed protobuf), log and return ErrPanic + logger.Error("panic in gigaDeliverTx", "panic", r, "stack", string(debug.Stack())) + resp = abci.ResponseDeliverTx{ + Code: sdkerrors.ErrPanic.ABCICode(), + Log: fmt.Sprintf("recovered: %v\nstack:\n%v", r, string(debug.Stack())), } } }()