github.com/koko1123/flow-go-1@v0.29.6/fvm/executionParameters.go (about) 1 package fvm 2 3 import ( 4 "context" 5 "fmt" 6 "math" 7 8 "github.com/onflow/cadence" 9 "github.com/onflow/cadence/runtime" 10 "github.com/onflow/cadence/runtime/common" 11 12 "github.com/koko1123/flow-go-1/fvm/blueprints" 13 "github.com/koko1123/flow-go-1/fvm/derived" 14 "github.com/koko1123/flow-go-1/fvm/environment" 15 "github.com/koko1123/flow-go-1/fvm/errors" 16 "github.com/koko1123/flow-go-1/fvm/meter" 17 "github.com/koko1123/flow-go-1/fvm/state" 18 "github.com/koko1123/flow-go-1/fvm/utils" 19 ) 20 21 // getBasicMeterParameters returns the set of meter parameters used for 22 // general procedure execution. Subparts of the procedure execution may 23 // specify custom meter parameters via nested transactions. 24 func getBasicMeterParameters( 25 ctx Context, 26 proc Procedure, 27 ) meter.MeterParameters { 28 params := meter.DefaultParameters(). 29 WithComputationLimit(uint(proc.ComputationLimit(ctx))). 30 WithMemoryLimit(proc.MemoryLimit(ctx)). 31 WithEventEmitByteLimit(ctx.EventCollectionByteSizeLimit). 32 WithStorageInteractionLimit(ctx.MaxStateInteractionSize) 33 34 // NOTE: The memory limit (and interaction limit) may be overridden by the 35 // environment. We need to ignore the override in that case. 36 if proc.ShouldDisableMemoryAndInteractionLimits(ctx) { 37 params = params.WithMemoryLimit(math.MaxUint64). 38 WithStorageInteractionLimit(math.MaxUint64) 39 } 40 41 return params 42 } 43 44 // getBodyMeterParameters returns the set of meter parameters used for 45 // transaction/script body execution. 46 func getBodyMeterParameters( 47 ctx Context, 48 proc Procedure, 49 txnState *state.TransactionState, 50 derivedTxnData *derived.DerivedTransactionData, 51 ) ( 52 meter.MeterParameters, 53 error, 54 ) { 55 procParams := getBasicMeterParameters(ctx, proc) 56 57 overrides, err := derivedTxnData.GetMeterParamOverrides( 58 txnState, 59 NewMeterParamOverridesComputer(ctx, derivedTxnData)) 60 if err != nil { 61 return procParams, err 62 } 63 64 if overrides.ComputationWeights != nil { 65 procParams = procParams.WithComputationWeights( 66 overrides.ComputationWeights) 67 } 68 69 if overrides.MemoryWeights != nil { 70 procParams = procParams.WithMemoryWeights(overrides.MemoryWeights) 71 } 72 73 if overrides.MemoryLimit != nil { 74 procParams = procParams.WithMemoryLimit(*overrides.MemoryLimit) 75 } 76 77 // NOTE: The memory limit (and interaction limit) may be overridden by the 78 // environment. We need to ignore the override in that case. 79 if proc.ShouldDisableMemoryAndInteractionLimits(ctx) { 80 procParams = procParams.WithMemoryLimit(math.MaxUint64). 81 WithStorageInteractionLimit(math.MaxUint64) 82 } 83 84 return procParams, nil 85 } 86 87 type MeterParamOverridesComputer struct { 88 ctx Context 89 derivedTxnData *derived.DerivedTransactionData 90 } 91 92 func NewMeterParamOverridesComputer( 93 ctx Context, 94 derivedTxnData *derived.DerivedTransactionData, 95 ) MeterParamOverridesComputer { 96 return MeterParamOverridesComputer{ctx, derivedTxnData} 97 } 98 99 func (computer MeterParamOverridesComputer) Compute( 100 txnState *state.TransactionState, 101 _ struct{}, 102 ) ( 103 derived.MeterParamOverrides, 104 error, 105 ) { 106 var overrides derived.MeterParamOverrides 107 var err error 108 txnState.RunWithAllLimitsDisabled(func() { 109 overrides, err = computer.getMeterParamOverrides(txnState) 110 }) 111 112 if err != nil { 113 return overrides, fmt.Errorf( 114 "error getting environment meter parameter overrides: %w", 115 err) 116 } 117 118 return overrides, nil 119 } 120 121 func (computer MeterParamOverridesComputer) getMeterParamOverrides( 122 txnState *state.TransactionState, 123 ) ( 124 derived.MeterParamOverrides, 125 error, 126 ) { 127 // Check that the service account exists because all the settings are 128 // stored in it 129 serviceAddress := computer.ctx.Chain.ServiceAddress() 130 service := runtime.Address(serviceAddress) 131 132 env := environment.NewScriptEnvironment( 133 context.Background(), 134 computer.ctx.TracerSpan, 135 computer.ctx.EnvironmentParams, 136 txnState, 137 computer.derivedTxnData) 138 139 overrides := derived.MeterParamOverrides{} 140 141 // set the property if no error, but if the error is a fatal error then 142 // return it 143 setIfOk := func(prop string, err error, setter func()) (fatal error) { 144 err, fatal = errors.SplitErrorTypes(err) 145 if fatal != nil { 146 // this is a fatal error. return it 147 computer.ctx.Logger. 148 Error(). 149 Err(fatal). 150 Msgf("error getting %s", prop) 151 return fatal 152 } 153 if err != nil { 154 // this is a general error. 155 // could be that no setting was present in the state, 156 // or that the setting was not parseable, 157 // or some other deterministic thing. 158 computer.ctx.Logger. 159 Debug(). 160 Err(err). 161 Msgf("could not set %s. Using defaults", prop) 162 return nil 163 } 164 // everything is ok. do the setting 165 setter() 166 return nil 167 } 168 169 computationWeights, err := GetExecutionEffortWeights(env, service) 170 err = setIfOk( 171 "execution effort weights", 172 err, 173 func() { overrides.ComputationWeights = computationWeights }) 174 if err != nil { 175 return overrides, err 176 } 177 178 memoryWeights, err := GetExecutionMemoryWeights(env, service) 179 err = setIfOk( 180 "execution memory weights", 181 err, 182 func() { overrides.MemoryWeights = memoryWeights }) 183 if err != nil { 184 return overrides, err 185 } 186 187 memoryLimit, err := GetExecutionMemoryLimit(env, service) 188 err = setIfOk( 189 "execution memory limit", 190 err, 191 func() { overrides.MemoryLimit = &memoryLimit }) 192 if err != nil { 193 return overrides, err 194 } 195 196 return overrides, nil 197 } 198 199 func getExecutionWeights[KindType common.ComputationKind | common.MemoryKind]( 200 env environment.Environment, 201 service runtime.Address, 202 path cadence.Path, 203 defaultWeights map[KindType]uint64, 204 ) ( 205 map[KindType]uint64, 206 error, 207 ) { 208 runtime := env.BorrowCadenceRuntime() 209 defer env.ReturnCadenceRuntime(runtime) 210 211 value, err := runtime.ReadStored(service, path) 212 213 if err != nil { 214 // this might be fatal, return as is 215 return nil, err 216 } 217 218 weightsRaw, ok := utils.CadenceValueToWeights(value) 219 if !ok { 220 // this is a non-fatal error. It is expected if the weights are not set up on the network yet. 221 return nil, errors.NewCouldNotGetExecutionParameterFromStateError( 222 service.Hex(), 223 path.String()) 224 } 225 226 // Merge the default weights with the weights from the state. 227 // This allows for weights that are not set in the state, to be set by default. 228 // In case the network is stuck because of a transaction using an FVM feature that has 0 weight 229 // (or is not metered at all), the defaults can be changed and the network restarted 230 // instead of trying to change the weights with a transaction. 231 weights := make(map[KindType]uint64, len(defaultWeights)) 232 for k, v := range defaultWeights { 233 weights[k] = v 234 } 235 for k, v := range weightsRaw { 236 weights[KindType(k)] = v 237 } 238 239 return weights, nil 240 } 241 242 // GetExecutionEffortWeights reads stored execution effort weights from the service account 243 func GetExecutionEffortWeights( 244 env environment.Environment, 245 service runtime.Address, 246 ) ( 247 computationWeights meter.ExecutionEffortWeights, 248 err error, 249 ) { 250 return getExecutionWeights( 251 env, 252 service, 253 blueprints.TransactionFeesExecutionEffortWeightsPath, 254 meter.DefaultComputationWeights) 255 } 256 257 // GetExecutionMemoryWeights reads stored execution memory weights from the service account 258 func GetExecutionMemoryWeights( 259 env environment.Environment, 260 service runtime.Address, 261 ) ( 262 memoryWeights meter.ExecutionMemoryWeights, 263 err error, 264 ) { 265 return getExecutionWeights( 266 env, 267 service, 268 blueprints.TransactionFeesExecutionMemoryWeightsPath, 269 meter.DefaultMemoryWeights) 270 } 271 272 // GetExecutionMemoryLimit reads the stored execution memory limit from the service account 273 func GetExecutionMemoryLimit( 274 env environment.Environment, 275 service runtime.Address, 276 ) ( 277 memoryLimit uint64, 278 err error, 279 ) { 280 runtime := env.BorrowCadenceRuntime() 281 defer env.ReturnCadenceRuntime(runtime) 282 283 value, err := runtime.ReadStored( 284 service, 285 blueprints.TransactionFeesExecutionMemoryLimitPath) 286 if err != nil { 287 // this might be fatal, return as is 288 return 0, err 289 } 290 291 memoryLimitRaw, ok := value.(cadence.UInt64) 292 if value == nil || !ok { 293 // this is a non-fatal error. It is expected if the weights are not set up on the network yet. 294 return 0, errors.NewCouldNotGetExecutionParameterFromStateError( 295 service.Hex(), 296 blueprints.TransactionFeesExecutionMemoryLimitPath.String()) 297 } 298 299 return memoryLimitRaw.ToGoValue().(uint64), nil 300 }