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