github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/storage/state/execution_state.go (about) 1 package state 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence/runtime/common" 7 "github.com/onflow/crypto/hash" 8 9 "github.com/onflow/flow-go/fvm/errors" 10 "github.com/onflow/flow-go/fvm/meter" 11 "github.com/onflow/flow-go/fvm/storage/snapshot" 12 "github.com/onflow/flow-go/model/flow" 13 ) 14 15 const ( 16 DefaultMaxKeySize = 16_000 // ~16KB 17 DefaultMaxValueSize = 256_000_000 // ~256MB 18 ) 19 20 // State represents the execution state 21 // it holds draft of updates and captures 22 // all register touches 23 type ExecutionState struct { 24 // NOTE: A finalized state is no longer accessible. It can however be 25 // re-attached to another transaction and be committed (for cached result 26 // bookkeeping purpose). 27 finalized bool 28 29 *spockState 30 meter *meter.Meter 31 32 // NOTE: parent and child state shares the same limits controller 33 *limitsController 34 } 35 36 type StateParameters struct { 37 meter.MeterParameters 38 39 maxKeySizeAllowed uint64 40 maxValueSizeAllowed uint64 41 } 42 43 func DefaultParameters() StateParameters { 44 return StateParameters{ 45 MeterParameters: meter.DefaultParameters(), 46 maxKeySizeAllowed: DefaultMaxKeySize, 47 maxValueSizeAllowed: DefaultMaxValueSize, 48 } 49 } 50 51 // WithMeterParameters sets the state's meter parameters 52 func (params StateParameters) WithMeterParameters( 53 meterParams meter.MeterParameters, 54 ) StateParameters { 55 newParams := params 56 newParams.MeterParameters = meterParams 57 return newParams 58 } 59 60 // WithMaxKeySizeAllowed sets limit on max key size 61 func (params StateParameters) WithMaxKeySizeAllowed( 62 limit uint64, 63 ) StateParameters { 64 newParams := params 65 newParams.maxKeySizeAllowed = limit 66 return newParams 67 } 68 69 // WithMaxValueSizeAllowed sets limit on max value size 70 func (params StateParameters) WithMaxValueSizeAllowed( 71 limit uint64, 72 ) StateParameters { 73 newParams := params 74 newParams.maxValueSizeAllowed = limit 75 return newParams 76 } 77 78 type limitsController struct { 79 enforceLimits bool 80 maxKeySizeAllowed uint64 81 maxValueSizeAllowed uint64 82 } 83 84 func newLimitsController(params StateParameters) *limitsController { 85 return &limitsController{ 86 enforceLimits: true, 87 maxKeySizeAllowed: params.maxKeySizeAllowed, 88 maxValueSizeAllowed: params.maxValueSizeAllowed, 89 } 90 } 91 92 func (controller *limitsController) RunWithAllLimitsDisabled(f func()) { 93 if f == nil { 94 return 95 } 96 current := controller.enforceLimits 97 controller.enforceLimits = false 98 f() 99 controller.enforceLimits = current 100 } 101 102 // NewExecutionState constructs a new state 103 func NewExecutionState( 104 snapshot snapshot.StorageSnapshot, 105 params StateParameters, 106 ) *ExecutionState { 107 return NewExecutionStateWithSpockStateHasher( 108 snapshot, 109 params, 110 DefaultSpockSecretHasher, 111 ) 112 } 113 114 // NewExecutionStateWithSpockStateHasher constructs a new state with a custom hasher 115 func NewExecutionStateWithSpockStateHasher( 116 snapshot snapshot.StorageSnapshot, 117 params StateParameters, 118 getHasher func() hash.Hasher, 119 ) *ExecutionState { 120 m := meter.NewMeter(params.MeterParameters) 121 return &ExecutionState{ 122 finalized: false, 123 spockState: newSpockState(snapshot, getHasher), 124 meter: m, 125 limitsController: newLimitsController(params), 126 } 127 } 128 129 // NewChildWithMeterParams generates a new child state using the provide meter 130 // parameters. 131 func (state *ExecutionState) NewChildWithMeterParams( 132 params meter.MeterParameters, 133 ) *ExecutionState { 134 return &ExecutionState{ 135 finalized: false, 136 spockState: state.spockState.NewChild(), 137 meter: meter.NewMeter(params), 138 limitsController: state.limitsController, 139 } 140 } 141 142 // NewChild generates a new child state using the parent's meter parameters. 143 func (state *ExecutionState) NewChild() *ExecutionState { 144 return state.NewChildWithMeterParams(state.meter.MeterParameters) 145 } 146 147 // InteractionUsed returns the amount of ledger interaction (total ledger byte read + total ledger byte written) 148 func (state *ExecutionState) InteractionUsed() uint64 { 149 return state.meter.TotalBytesOfStorageInteractions() 150 } 151 152 // BytesWritten returns the amount of total ledger bytes written 153 func (state *ExecutionState) BytesWritten() uint64 { 154 return state.meter.TotalBytesWrittenToStorage() 155 } 156 157 func (state *ExecutionState) DropChanges() error { 158 if state.finalized { 159 return fmt.Errorf("cannot DropChanges on a finalized state") 160 } 161 162 return state.spockState.DropChanges() 163 } 164 165 // Get returns a register value given owner and key 166 func (state *ExecutionState) Get(id flow.RegisterID) (flow.RegisterValue, error) { 167 if state.finalized { 168 return nil, fmt.Errorf("cannot Get on a finalized state") 169 } 170 171 var value []byte 172 var err error 173 174 if state.enforceLimits { 175 if err = state.checkSize(id, []byte{}); err != nil { 176 return nil, err 177 } 178 } 179 180 if value, err = state.spockState.Get(id); err != nil { 181 // wrap error into a fatal error 182 getError := errors.NewLedgerFailure(err) 183 // wrap with more info 184 return nil, fmt.Errorf("failed to read %s: %w", id, getError) 185 } 186 187 err = state.meter.MeterStorageRead(id, value, state.enforceLimits) 188 return value, err 189 } 190 191 // Set updates state delta with a register update 192 func (state *ExecutionState) Set(id flow.RegisterID, value flow.RegisterValue) error { 193 if state.finalized { 194 return fmt.Errorf("cannot Set on a finalized state") 195 } 196 197 if state.enforceLimits { 198 if err := state.checkSize(id, value); err != nil { 199 return err 200 } 201 } 202 203 if err := state.spockState.Set(id, value); err != nil { 204 // wrap error into a fatal error 205 setError := errors.NewLedgerFailure(err) 206 // wrap with more info 207 return fmt.Errorf("failed to update %s: %w", id, setError) 208 } 209 210 return state.meter.MeterStorageWrite(id, value, state.enforceLimits) 211 } 212 213 // MeterComputation meters computation usage 214 func (state *ExecutionState) MeterComputation(kind common.ComputationKind, intensity uint) error { 215 if state.finalized { 216 return fmt.Errorf("cannot MeterComputation on a finalized state") 217 } 218 219 if state.enforceLimits { 220 return state.meter.MeterComputation(kind, intensity) 221 } 222 return nil 223 } 224 225 // ComputationAvailable checks if enough computation capacity is available without metering 226 func (state *ExecutionState) ComputationAvailable(kind common.ComputationKind, intensity uint) bool { 227 if state.finalized { 228 // if state is finalized return false 229 return false 230 } 231 232 if state.enforceLimits { 233 return state.meter.ComputationAvailable(kind, intensity) 234 } 235 return true 236 } 237 238 // TotalComputationUsed returns total computation used 239 func (state *ExecutionState) TotalComputationUsed() uint64 { 240 return state.meter.TotalComputationUsed() 241 } 242 243 // ComputationIntensities returns computation intensities 244 func (state *ExecutionState) ComputationIntensities() meter.MeteredComputationIntensities { 245 return state.meter.ComputationIntensities() 246 } 247 248 // TotalComputationLimit returns total computation limit 249 func (state *ExecutionState) TotalComputationLimit() uint { 250 return state.meter.TotalComputationLimit() 251 } 252 253 // MeterMemory meters memory usage 254 func (state *ExecutionState) MeterMemory(kind common.MemoryKind, intensity uint) error { 255 if state.finalized { 256 return fmt.Errorf("cannot MeterMemory on a finalized state") 257 } 258 259 if state.enforceLimits { 260 return state.meter.MeterMemory(kind, intensity) 261 } 262 263 return nil 264 } 265 266 // MemoryIntensities returns computation intensities 267 func (state *ExecutionState) MemoryIntensities() meter.MeteredMemoryIntensities { 268 return state.meter.MemoryIntensities() 269 } 270 271 // TotalMemoryEstimate returns total memory used 272 func (state *ExecutionState) TotalMemoryEstimate() uint64 { 273 return state.meter.TotalMemoryEstimate() 274 } 275 276 // TotalMemoryLimit returns total memory limit 277 func (state *ExecutionState) TotalMemoryLimit() uint { 278 return uint(state.meter.TotalMemoryLimit()) 279 } 280 281 func (state *ExecutionState) MeterEmittedEvent(byteSize uint64) error { 282 if state.finalized { 283 return fmt.Errorf("cannot MeterEmittedEvent on a finalized state") 284 } 285 286 if state.enforceLimits { 287 return state.meter.MeterEmittedEvent(byteSize) 288 } 289 290 return nil 291 } 292 293 func (state *ExecutionState) TotalEmittedEventBytes() uint64 { 294 return state.meter.TotalEmittedEventBytes() 295 } 296 297 func (state *ExecutionState) Finalize() *snapshot.ExecutionSnapshot { 298 state.finalized = true 299 snapshot := state.spockState.Finalize() 300 snapshot.Meter = state.meter 301 return snapshot 302 } 303 304 // MergeState the changes from a the given execution snapshot to this state. 305 func (state *ExecutionState) Merge(other *snapshot.ExecutionSnapshot) error { 306 if state.finalized { 307 return fmt.Errorf("cannot Merge on a finalized state") 308 } 309 310 err := state.spockState.Merge(other) 311 if err != nil { 312 return errors.NewStateMergeFailure(err) 313 } 314 315 state.meter.MergeMeter(other.Meter) 316 return nil 317 } 318 319 func (state *ExecutionState) checkSize( 320 id flow.RegisterID, 321 value flow.RegisterValue, 322 ) error { 323 keySize := uint64(len(id.Owner) + len(id.Key)) 324 valueSize := uint64(len(value)) 325 if keySize > state.maxKeySizeAllowed { 326 return errors.NewStateKeySizeLimitError( 327 id, 328 keySize, 329 state.maxKeySizeAllowed) 330 } 331 if valueSize > state.maxValueSizeAllowed { 332 return errors.NewStateValueSizeLimitError( 333 value, 334 valueSize, 335 state.maxValueSizeAllowed) 336 } 337 return nil 338 } 339 340 func (state *ExecutionState) readSetSize() int { 341 return state.spockState.readSetSize() 342 } 343 344 func (state *ExecutionState) interimReadSet( 345 accumulator map[flow.RegisterID]struct{}, 346 ) { 347 state.spockState.interimReadSet(accumulator) 348 }