github.com/koko1123/flow-go-1@v0.29.6/fvm/script.go (about) 1 package fvm 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/onflow/cadence" 8 "github.com/onflow/cadence/runtime" 9 "github.com/onflow/cadence/runtime/common" 10 11 "github.com/koko1123/flow-go-1/fvm/derived" 12 "github.com/koko1123/flow-go-1/fvm/environment" 13 "github.com/koko1123/flow-go-1/fvm/errors" 14 "github.com/koko1123/flow-go-1/fvm/state" 15 "github.com/koko1123/flow-go-1/model/flow" 16 "github.com/koko1123/flow-go-1/model/hash" 17 ) 18 19 type ScriptProcedure struct { 20 ID flow.Identifier 21 Script []byte 22 Arguments [][]byte 23 RequestContext context.Context 24 Value cadence.Value 25 Logs []string 26 Events []flow.Event 27 GasUsed uint64 28 MemoryEstimate uint64 29 Err errors.CodedError 30 } 31 32 func Script(code []byte) *ScriptProcedure { 33 scriptHash := hash.DefaultHasher.ComputeHash(code) 34 35 return &ScriptProcedure{ 36 Script: code, 37 ID: flow.HashToID(scriptHash), 38 RequestContext: context.Background(), 39 } 40 } 41 42 func (proc *ScriptProcedure) WithArguments(args ...[]byte) *ScriptProcedure { 43 return &ScriptProcedure{ 44 ID: proc.ID, 45 Script: proc.Script, 46 RequestContext: proc.RequestContext, 47 Arguments: args, 48 } 49 } 50 51 func (proc *ScriptProcedure) WithRequestContext( 52 reqContext context.Context, 53 ) *ScriptProcedure { 54 return &ScriptProcedure{ 55 ID: proc.ID, 56 Script: proc.Script, 57 RequestContext: reqContext, 58 Arguments: proc.Arguments, 59 } 60 } 61 62 func NewScriptWithContextAndArgs( 63 code []byte, 64 reqContext context.Context, 65 args ...[]byte, 66 ) *ScriptProcedure { 67 scriptHash := hash.DefaultHasher.ComputeHash(code) 68 return &ScriptProcedure{ 69 ID: flow.HashToID(scriptHash), 70 Script: code, 71 RequestContext: reqContext, 72 Arguments: args, 73 } 74 } 75 76 func (proc *ScriptProcedure) NewExecutor( 77 ctx Context, 78 txnState *state.TransactionState, 79 derivedTxnData *derived.DerivedTransactionData, 80 ) ProcedureExecutor { 81 return newScriptExecutor(ctx, proc, txnState, derivedTxnData) 82 } 83 84 func (proc *ScriptProcedure) ComputationLimit(ctx Context) uint64 { 85 computationLimit := ctx.ComputationLimit 86 // if ctx.ComputationLimit is also zero, fallback to the default computation limit 87 if computationLimit == 0 { 88 computationLimit = DefaultComputationLimit 89 } 90 return computationLimit 91 } 92 93 func (proc *ScriptProcedure) MemoryLimit(ctx Context) uint64 { 94 memoryLimit := ctx.MemoryLimit 95 // if ctx.MemoryLimit is also zero, fallback to the default memory limit 96 if memoryLimit == 0 { 97 memoryLimit = DefaultMemoryLimit 98 } 99 return memoryLimit 100 } 101 102 func (proc *ScriptProcedure) ShouldDisableMemoryAndInteractionLimits( 103 ctx Context, 104 ) bool { 105 return ctx.DisableMemoryAndInteractionLimits 106 } 107 108 func (ScriptProcedure) Type() ProcedureType { 109 return ScriptProcedureType 110 } 111 112 func (proc *ScriptProcedure) InitialSnapshotTime() derived.LogicalTime { 113 return derived.EndOfBlockExecutionTime 114 } 115 116 func (proc *ScriptProcedure) ExecutionTime() derived.LogicalTime { 117 return derived.EndOfBlockExecutionTime 118 } 119 120 type scriptExecutor struct { 121 ctx Context 122 proc *ScriptProcedure 123 txnState *state.TransactionState 124 derivedTxnData *derived.DerivedTransactionData 125 126 env environment.Environment 127 } 128 129 func newScriptExecutor( 130 ctx Context, 131 proc *ScriptProcedure, 132 txnState *state.TransactionState, 133 derivedTxnData *derived.DerivedTransactionData, 134 ) *scriptExecutor { 135 return &scriptExecutor{ 136 ctx: ctx, 137 proc: proc, 138 txnState: txnState, 139 derivedTxnData: derivedTxnData, 140 env: environment.NewScriptEnvironment( 141 proc.RequestContext, 142 ctx.TracerSpan, 143 ctx.EnvironmentParams, 144 txnState, 145 derivedTxnData), 146 } 147 } 148 149 func (executor *scriptExecutor) Cleanup() { 150 // Do nothing. 151 } 152 153 func (executor *scriptExecutor) Preprocess() error { 154 // Do nothing. 155 return nil 156 } 157 158 func (executor *scriptExecutor) Execute() error { 159 err := executor.execute() 160 txError, failure := errors.SplitErrorTypes(err) 161 if failure != nil { 162 if errors.IsLedgerFailure(failure) { 163 return fmt.Errorf( 164 "cannot execute the script, this error usually happens if "+ 165 "the reference block for this script is not set to a "+ 166 "recent block: %w", 167 failure) 168 } 169 return failure 170 } 171 if txError != nil { 172 executor.proc.Err = txError 173 } 174 175 return nil 176 } 177 178 func (executor *scriptExecutor) execute() error { 179 meterParams, err := getBodyMeterParameters( 180 executor.ctx, 181 executor.proc, 182 executor.txnState, 183 executor.derivedTxnData) 184 if err != nil { 185 return fmt.Errorf("error gettng meter parameters: %w", err) 186 } 187 188 txnId, err := executor.txnState.BeginNestedTransactionWithMeterParams( 189 meterParams) 190 if err != nil { 191 return err 192 } 193 194 rt := executor.env.BorrowCadenceRuntime() 195 defer executor.env.ReturnCadenceRuntime(rt) 196 197 value, err := rt.ExecuteScript( 198 runtime.Script{ 199 Source: executor.proc.Script, 200 Arguments: executor.proc.Arguments, 201 }, 202 common.ScriptLocation(executor.proc.ID)) 203 204 if err != nil { 205 return err 206 } 207 208 executor.proc.Value = value 209 executor.proc.Logs = executor.env.Logs() 210 executor.proc.Events = executor.env.Events() 211 executor.proc.GasUsed = executor.env.ComputationUsed() 212 executor.proc.MemoryEstimate = executor.env.MemoryEstimate() 213 214 _, err = executor.txnState.Commit(txnId) 215 return err 216 }