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