Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: createCachedContext #278

Merged
merged 4 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 33 additions & 15 deletions x/interchaintxs/keeper/ibc_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,46 @@ func (k *Keeper) outOfGasRecovery(

k.Logger(ctx).Debug("Out of gas", "Gas meter", gasMeter.String())
k.contractManagerKeeper.AddContractFailure(ctx, packet.SourceChannel, senderAddress.String(), packet.GetSequence(), failureAckType)
// FIXME: add distribution call
}
}

func (k *Keeper) createCachedContext(ctx sdk.Context) (cacheCtx sdk.Context, writeFn func(), newGasMeter sdk.GasMeter) {
gasLeft := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumed()
// createCachedContext creates a cached context for handling Sudo calls to CosmWasm smart-contracts.
// If there is an error during Sudo call, we can safely revert changes made in cached context.
func (k *Keeper) createCachedContext(ctx sdk.Context) (sdk.Context, func(), sdk.GasMeter) {
gasMeter := ctx.GasMeter()
// determines type of gas meter by its prefix:
// * BasicGasMeter - basic gas meter which is used for processing tx directly in block;
// * InfiniteGasMeter - is used to process txs during simulation calls. We don't need to create a limit for such meter,
// since it's infinite.
gasMeterIsLimited := strings.HasPrefix(ctx.GasMeter().String(), "BasicGasMeter")

cacheCtx, writeFn := ctx.CacheContext()

// if gas meter is limited:
// 1. calculate how much free gas left we have for a Sudo call;
// 2. If gasLeft less than reserved gas (GasReserved), we set gas limit for cached context to zero, meaning we can't
// process Sudo call;
// 3. If we have more gas left than reserved gas (GasReserved) for Sudo call, we set gas limit for cached context to
// difference between gas left and reserved gas: (gasLeft - GasReserve);
//
// GasReserve is the amount of gas on the context gas meter we need to reserve in order to add contract failure to keeper
// and process failed Sudo call
if gasMeterIsLimited {
gasLeft := gasMeter.Limit() - gasMeter.GasConsumed()

var newLimit uint64
if gasLeft < GasReserve {
newLimit = 0
} else {
newLimit = gasLeft - GasReserve
}

var newLimit uint64
if gasLeft < GasReserve {
newLimit = 0
} else {
newLimit = gasLeft - GasReserve
gasMeter = sdk.NewGasMeter(newLimit)
}

newGasMeter = sdk.NewGasMeter(newLimit)

cacheCtx, writeFn = ctx.CacheContext()
if strings.HasPrefix(ctx.GasMeter().String(), "BasicGasMeter") {
cacheCtx = ctx.WithGasMeter(newGasMeter)
}
cacheCtx = cacheCtx.WithGasMeter(gasMeter)

return
return cacheCtx, writeFn, gasMeter
}

// HandleAcknowledgement passes the acknowledgement data to the appropriate contract via a Sudo call.
Expand Down
47 changes: 33 additions & 14 deletions x/transfer/ibc_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,43 @@ func (im IBCModule) outOfGasRecovery(
}
}

func (im IBCModule) createCachedContext(ctx sdk.Context) (cacheCtx sdk.Context, writeFn func(), newGasMeter sdk.GasMeter) {
gasLeft := ctx.GasMeter().Limit() - ctx.GasMeter().GasConsumed()
// createCachedContext creates a cached context for handling Sudo calls to CosmWasm smart-contracts.
// If there is an error during Sudo call, we can safely revert changes made in cached context.
func (im *IBCModule) createCachedContext(ctx sdk.Context) (sdk.Context, func(), sdk.GasMeter) {
gasMeter := ctx.GasMeter()
// determines type of gas meter by its prefix:
// * BasicGasMeter - basic gas meter which is used for processing tx directly in block;
// * InfiniteGasMeter - is used to process txs during simulation calls. We don't need to create a limit for such meter,
// since it's infinite.
gasMeterIsLimited := strings.HasPrefix(ctx.GasMeter().String(), "BasicGasMeter")

cacheCtx, writeFn := ctx.CacheContext()

// if gas meter is limited:
// 1. calculate how much free gas left we have for a Sudo call;
// 2. If gasLeft less than reserved gas (GasReserved), we set gas limit for cached context to zero, meaning we can't
// process Sudo call;
// 3. If we have more gas left than reserved gas (GasReserved) for Sudo call, we set gas limit for cached context to
// difference between gas left and reserved gas: (gasLeft - GasReserve);
//
// GasReserve is the amount of gas on the context gas meter we need to reserve in order to add contract failure to keeper
// and process failed Sudo call
if gasMeterIsLimited {
gasLeft := gasMeter.Limit() - gasMeter.GasConsumed()

var newLimit uint64
if gasLeft < GasReserve {
newLimit = 0
} else {
newLimit = gasLeft - GasReserve
}

var newLimit uint64
if gasLeft < GasReserve {
newLimit = 0
} else {
newLimit = gasLeft - GasReserve
gasMeter = sdk.NewGasMeter(newLimit)
}

newGasMeter = sdk.NewGasMeter(newLimit)

cacheCtx, writeFn = ctx.CacheContext()
if strings.HasPrefix(ctx.GasMeter().String(), "BasicGasMeter") {
cacheCtx = ctx.WithGasMeter(newGasMeter)
}
cacheCtx = cacheCtx.WithGasMeter(gasMeter)

return
return cacheCtx, writeFn, gasMeter
}

// HandleAcknowledgement passes the acknowledgement data to the appropriate contract via a Sudo call.
Expand Down