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 }