cosmos-sdk/server/v2/stf/gas/store.go

177 lines
4.1 KiB
Go

package gas
import (
"cosmossdk.io/core/gas"
"cosmossdk.io/core/store"
)
// Gas consumption descriptors.
const (
DescIterNextCostFlat = "IterNextFlat"
DescValuePerByte = "ValuePerByte"
DescWritePerByte = "WritePerByte"
DescReadPerByte = "ReadPerByte"
DescWriteCostFlat = "WriteFlat"
DescReadCostFlat = "ReadFlat"
DescHas = "Has"
DescDelete = "Delete"
)
type Store struct {
parent store.Writer
gasMeter gas.Meter
gasConfig gas.GasConfig
}
func NewStore(gc gas.GasConfig, meter gas.Meter, parent store.Writer) *Store {
return &Store{
parent: parent,
gasMeter: meter,
gasConfig: gc,
}
}
func (s *Store) Get(key []byte) ([]byte, error) {
if err := s.gasMeter.Consume(s.gasConfig.ReadCostFlat, DescReadCostFlat); err != nil {
return nil, err
}
value, err := s.parent.Get(key)
if err := s.gasMeter.Consume(s.gasConfig.ReadCostPerByte*gas.Gas(len(key)), DescReadPerByte); err != nil {
return nil, err
}
if err := s.gasMeter.Consume(s.gasConfig.ReadCostPerByte*gas.Gas(len(value)), DescReadPerByte); err != nil {
return nil, err
}
return value, err
}
func (s *Store) Has(key []byte) (bool, error) {
if err := s.gasMeter.Consume(s.gasConfig.HasCost, DescHas); err != nil {
return false, err
}
return s.parent.Has(key)
}
func (s *Store) Set(key, value []byte) error {
if err := s.gasMeter.Consume(s.gasConfig.WriteCostFlat, DescWriteCostFlat); err != nil {
return err
}
if err := s.gasMeter.Consume(s.gasConfig.WriteCostPerByte*gas.Gas(len(key)), DescWritePerByte); err != nil {
return err
}
if err := s.gasMeter.Consume(s.gasConfig.WriteCostPerByte*gas.Gas(len(value)), DescWritePerByte); err != nil {
return err
}
return s.parent.Set(key, value)
}
func (s *Store) Delete(key []byte) error {
if err := s.gasMeter.Consume(s.gasConfig.DeleteCost, DescDelete); err != nil {
return err
}
return s.parent.Delete(key)
}
func (s *Store) ApplyChangeSets(changes []store.KVPair) error {
return s.parent.ApplyChangeSets(changes)
}
func (s *Store) ChangeSets() ([]store.KVPair, error) {
return s.parent.ChangeSets()
}
func (s *Store) Iterator(start, end []byte) (store.Iterator, error) {
itr, err := s.parent.Iterator(start, end)
if err != nil {
return nil, err
}
return newIterator(itr, s.gasMeter, s.gasConfig), nil
}
func (s *Store) ReverseIterator(start, end []byte) (store.Iterator, error) {
itr, err := s.parent.ReverseIterator(start, end)
if err != nil {
return nil, err
}
return newIterator(itr, s.gasMeter, s.gasConfig), nil
}
var _ store.Iterator = (*iterator)(nil)
type iterator struct {
gasMeter gas.Meter
gasConfig gas.GasConfig
parent store.Iterator
}
func newIterator(parent store.Iterator, gm gas.Meter, gc gas.GasConfig) store.Iterator {
return &iterator{
parent: parent,
gasConfig: gc,
gasMeter: gm,
}
}
func (itr *iterator) Domain() ([]byte, []byte) {
return itr.parent.Domain()
}
func (itr *iterator) Valid() bool {
return itr.parent.Valid()
}
func (itr *iterator) Key() []byte {
return itr.parent.Key()
}
func (itr *iterator) Value() []byte {
return itr.parent.Value()
}
func (itr *iterator) Next() {
if err := itr.consumeGasSeek(); err != nil {
// closing the iterator prematurely to prevent further execution
itr.parent.Close()
return
}
itr.parent.Next()
}
func (itr *iterator) Close() error {
return itr.parent.Close()
}
func (itr *iterator) Error() error {
return itr.parent.Error()
}
// consumeGasSeek consumes a fixed amount of gas for each iteration step and a
// variable gas cost based on the current key and value's length. This is called
// prior to the iterator's Next() call.
func (itr *iterator) consumeGasSeek() error {
if itr.Valid() {
key := itr.Key()
value := itr.Value()
if err := itr.gasMeter.Consume(itr.gasConfig.ReadCostPerByte*gas.Gas(len(key)), DescValuePerByte); err != nil {
return err
}
if err := itr.gasMeter.Consume(itr.gasConfig.ReadCostPerByte*gas.Gas(len(value)), DescValuePerByte); err != nil {
return err
}
}
if err := itr.gasMeter.Consume(itr.gasConfig.IterNextCostFlat, DescIterNextCostFlat); err != nil {
return err
}
return nil
}