From b38ab902d643855e10723f135c27815ed8b71d26 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 Mar 2023 11:53:03 +0100 Subject: [PATCH 1/3] fix(logic): fix out of gas on goroutine --- x/logic/keeper/grpc_query_ask.go | 7 +++++++ x/logic/types/gas.go | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/x/logic/keeper/grpc_query_ask.go b/x/logic/keeper/grpc_query_ask.go index 219e3b84..ed22524f 100644 --- a/x/logic/keeper/grpc_query_ask.go +++ b/x/logic/keeper/grpc_query_ask.go @@ -33,6 +33,13 @@ func (k Keeper) Ask(ctx goctx.Context, req *types.QueryServiceAskRequest) (respo panic(r) } + if sdkCtx.GasMeter().IsOutOfGas() { + response, err = nil, sdkerrors.Wrapf( + types.LimitExceeded, "out of gas: %s (%d/%d)", + types.ModuleName, sdkCtx.GasMeter().GasConsumed(), sdkCtx.GasMeter().Limit()) + + return + } }() sdkCtx.GasMeter().ConsumeGas(sdkCtx.GasMeter().GasConsumed(), types.ModuleName) diff --git a/x/logic/types/gas.go b/x/logic/types/gas.go index cbad9384..7549393e 100644 --- a/x/logic/types/gas.go +++ b/x/logic/types/gas.go @@ -1,6 +1,7 @@ package types import ( + "runtime" "sync" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,6 +19,14 @@ type safeGasMeter struct { func (m *safeGasMeter) ConsumeGas(amount uint64, descriptor string) { m.mutex.Lock() + defer func() { + if r := recover(); r != nil { + if _, ok := r.(sdk.ErrorOutOfGas); ok { + runtime.Goexit() + } + panic(r) + } + }() defer m.mutex.Unlock() m.gasMeter.ConsumeGas(amount, descriptor) From 9e8626ec9d76896d7166cd332f4ad3b28da37561 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX Date: Fri, 17 Mar 2023 11:57:46 +0100 Subject: [PATCH 2/3] docs(logic): add explaination on GOexit --- x/logic/types/gas.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/x/logic/types/gas.go b/x/logic/types/gas.go index 7549393e..ed993e52 100644 --- a/x/logic/types/gas.go +++ b/x/logic/types/gas.go @@ -22,6 +22,12 @@ func (m *safeGasMeter) ConsumeGas(amount uint64, descriptor string) { defer func() { if r := recover(); r != nil { if _, ok := r.(sdk.ErrorOutOfGas); ok { + // Since predicate is call into a goroutine, when out of gas is throw, the main caller + // (grpc: https://github.com/okp4/okp4d/blob/main/x/logic/keeper/grpc_query_ask.go#L25-L36, or querier) + // cannot recover ErrOutOfGas. To avoid the chain panic, we need to exit without panic. + // Goexit runs all deferred calls before terminating the goroutine. Because Goexit + // is not a panic, any recover calls in those deferred functions will return nil. + // This is a temporary solution before implementing a context cancellation. runtime.Goexit() } panic(r) From 04dcf6ef416e7aa01056d6738abd827030c22169 Mon Sep 17 00:00:00 2001 From: Benjamin DENEUX <33665639+bdeneux@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:27:35 +0100 Subject: [PATCH 3/3] fix(logic): comment typo Co-authored-by: Chris --- x/logic/types/gas.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/logic/types/gas.go b/x/logic/types/gas.go index ed993e52..5952bab7 100644 --- a/x/logic/types/gas.go +++ b/x/logic/types/gas.go @@ -22,9 +22,9 @@ func (m *safeGasMeter) ConsumeGas(amount uint64, descriptor string) { defer func() { if r := recover(); r != nil { if _, ok := r.(sdk.ErrorOutOfGas); ok { - // Since predicate is call into a goroutine, when out of gas is throw, the main caller + // Since predicate is called into a goroutine, when out of gas is thrown, the main caller // (grpc: https://github.com/okp4/okp4d/blob/main/x/logic/keeper/grpc_query_ask.go#L25-L36, or querier) - // cannot recover ErrOutOfGas. To avoid the chain panic, we need to exit without panic. + // cannot recover ErrOutOfGas. To avoid the chain panicking, we need to exit without panic. // Goexit runs all deferred calls before terminating the goroutine. Because Goexit // is not a panic, any recover calls in those deferred functions will return nil. // This is a temporary solution before implementing a context cancellation.