package types // Gas consumption descriptors. const ( GasIterNextCostFlatDesc = "IterNextFlat" GasValuePerByteDesc = "ValuePerByte" GasWritePerByteDesc = "WritePerByte" GasReadPerByteDesc = "ReadPerByte" GasWriteCostFlatDesc = "WriteFlat" GasReadCostFlatDesc = "ReadFlat" GasHasDesc = "Has" GasDeleteDesc = "Delete" ) var ( cachedKVGasConfig = KVGasConfig() cachedTransientGasConfig = TransientGasConfig() ) // Gas measured by the SDK type Gas = uint64 // ErrorOutOfGas defines an error thrown when an action results in out of gas. type ErrorOutOfGas struct { Descriptor string } // ErrorGasOverflow defines an error thrown when an action results gas consumption // unsigned integer overflow. type ErrorGasOverflow struct { Descriptor string } // GasMeter interface to track gas consumption type GasMeter interface { GasConsumed() Gas GasConsumedToLimit() Gas Limit() Gas ConsumeGas(amount Gas, descriptor string) IsPastLimit() bool IsOutOfGas() bool } type basicGasMeter struct { limit Gas consumed Gas } // NewGasMeter returns a reference to a new basicGasMeter. 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.consumed > g.limit { return g.limit } else { return g.consumed } } func (g *basicGasMeter) ConsumeGas(amount 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}) } if g.consumed > g.limit { panic(ErrorOutOfGas{descriptor}) } } func (g *basicGasMeter) IsPastLimit() bool { return g.consumed > g.limit } func (g *basicGasMeter) IsOutOfGas() bool { return g.consumed >= g.limit } type infiniteGasMeter struct { consumed Gas } // NewInfiniteGasMeter returns a reference to a new infiniteGasMeter. 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 } func (g *infiniteGasMeter) ConsumeGas(amount 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}) } } func (g *infiniteGasMeter) IsPastLimit() bool { return false } func (g *infiniteGasMeter) IsOutOfGas() bool { return false } // GasConfig defines gas cost for each operation on KVStores type GasConfig struct { HasCost Gas DeleteCost Gas ReadCostFlat Gas ReadCostPerByte Gas WriteCostFlat Gas WriteCostPerByte Gas ValueCostPerByte Gas IterNextCostFlat Gas } // KVGasConfig returns a default gas config for KVStores. func KVGasConfig() GasConfig { return GasConfig{ HasCost: 10, DeleteCost: 10, ReadCostFlat: 10, ReadCostPerByte: 1, WriteCostFlat: 10, WriteCostPerByte: 10, ValueCostPerByte: 1, IterNextCostFlat: 15, } } // TransientGasConfig returns a default gas config for TransientStores. func TransientGasConfig() GasConfig { // TODO: define gasconfig for transient stores return KVGasConfig() }