github.com/koko1123/flow-go-1@v0.29.6/fvm/runtime/reusable_cadence_runtime.go (about) 1 package runtime 2 3 import ( 4 "github.com/onflow/cadence" 5 "github.com/onflow/cadence/runtime" 6 "github.com/onflow/cadence/runtime/common" 7 "github.com/onflow/cadence/runtime/interpreter" 8 "github.com/onflow/cadence/runtime/sema" 9 "github.com/onflow/cadence/runtime/stdlib" 10 11 "github.com/koko1123/flow-go-1/fvm/errors" 12 ) 13 14 // Note: this is a subset of environment.Environment, redeclared to handle 15 // circular dependency. 16 type Environment interface { 17 runtime.Interface 18 19 SetAccountFrozen(address common.Address, frozen bool) error 20 } 21 22 var setAccountFrozenFunctionType = &sema.FunctionType{ 23 Parameters: []sema.Parameter{ 24 { 25 Label: sema.ArgumentLabelNotRequired, 26 Identifier: "account", 27 TypeAnnotation: sema.NewTypeAnnotation(sema.TheAddressType), 28 }, 29 { 30 Label: sema.ArgumentLabelNotRequired, 31 Identifier: "frozen", 32 TypeAnnotation: sema.NewTypeAnnotation(sema.BoolType), 33 }, 34 }, 35 ReturnTypeAnnotation: sema.TypeAnnotation{ 36 Type: sema.VoidType, 37 }, 38 } 39 40 type ReusableCadenceRuntime struct { 41 runtime.Runtime 42 runtime.Environment 43 44 fvmEnv Environment 45 } 46 47 func NewReusableCadenceRuntime(rt runtime.Runtime, config runtime.Config) *ReusableCadenceRuntime { 48 reusable := &ReusableCadenceRuntime{ 49 Runtime: rt, 50 Environment: runtime.NewBaseInterpreterEnvironment(config), 51 } 52 53 setAccountFrozen := stdlib.StandardLibraryValue{ 54 Name: "setAccountFrozen", 55 Type: setAccountFrozenFunctionType, 56 Kind: common.DeclarationKindFunction, 57 Value: interpreter.NewUnmeteredHostFunctionValue( 58 func(invocation interpreter.Invocation) interpreter.Value { 59 address, ok := invocation.Arguments[0].(interpreter.AddressValue) 60 if !ok { 61 panic(errors.NewValueErrorf(invocation.Arguments[0].String(), 62 "first argument of setAccountFrozen must be an address")) 63 } 64 65 frozen, ok := invocation.Arguments[1].(interpreter.BoolValue) 66 if !ok { 67 panic(errors.NewValueErrorf(invocation.Arguments[0].String(), 68 "second argument of setAccountFrozen must be a boolean")) 69 } 70 71 var err error 72 if reusable.fvmEnv != nil { 73 err = reusable.fvmEnv.SetAccountFrozen( 74 common.Address(address), 75 bool(frozen)) 76 } else { 77 err = errors.NewOperationNotSupportedError("SetAccountFrozen") 78 } 79 80 if err != nil { 81 panic(err) 82 } 83 84 return interpreter.VoidValue{} 85 }, 86 setAccountFrozenFunctionType, 87 ), 88 } 89 90 reusable.Declare(setAccountFrozen) 91 return reusable 92 } 93 94 func (reusable *ReusableCadenceRuntime) SetFvmEnvironment(fvmEnv Environment) { 95 reusable.fvmEnv = fvmEnv 96 } 97 98 func (reusable *ReusableCadenceRuntime) ReadStored( 99 address common.Address, 100 path cadence.Path, 101 ) ( 102 cadence.Value, 103 error, 104 ) { 105 return reusable.Runtime.ReadStored( 106 address, 107 path, 108 runtime.Context{ 109 Interface: reusable.fvmEnv, 110 Environment: reusable.Environment, 111 }, 112 ) 113 } 114 115 func (reusable *ReusableCadenceRuntime) InvokeContractFunction( 116 contractLocation common.AddressLocation, 117 functionName string, 118 arguments []cadence.Value, 119 argumentTypes []sema.Type, 120 ) ( 121 cadence.Value, 122 error, 123 ) { 124 return reusable.Runtime.InvokeContractFunction( 125 contractLocation, 126 functionName, 127 arguments, 128 argumentTypes, 129 runtime.Context{ 130 Interface: reusable.fvmEnv, 131 Environment: reusable.Environment, 132 }, 133 ) 134 } 135 136 func (reusable *ReusableCadenceRuntime) NewTransactionExecutor( 137 script runtime.Script, 138 location common.Location, 139 ) runtime.Executor { 140 return reusable.Runtime.NewTransactionExecutor( 141 script, 142 runtime.Context{ 143 Interface: reusable.fvmEnv, 144 Location: location, 145 Environment: reusable.Environment, 146 }, 147 ) 148 } 149 150 func (reusable *ReusableCadenceRuntime) ExecuteScript( 151 script runtime.Script, 152 location common.Location, 153 ) ( 154 cadence.Value, 155 error, 156 ) { 157 return reusable.Runtime.ExecuteScript( 158 script, 159 runtime.Context{ 160 Interface: reusable.fvmEnv, 161 Location: location, 162 }, 163 ) 164 } 165 166 type CadenceRuntimeConstructor func(config runtime.Config) runtime.Runtime 167 168 type ReusableCadenceRuntimePool struct { 169 pool chan *ReusableCadenceRuntime 170 171 config runtime.Config 172 173 // When newCustomRuntime is nil, the pool will create standard cadence 174 // interpreter runtimes via runtime.NewInterpreterRuntime. Otherwise, the 175 // pool will create runtimes using this function. 176 // 177 // Note that this is primarily used for testing. 178 newCustomRuntime CadenceRuntimeConstructor 179 } 180 181 func newReusableCadenceRuntimePool( 182 poolSize int, 183 config runtime.Config, 184 newCustomRuntime CadenceRuntimeConstructor, 185 ) ReusableCadenceRuntimePool { 186 var pool chan *ReusableCadenceRuntime 187 if poolSize > 0 { 188 pool = make(chan *ReusableCadenceRuntime, poolSize) 189 } 190 191 return ReusableCadenceRuntimePool{ 192 pool: pool, 193 config: config, 194 newCustomRuntime: newCustomRuntime, 195 } 196 } 197 198 func NewReusableCadenceRuntimePool( 199 poolSize int, 200 config runtime.Config, 201 ) ReusableCadenceRuntimePool { 202 return newReusableCadenceRuntimePool(poolSize, config, nil) 203 } 204 205 func NewCustomReusableCadenceRuntimePool( 206 poolSize int, 207 newCustomRuntime CadenceRuntimeConstructor, 208 ) ReusableCadenceRuntimePool { 209 return newReusableCadenceRuntimePool( 210 poolSize, 211 runtime.Config{}, 212 newCustomRuntime, 213 ) 214 } 215 216 func (pool ReusableCadenceRuntimePool) newRuntime() runtime.Runtime { 217 if pool.newCustomRuntime != nil { 218 return pool.newCustomRuntime(pool.config) 219 } 220 return runtime.NewInterpreterRuntime(pool.config) 221 } 222 223 func (pool ReusableCadenceRuntimePool) Borrow( 224 fvmEnv Environment, 225 ) *ReusableCadenceRuntime { 226 var reusable *ReusableCadenceRuntime 227 select { 228 case reusable = <-pool.pool: 229 // Do nothing. 230 default: 231 reusable = NewReusableCadenceRuntime( 232 WrappedCadenceRuntime{ 233 pool.newRuntime(), 234 }, 235 pool.config, 236 ) 237 } 238 239 reusable.SetFvmEnvironment(fvmEnv) 240 return reusable 241 } 242 243 func (pool ReusableCadenceRuntimePool) Return( 244 reusable *ReusableCadenceRuntime, 245 ) { 246 reusable.SetFvmEnvironment(nil) 247 select { 248 case pool.pool <- reusable: 249 // Do nothing. 250 default: 251 // Do nothing. Discard the overflow entry. 252 } 253 }