github.com/Finschia/finschia-sdk@v0.48.1/store/gaskv/store.go (about)

     1  package gaskv
     2  
     3  import (
     4  	"io"
     5  	"time"
     6  
     7  	"github.com/Finschia/finschia-sdk/store/types"
     8  	"github.com/Finschia/finschia-sdk/telemetry"
     9  )
    10  
    11  var _ types.KVStore = &Store{}
    12  
    13  // Store applies gas tracking to an underlying KVStore. It implements the
    14  // KVStore interface.
    15  type Store struct {
    16  	gasMeter  types.GasMeter
    17  	gasConfig types.GasConfig
    18  	parent    types.KVStore
    19  }
    20  
    21  // NewStore returns a reference to a new GasKVStore.
    22  func NewStore(parent types.KVStore, gasMeter types.GasMeter, gasConfig types.GasConfig) *Store {
    23  	kvs := &Store{
    24  		gasMeter:  gasMeter,
    25  		gasConfig: gasConfig,
    26  		parent:    parent,
    27  	}
    28  	return kvs
    29  }
    30  
    31  // Implements Store.
    32  func (gs *Store) GetStoreType() types.StoreType {
    33  	return gs.parent.GetStoreType()
    34  }
    35  
    36  // Implements KVStore.
    37  func (gs *Store) Get(key []byte) (value []byte) {
    38  	gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostFlat, types.GasReadCostFlatDesc)
    39  	value = gs.parent.Get(key)
    40  
    41  	// TODO overflow-safe math?
    42  	gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasReadPerByteDesc)
    43  	gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasReadPerByteDesc)
    44  
    45  	return value
    46  }
    47  
    48  // Implements KVStore.
    49  func (gs *Store) Set(key []byte, value []byte) {
    50  	types.AssertValidKey(key)
    51  	types.AssertValidValue(value)
    52  	gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, types.GasWriteCostFlatDesc)
    53  	// TODO overflow-safe math?
    54  	gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(key)), types.GasWritePerByteDesc)
    55  	gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(value)), types.GasWritePerByteDesc)
    56  	gs.parent.Set(key, value)
    57  }
    58  
    59  // Implements KVStore.
    60  func (gs *Store) Has(key []byte) bool {
    61  	defer telemetry.MeasureSince(time.Now(), "store", "gaskv", "has")
    62  	gs.gasMeter.ConsumeGas(gs.gasConfig.HasCost, types.GasHasDesc)
    63  	return gs.parent.Has(key)
    64  }
    65  
    66  // Implements KVStore.
    67  func (gs *Store) Delete(key []byte) {
    68  	defer telemetry.MeasureSince(time.Now(), "store", "gaskv", "delete")
    69  	// charge gas to prevent certain attack vectors even though space is being freed
    70  	gs.gasMeter.ConsumeGas(gs.gasConfig.DeleteCost, types.GasDeleteDesc)
    71  	gs.parent.Delete(key)
    72  }
    73  
    74  // Iterator implements the KVStore interface. It returns an iterator which
    75  // incurs a flat gas cost for seeking to the first key/value pair and a variable
    76  // gas cost based on the current value's length if the iterator is valid.
    77  func (gs *Store) Iterator(start, end []byte) types.Iterator {
    78  	return gs.iterator(start, end, true)
    79  }
    80  
    81  // ReverseIterator implements the KVStore interface. It returns a reverse
    82  // iterator which incurs a flat gas cost for seeking to the first key/value pair
    83  // and a variable gas cost based on the current value's length if the iterator
    84  // is valid.
    85  func (gs *Store) ReverseIterator(start, end []byte) types.Iterator {
    86  	return gs.iterator(start, end, false)
    87  }
    88  
    89  // Implements KVStore.
    90  func (gs *Store) CacheWrap() types.CacheWrap {
    91  	panic("cannot CacheWrap a GasKVStore")
    92  }
    93  
    94  // CacheWrapWithTrace implements the KVStore interface.
    95  func (gs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap {
    96  	panic("cannot CacheWrapWithTrace a GasKVStore")
    97  }
    98  
    99  // CacheWrapWithListeners implements the CacheWrapper interface.
   100  func (gs *Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap {
   101  	panic("cannot CacheWrapWithListeners a GasKVStore")
   102  }
   103  
   104  func (gs *Store) iterator(start, end []byte, ascending bool) types.Iterator {
   105  	var parent types.Iterator
   106  	if ascending {
   107  		parent = gs.parent.Iterator(start, end)
   108  	} else {
   109  		parent = gs.parent.ReverseIterator(start, end)
   110  	}
   111  
   112  	gi := newGasIterator(gs.gasMeter, gs.gasConfig, parent)
   113  	gi.(*gasIterator).consumeSeekGas()
   114  
   115  	return gi
   116  }
   117  
   118  type gasIterator struct {
   119  	gasMeter  types.GasMeter
   120  	gasConfig types.GasConfig
   121  	parent    types.Iterator
   122  }
   123  
   124  func newGasIterator(gasMeter types.GasMeter, gasConfig types.GasConfig, parent types.Iterator) types.Iterator {
   125  	return &gasIterator{
   126  		gasMeter:  gasMeter,
   127  		gasConfig: gasConfig,
   128  		parent:    parent,
   129  	}
   130  }
   131  
   132  // Implements Iterator.
   133  func (gi *gasIterator) Domain() (start []byte, end []byte) {
   134  	return gi.parent.Domain()
   135  }
   136  
   137  // Implements Iterator.
   138  func (gi *gasIterator) Valid() bool {
   139  	return gi.parent.Valid()
   140  }
   141  
   142  // Next implements the Iterator interface. It seeks to the next key/value pair
   143  // in the iterator. It incurs a flat gas cost for seeking and a variable gas
   144  // cost based on the current value's length if the iterator is valid.
   145  func (gi *gasIterator) Next() {
   146  	gi.consumeSeekGas()
   147  	gi.parent.Next()
   148  }
   149  
   150  // Key implements the Iterator interface. It returns the current key and it does
   151  // not incur any gas cost.
   152  func (gi *gasIterator) Key() (key []byte) {
   153  	key = gi.parent.Key()
   154  	return key
   155  }
   156  
   157  // Value implements the Iterator interface. It returns the current value and it
   158  // does not incur any gas cost.
   159  func (gi *gasIterator) Value() (value []byte) {
   160  	value = gi.parent.Value()
   161  	return value
   162  }
   163  
   164  // Implements Iterator.
   165  func (gi *gasIterator) Close() error {
   166  	return gi.parent.Close()
   167  }
   168  
   169  // Error delegates the Error call to the parent iterator.
   170  func (gi *gasIterator) Error() error {
   171  	return gi.parent.Error()
   172  }
   173  
   174  // consumeSeekGas consumes on each iteration step a flat gas cost and a variable gas cost
   175  // based on the current value's length.
   176  func (gi *gasIterator) consumeSeekGas() {
   177  	if gi.Valid() {
   178  		key := gi.Key()
   179  		value := gi.Value()
   180  
   181  		gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasValuePerByteDesc)
   182  		gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasValuePerByteDesc)
   183  	}
   184  
   185  	gi.gasMeter.ConsumeGas(gi.gasConfig.IterNextCostFlat, types.GasIterNextCostFlatDesc)
   186  }