laconicd/types/gasmeter.go
Loredana Cirstea 77d9e29923
fix: GasMeter reset in AnteHandler EthGasConsumeDecorator (#964)
* Fix GasMeter reset in AnteHandler - EthGasConsumeDecorator

Conforming to the spec:
e7066c4271/docs/basics/gas-fees.md
> Set newCtx.GasMeter to 0, with a limit of GasWanted.
> This step is extremely important, as it not only makes sure the transaction cannot consume infinite gas,
> but also that ctx.GasMeter is reset in-between each DeliverTx
> (ctx is set to newCtx after anteHandler is run, and the anteHandler is run each time DeliverTx is called).

* Compute gasWanted in ante handler based on msg gas

* Tests - check gas meter limit after EthGasConsumeDecorator ante handler runs

* Update CHANGELOG.md

* EthGasConsumeDecorator ante handler resets the gas meter only for CheckTx

* Reset the gas meter in Keeper.EthereumTx to an infinite gas meter

* Fix TestOutOfGasWhenDeployContract error check

* Move gas meter reset to the innermost EthAnteHandle

* add NewInfiniteGasMeterWithLimit for setting the user provided gas limit

Fixes block's consumed gas calculation in the block creation phase.

* Fix lint

* Fix lint

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
2022-03-06 15:09:28 +01:00

92 lines
2.4 KiB
Go

package types
import (
fmt "fmt"
math "math"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// ErrorNegativeGasConsumed defines an error thrown when the amount of gas refunded results in a
// negative gas consumed amount.
// Copied from cosmos-sdk
type ErrorNegativeGasConsumed struct {
Descriptor string
}
// ErrorGasOverflow defines an error thrown when an action results gas consumption
// unsigned integer overflow.
type ErrorGasOverflow struct {
Descriptor string
}
type infiniteGasMeterWithLimit struct {
consumed sdk.Gas
limit sdk.Gas
}
// NewInfiniteGasMeterWithLimit returns a reference to a new infiniteGasMeter.
func NewInfiniteGasMeterWithLimit(limit sdk.Gas) sdk.GasMeter {
return &infiniteGasMeterWithLimit{
consumed: 0,
limit: limit,
}
}
func (g *infiniteGasMeterWithLimit) GasConsumed() sdk.Gas {
return g.consumed
}
func (g *infiniteGasMeterWithLimit) GasConsumedToLimit() sdk.Gas {
return g.consumed
}
func (g *infiniteGasMeterWithLimit) Limit() sdk.Gas {
return g.limit
}
// addUint64Overflow performs the addition operation on two uint64 integers and
// returns a boolean on whether or not the result overflows.
func addUint64Overflow(a, b uint64) (uint64, bool) {
if math.MaxUint64-a < b {
return 0, true
}
return a + b, false
}
func (g *infiniteGasMeterWithLimit) ConsumeGas(amount sdk.Gas, descriptor string) {
var overflow bool
// TODO: Should we set the consumed field after overflow checking?
g.consumed, overflow = addUint64Overflow(g.consumed, amount)
if overflow {
panic(ErrorGasOverflow{descriptor})
}
}
// RefundGas will deduct the given amount from the gas consumed. If the amount is greater than the
// gas consumed, the function will panic.
//
// Use case: This functionality enables refunding gas to the trasaction or block gas pools so that
// EVM-compatible chains can fully support the go-ethereum StateDb interface.
// See https://github.com/cosmos/cosmos-sdk/pull/9403 for reference.
func (g *infiniteGasMeterWithLimit) RefundGas(amount sdk.Gas, descriptor string) {
if g.consumed < amount {
panic(ErrorNegativeGasConsumed{Descriptor: descriptor})
}
g.consumed -= amount
}
func (g *infiniteGasMeterWithLimit) IsPastLimit() bool {
return false
}
func (g *infiniteGasMeterWithLimit) IsOutOfGas() bool {
return false
}
func (g *infiniteGasMeterWithLimit) String() string {
return fmt.Sprintf("InfiniteGasMeter:\n consumed: %d", g.consumed)
}