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