cosmos-sdk/store/types/gas.go

223 lines
5.3 KiB
Go
Raw Normal View History

2018-05-07 10:48:12 -07:00
package types
import (
"fmt"
"math"
)
2019-02-01 17:03:09 -08:00
// Gas consumption descriptors.
const (
GasIterNextCostFlatDesc = "IterNextFlat"
GasValuePerByteDesc = "ValuePerByte"
GasWritePerByteDesc = "WritePerByte"
GasReadPerByteDesc = "ReadPerByte"
GasWriteCostFlatDesc = "WriteFlat"
GasReadCostFlatDesc = "ReadFlat"
GasHasDesc = "Has"
GasDeleteDesc = "Delete"
)
2018-05-07 12:49:11 -07:00
// Gas measured by the SDK
type Gas = uint64
2018-05-07 10:48:12 -07:00
// 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.
2018-05-08 08:34:09 -07:00
type ErrorOutOfGas struct {
Descriptor string
}
// ErrorGasOverflow defines an error thrown when an action results gas consumption
// unsigned integer overflow.
type ErrorGasOverflow struct {
Descriptor string
}
2018-05-07 12:49:11 -07:00
// GasMeter interface to track gas consumption
2018-05-07 10:48:12 -07:00
type GasMeter interface {
GasConsumed() Gas
GasConsumedToLimit() Gas
Limit() Gas
2018-05-08 08:34:09 -07:00
ConsumeGas(amount Gas, descriptor string)
RefundGas(amount Gas, descriptor string)
IsPastLimit() bool
IsOutOfGas() bool
String() string
2018-05-07 10:48:12 -07:00
}
type basicGasMeter struct {
limit Gas
consumed Gas
}
// NewGasMeter returns a reference to a new basicGasMeter.
2018-05-07 10:48:12 -07:00
func NewGasMeter(limit Gas) GasMeter {
return &basicGasMeter{
limit: limit,
consumed: 0,
}
}
func (g *basicGasMeter) GasConsumed() Gas {
return g.consumed
}
func (g *basicGasMeter) Limit() Gas {
return g.limit
}
func (g *basicGasMeter) GasConsumedToLimit() Gas {
if g.IsPastLimit() {
return g.limit
}
2018-11-20 23:02:15 -08:00
return g.consumed
}
2019-02-01 17:03:09 -08:00
// 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
}
2018-05-08 08:34:09 -07:00
func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
var overflow bool
2019-02-01 17:03:09 -08:00
g.consumed, overflow = addUint64Overflow(g.consumed, amount)
if overflow {
fix: use full gas on overflow (backport #10897) (#10912) * fix: use full gas on overflow (#10897) ## Description Investigating missing gas consumption --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) (cherry picked from commit b0d3ef96506054b66bc1160d48f4b24105e7d35a) # Conflicts: # x/auth/middleware/fee.go # x/auth/middleware/middleware.go * Update CHANGELOG.md * conflict fix Co-authored-by: Robert Zaremba <robert@zaremba.ch>
2022-01-07 10:55:26 -08:00
g.consumed = math.MaxUint64
panic(ErrorGasOverflow{descriptor})
}
2018-05-08 08:34:09 -07:00
if g.consumed > g.limit {
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})
}
2019-02-01 17:03:09 -08:00
g.consumed -= amount
2018-05-07 10:48:12 -07:00
}
2018-05-15 17:31:52 -07:00
func (g *basicGasMeter) IsPastLimit() bool {
2018-11-13 08:30:06 -08:00
return g.consumed > g.limit
}
func (g *basicGasMeter) IsOutOfGas() bool {
return g.consumed >= g.limit
}
func (g *basicGasMeter) String() string {
return fmt.Sprintf("BasicGasMeter:\n limit: %d\n consumed: %d", g.limit, g.consumed)
}
2018-05-15 17:31:52 -07:00
type infiniteGasMeter struct {
consumed Gas
}
// NewInfiniteGasMeter returns a reference to a new infiniteGasMeter.
2018-05-15 17:31:52 -07:00
func NewInfiniteGasMeter() GasMeter {
return &infiniteGasMeter{
consumed: 0,
}
}
func (g *infiniteGasMeter) GasConsumed() Gas {
return g.consumed
}
func (g *infiniteGasMeter) GasConsumedToLimit() Gas {
return g.consumed
}
func (g *infiniteGasMeter) Limit() Gas {
return 0
}
2018-05-15 17:31:52 -07:00
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
var overflow bool
// TODO: Should we set the consumed field after overflow checking?
2019-02-01 17:03:09 -08:00
g.consumed, overflow = addUint64Overflow(g.consumed, amount)
if overflow {
panic(ErrorGasOverflow{descriptor})
}
2018-05-15 17:31:52 -07:00
}
2018-07-26 18:24:18 -07:00
// 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 {
return false
}
func (g *infiniteGasMeter) IsOutOfGas() bool {
2018-11-13 08:30:06 -08:00
return false
}
func (g *infiniteGasMeter) String() string {
return fmt.Sprintf("InfiniteGasMeter:\n consumed: %d", g.consumed)
}
2018-07-26 18:24:18 -07:00
// GasConfig defines gas cost for each operation on KVStores
type GasConfig struct {
HasCost Gas
DeleteCost Gas
2018-07-26 18:24:18 -07:00
ReadCostFlat Gas
ReadCostPerByte Gas
WriteCostFlat Gas
WriteCostPerByte Gas
IterNextCostFlat Gas
2018-07-26 18:24:18 -07:00
}
// KVGasConfig returns a default gas config for KVStores.
func KVGasConfig() GasConfig {
2018-07-26 18:24:18 -07:00
return GasConfig{
HasCost: 1000,
DeleteCost: 1000,
ReadCostFlat: 1000,
ReadCostPerByte: 3,
WriteCostFlat: 2000,
WriteCostPerByte: 30,
IterNextCostFlat: 30,
2018-07-26 18:24:18 -07:00
}
}
// TransientGasConfig returns a default gas config for TransientStores.
2018-07-26 18:24:18 -07:00
func TransientGasConfig() GasConfig {
return GasConfig{
HasCost: 100,
DeleteCost: 100,
ReadCostFlat: 100,
ReadCostPerByte: 0,
WriteCostFlat: 200,
WriteCostPerByte: 3,
IterNextCostFlat: 3,
}
2018-07-26 18:24:18 -07:00
}