github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/value_store.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/atree" 7 8 "github.com/onflow/flow-go/fvm/errors" 9 "github.com/onflow/flow-go/fvm/storage/state" 10 "github.com/onflow/flow-go/fvm/tracing" 11 "github.com/onflow/flow-go/model/flow" 12 "github.com/onflow/flow-go/module/trace" 13 ) 14 15 // ValueStore provides read/write access to the account storage. 16 type ValueStore interface { 17 GetValue(owner []byte, key []byte) ([]byte, error) 18 19 SetValue(owner, key, value []byte) error 20 21 ValueExists(owner []byte, key []byte) (bool, error) 22 23 AllocateSlabIndex(owner []byte) (atree.SlabIndex, error) 24 } 25 26 type ParseRestrictedValueStore struct { 27 txnState state.NestedTransactionPreparer 28 impl ValueStore 29 } 30 31 func NewParseRestrictedValueStore( 32 txnState state.NestedTransactionPreparer, 33 impl ValueStore, 34 ) ValueStore { 35 return ParseRestrictedValueStore{ 36 txnState: txnState, 37 impl: impl, 38 } 39 } 40 41 func (store ParseRestrictedValueStore) GetValue( 42 owner []byte, 43 key []byte, 44 ) ( 45 []byte, 46 error, 47 ) { 48 return parseRestrict2Arg1Ret( 49 store.txnState, 50 trace.FVMEnvGetValue, 51 store.impl.GetValue, 52 owner, 53 key) 54 } 55 56 func (store ParseRestrictedValueStore) SetValue( 57 owner []byte, 58 key []byte, 59 value []byte, 60 ) error { 61 return parseRestrict3Arg( 62 store.txnState, 63 trace.FVMEnvSetValue, 64 store.impl.SetValue, 65 owner, 66 key, 67 value) 68 } 69 70 func (store ParseRestrictedValueStore) ValueExists( 71 owner []byte, 72 key []byte, 73 ) ( 74 bool, 75 error, 76 ) { 77 return parseRestrict2Arg1Ret( 78 store.txnState, 79 trace.FVMEnvValueExists, 80 store.impl.ValueExists, 81 owner, 82 key) 83 } 84 85 func (store ParseRestrictedValueStore) AllocateSlabIndex( 86 owner []byte, 87 ) ( 88 atree.SlabIndex, 89 error, 90 ) { 91 return parseRestrict1Arg1Ret( 92 store.txnState, 93 trace.FVMEnvAllocateStorageIndex, 94 store.impl.AllocateSlabIndex, 95 owner) 96 } 97 98 type valueStore struct { 99 tracer tracing.TracerSpan 100 meter Meter 101 102 accounts Accounts 103 } 104 105 func NewValueStore( 106 tracer tracing.TracerSpan, 107 meter Meter, 108 accounts Accounts, 109 ) ValueStore { 110 return &valueStore{ 111 tracer: tracer, 112 meter: meter, 113 accounts: accounts, 114 } 115 } 116 117 func (store *valueStore) GetValue( 118 owner []byte, 119 keyBytes []byte, 120 ) ( 121 []byte, 122 error, 123 ) { 124 defer store.tracer.StartChildSpan(trace.FVMEnvGetValue).End() 125 126 id := flow.CadenceRegisterID(owner, keyBytes) 127 if id.IsInternalState() { 128 return nil, errors.NewInvalidInternalStateAccessError(id, "read") 129 } 130 131 v, err := store.accounts.GetValue(id) 132 if err != nil { 133 return nil, fmt.Errorf("get value failed: %w", err) 134 } 135 136 err = store.meter.MeterComputation(ComputationKindGetValue, uint(len(v))) 137 if err != nil { 138 return nil, fmt.Errorf("get value failed: %w", err) 139 } 140 return v, nil 141 } 142 143 // TODO disable SetValue for scripts, right now the view changes are discarded 144 func (store *valueStore) SetValue( 145 owner []byte, 146 keyBytes []byte, 147 value []byte, 148 ) error { 149 defer store.tracer.StartChildSpan(trace.FVMEnvSetValue).End() 150 151 id := flow.CadenceRegisterID(owner, keyBytes) 152 if id.IsInternalState() { 153 return errors.NewInvalidInternalStateAccessError(id, "modify") 154 } 155 156 err := store.meter.MeterComputation( 157 ComputationKindSetValue, 158 uint(len(value))) 159 if err != nil { 160 return fmt.Errorf("set value failed: %w", err) 161 } 162 163 err = store.accounts.SetValue(id, value) 164 if err != nil { 165 return fmt.Errorf("set value failed: %w", err) 166 } 167 return nil 168 } 169 170 func (store *valueStore) ValueExists( 171 owner []byte, 172 key []byte, 173 ) ( 174 exists bool, 175 err error, 176 ) { 177 defer store.tracer.StartChildSpan(trace.FVMEnvValueExists).End() 178 179 err = store.meter.MeterComputation(ComputationKindValueExists, 1) 180 if err != nil { 181 return false, fmt.Errorf("check value existence failed: %w", err) 182 } 183 184 v, err := store.GetValue(owner, key) 185 if err != nil { 186 return false, fmt.Errorf("check value existence failed: %w", err) 187 } 188 189 return len(v) > 0, nil 190 } 191 192 // AllocateSlabIndex allocates new storage index under the owner accounts 193 // to store a new register. 194 func (store *valueStore) AllocateSlabIndex( 195 owner []byte, 196 ) ( 197 atree.SlabIndex, 198 error, 199 ) { 200 defer store.tracer.StartChildSpan(trace.FVMEnvAllocateStorageIndex).End() 201 202 err := store.meter.MeterComputation(ComputationKindAllocateStorageIndex, 1) 203 if err != nil { 204 return atree.SlabIndex{}, fmt.Errorf( 205 "allocate storage index failed: %w", 206 err) 207 } 208 209 v, err := store.accounts.AllocateSlabIndex(flow.BytesToAddress(owner)) 210 if err != nil { 211 return atree.SlabIndex{}, fmt.Errorf( 212 "storage address allocation failed: %w", 213 err) 214 } 215 return v, nil 216 }