Skip to content

Commit

Permalink
Merge pull request #278 from neutron-org/fix/chached-context
Browse files Browse the repository at this point in the history
Fix: createCachedContext
  • Loading branch information
pr0n00gler authored Jul 3, 2023
2 parents 00c3bf0 + fbe35d0 commit 1c70133
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 29 deletions.
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

0 comments on commit 1c70133

Please sign in to comment.