feat: add `RefundGas` function to `GasMeter` (#9403)
* feat: add RefundGas function to GasMeter * changelog * add comment about use case * Apply suggestions from code review Co-authored-by: Alessio Treglia <alessio@tendermint.com> Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com>
This commit is contained in:
parent
33c045c3c9
commit
90edeb67e2
|
@ -128,8 +128,9 @@ if input key is empty, or input data contains empty key.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
|
* (store) [\#9403](https://github.com/cosmos/cosmos-sdk/pull/9403) Add `RefundGas` function to `GasMeter` interface
|
||||||
|
* (baseapp, types) [\#9390](https://github.com/cosmos/cosmos-sdk/pull/9390) Add current block header hash to `Context`
|
||||||
* (x/staking) [\#9423](https://github.com/cosmos/cosmos-sdk/pull/9423) Staking delegations now returns empty list instead of rpc error when no records found.
|
* (x/staking) [\#9423](https://github.com/cosmos/cosmos-sdk/pull/9423) Staking delegations now returns empty list instead of rpc error when no records found.
|
||||||
* (baseapp, types) [#\9390](https://github.com/cosmos/cosmos-sdk/pull/9390) Add current block header hash to `Context`
|
|
||||||
* (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata
|
* (x/bank) [\#8614](https://github.com/cosmos/cosmos-sdk/issues/8614) Add `Name` and `Symbol` fields to denom metadata
|
||||||
* (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts
|
* (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts
|
||||||
* (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method.
|
* (crypto/types) [\#8600](https://github.com/cosmos/cosmos-sdk/pull/8600) `CompactBitArray`: optimize the `NumTrueBitsBefore` method and add an `Equal` method.
|
||||||
|
|
|
@ -20,6 +20,12 @@ const (
|
||||||
// Gas measured by the SDK
|
// Gas measured by the SDK
|
||||||
type Gas = uint64
|
type Gas = uint64
|
||||||
|
|
||||||
|
// ErrorNegativeGasConsumed defines an error thrown when the amount of gas refunded results in a
|
||||||
|
// negative gas consumed amount.
|
||||||
|
type ErrorNegativeGasConsumed struct {
|
||||||
|
Descriptor string
|
||||||
|
}
|
||||||
|
|
||||||
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
|
// ErrorOutOfGas defines an error thrown when an action results in out of gas.
|
||||||
type ErrorOutOfGas struct {
|
type ErrorOutOfGas struct {
|
||||||
Descriptor string
|
Descriptor string
|
||||||
|
@ -37,6 +43,7 @@ type GasMeter interface {
|
||||||
GasConsumedToLimit() Gas
|
GasConsumedToLimit() Gas
|
||||||
Limit() Gas
|
Limit() Gas
|
||||||
ConsumeGas(amount Gas, descriptor string)
|
ConsumeGas(amount Gas, descriptor string)
|
||||||
|
RefundGas(amount Gas, descriptor string)
|
||||||
IsPastLimit() bool
|
IsPastLimit() bool
|
||||||
IsOutOfGas() bool
|
IsOutOfGas() bool
|
||||||
String() string
|
String() string
|
||||||
|
@ -91,7 +98,20 @@ func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
if g.consumed > g.limit {
|
if g.consumed > g.limit {
|
||||||
panic(ErrorOutOfGas{descriptor})
|
panic(ErrorOutOfGas{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 transaction 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 *basicGasMeter) RefundGas(amount Gas, descriptor string) {
|
||||||
|
if g.consumed < amount {
|
||||||
|
panic(ErrorNegativeGasConsumed{Descriptor: descriptor})
|
||||||
|
}
|
||||||
|
|
||||||
|
g.consumed -= amount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *basicGasMeter) IsPastLimit() bool {
|
func (g *basicGasMeter) IsPastLimit() bool {
|
||||||
|
@ -138,6 +158,20 @@ func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 *infiniteGasMeter) RefundGas(amount Gas, descriptor string) {
|
||||||
|
if g.consumed < amount {
|
||||||
|
panic(ErrorNegativeGasConsumed{Descriptor: descriptor})
|
||||||
|
}
|
||||||
|
|
||||||
|
g.consumed -= amount
|
||||||
|
}
|
||||||
|
|
||||||
func (g *infiniteGasMeter) IsPastLimit() bool {
|
func (g *infiniteGasMeter) IsPastLimit() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,13 @@ func TestInfiniteGasMeter(t *testing.T) {
|
||||||
meter.ConsumeGas(10, "consume 10")
|
meter.ConsumeGas(10, "consume 10")
|
||||||
require.Equal(t, uint64(10), meter.GasConsumed())
|
require.Equal(t, uint64(10), meter.GasConsumed())
|
||||||
require.Equal(t, uint64(10), meter.GasConsumedToLimit())
|
require.Equal(t, uint64(10), meter.GasConsumedToLimit())
|
||||||
|
meter.RefundGas(1, "refund 1")
|
||||||
|
require.Equal(t, uint64(9), meter.GasConsumed())
|
||||||
require.False(t, meter.IsPastLimit())
|
require.False(t, meter.IsPastLimit())
|
||||||
require.False(t, meter.IsOutOfGas())
|
require.False(t, meter.IsOutOfGas())
|
||||||
meter.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64")
|
meter.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64")
|
||||||
require.Panics(t, func() { meter.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") })
|
require.Panics(t, func() { meter.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") })
|
||||||
|
require.Panics(t, func() { meter.RefundGas(meter.GasConsumed()+1, "refund greater than consumed") })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGasMeter(t *testing.T) {
|
func TestGasMeter(t *testing.T) {
|
||||||
|
@ -57,6 +60,11 @@ func TestGasMeter(t *testing.T) {
|
||||||
require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum)
|
require.Panics(t, func() { meter.ConsumeGas(1, "") }, "Exceeded but not panicked. tc #%d", tcnum)
|
||||||
require.Equal(t, meter.GasConsumedToLimit(), meter.Limit(), "Gas consumption (to limit) not match limit")
|
require.Equal(t, meter.GasConsumedToLimit(), meter.Limit(), "Gas consumption (to limit) not match limit")
|
||||||
require.Equal(t, meter.GasConsumed(), meter.Limit()+1, "Gas consumption not match limit+1")
|
require.Equal(t, meter.GasConsumed(), meter.Limit()+1, "Gas consumption not match limit+1")
|
||||||
|
|
||||||
|
require.NotPanics(t, func() { meter.RefundGas(1, "refund 1") })
|
||||||
|
require.Equal(t, meter.GasConsumed(), meter.Limit(), "Gas consumption not match limit+1")
|
||||||
|
require.Panics(t, func() { meter.RefundGas(meter.GasConsumed()+1, "refund greater than consumed") })
|
||||||
|
|
||||||
meter2 := NewGasMeter(math.MaxUint64)
|
meter2 := NewGasMeter(math.MaxUint64)
|
||||||
meter2.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64")
|
meter2.ConsumeGas(Gas(math.MaxUint64/2), "consume half max uint64")
|
||||||
require.Panics(t, func() { meter2.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") })
|
require.Panics(t, func() { meter2.ConsumeGas(Gas(math.MaxUint64/2)+2, "panic") })
|
||||||
|
|
Loading…
Reference in New Issue