github.com/koko1123/flow-go-1@v0.29.6/fvm/environment/system_contracts.go (about) 1 package environment 2 3 import ( 4 "github.com/onflow/cadence" 5 "github.com/onflow/cadence/runtime/common" 6 "github.com/onflow/cadence/runtime/sema" 7 "go.opentelemetry.io/otel/attribute" 8 9 "github.com/koko1123/flow-go-1/fvm/systemcontracts" 10 "github.com/koko1123/flow-go-1/fvm/tracing" 11 "github.com/koko1123/flow-go-1/model/flow" 12 "github.com/koko1123/flow-go-1/module/trace" 13 ) 14 15 // ContractFunctionSpec specify all the information, except the function's 16 // address and arguments, needed to invoke the contract function. 17 type ContractFunctionSpec struct { 18 AddressFromChain func(flow.Chain) flow.Address 19 LocationName string 20 FunctionName string 21 ArgumentTypes []sema.Type 22 } 23 24 // SystemContracts provides methods for invoking system contract functions as 25 // service account. 26 type SystemContracts struct { 27 chain flow.Chain 28 29 tracer tracing.TracerSpan 30 logger *ProgramLogger 31 runtime *Runtime 32 } 33 34 func NewSystemContracts( 35 chain flow.Chain, 36 tracer tracing.TracerSpan, 37 logger *ProgramLogger, 38 runtime *Runtime, 39 ) *SystemContracts { 40 return &SystemContracts{ 41 chain: chain, 42 tracer: tracer, 43 logger: logger, 44 runtime: runtime, 45 } 46 } 47 48 func (sys *SystemContracts) Invoke( 49 spec ContractFunctionSpec, 50 arguments []cadence.Value, 51 ) ( 52 cadence.Value, 53 error, 54 ) { 55 contractLocation := common.AddressLocation{ 56 Address: common.Address(spec.AddressFromChain(sys.chain)), 57 Name: spec.LocationName, 58 } 59 60 span := sys.tracer.StartChildSpan(trace.FVMInvokeContractFunction) 61 span.SetAttributes( 62 attribute.String( 63 "transaction.ContractFunctionCall", 64 contractLocation.String()+"."+spec.FunctionName)) 65 defer span.End() 66 67 runtime := sys.runtime.BorrowCadenceRuntime() 68 defer sys.runtime.ReturnCadenceRuntime(runtime) 69 70 value, err := runtime.InvokeContractFunction( 71 contractLocation, 72 spec.FunctionName, 73 arguments, 74 spec.ArgumentTypes, 75 ) 76 if err != nil { 77 sys.logger.Logger(). 78 Info(). 79 Err(err). 80 Str("contract", contractLocation.String()). 81 Str("function", spec.FunctionName). 82 Msg("Contract function call executed with error") 83 } 84 return value, err 85 } 86 87 func FlowFeesAddress(chain flow.Chain) flow.Address { 88 address, _ := chain.AddressAtIndex(FlowFeesAccountIndex) 89 return address 90 } 91 92 func ServiceAddress(chain flow.Chain) flow.Address { 93 return chain.ServiceAddress() 94 } 95 96 var verifyPayersBalanceForTransactionExecutionSpec = ContractFunctionSpec{ 97 AddressFromChain: FlowFeesAddress, 98 LocationName: systemcontracts.ContractNameFlowFees, 99 FunctionName: systemcontracts.ContractServiceAccountFunction_verifyPayersBalanceForTransactionExecution, 100 ArgumentTypes: []sema.Type{ 101 sema.AuthAccountType, 102 sema.UInt64Type, 103 sema.UInt64Type, 104 }, 105 } 106 107 // CheckPayerBalanceAndGetMaxTxFees executes the verifyPayersBalanceForTransactionExecution 108 // on the FlowFees account. 109 // It checks whether the given payer has enough balance to cover inclusion fee and max execution 110 // fee. 111 // It returns (maxTransactionFee, ErrCodeInsufficientPayerBalance) if the payer doesn't have enough balance 112 // It returns (maxTransactionFee, nil) if the payer has enough balance 113 func (sys *SystemContracts) CheckPayerBalanceAndGetMaxTxFees( 114 payer flow.Address, 115 inclusionEffort uint64, 116 maxExecutionEffort uint64, 117 ) (cadence.Value, error) { 118 return sys.Invoke( 119 verifyPayersBalanceForTransactionExecutionSpec, 120 []cadence.Value{ 121 cadence.BytesToAddress(payer.Bytes()), 122 cadence.UFix64(inclusionEffort), 123 cadence.UFix64(maxExecutionEffort), 124 }, 125 ) 126 } 127 128 var deductTransactionFeeSpec = ContractFunctionSpec{ 129 AddressFromChain: FlowFeesAddress, 130 LocationName: systemcontracts.ContractNameFlowFees, 131 FunctionName: systemcontracts.ContractServiceAccountFunction_deductTransactionFee, 132 ArgumentTypes: []sema.Type{ 133 sema.AuthAccountType, 134 sema.UInt64Type, 135 sema.UInt64Type, 136 }, 137 } 138 139 // DeductTransactionFees executes the fee deduction function 140 // on the FlowFees account. 141 func (sys *SystemContracts) DeductTransactionFees( 142 payer flow.Address, 143 inclusionEffort uint64, 144 executionEffort uint64, 145 ) (cadence.Value, error) { 146 return sys.Invoke( 147 deductTransactionFeeSpec, 148 []cadence.Value{ 149 cadence.BytesToAddress(payer.Bytes()), 150 cadence.UFix64(inclusionEffort), 151 cadence.UFix64(executionEffort), 152 }, 153 ) 154 } 155 156 // uses `FlowServiceAccount.setupNewAccount` from https://github.com/onflow/flow-core-contracts/blob/master/contracts/FlowServiceAccount.cdc 157 var setupNewAccountSpec = ContractFunctionSpec{ 158 AddressFromChain: ServiceAddress, 159 LocationName: systemcontracts.ContractServiceAccount, 160 FunctionName: systemcontracts.ContractServiceAccountFunction_setupNewAccount, 161 ArgumentTypes: []sema.Type{ 162 sema.AuthAccountType, 163 sema.AuthAccountType, 164 }, 165 } 166 167 // SetupNewAccount executes the new account setup contract on the service 168 // account. 169 func (sys *SystemContracts) SetupNewAccount( 170 flowAddress flow.Address, 171 payer common.Address, 172 ) (cadence.Value, error) { 173 return sys.Invoke( 174 setupNewAccountSpec, 175 []cadence.Value{ 176 cadence.BytesToAddress(flowAddress.Bytes()), 177 cadence.BytesToAddress(payer.Bytes()), 178 }, 179 ) 180 } 181 182 var accountAvailableBalanceSpec = ContractFunctionSpec{ 183 AddressFromChain: ServiceAddress, 184 LocationName: systemcontracts.ContractStorageFees, 185 FunctionName: systemcontracts.ContractStorageFeesFunction_defaultTokenAvailableBalance, 186 ArgumentTypes: []sema.Type{ 187 &sema.AddressType{}, 188 }, 189 } 190 191 // AccountAvailableBalance executes the get available balance contract on the 192 // storage fees contract. 193 func (sys *SystemContracts) AccountAvailableBalance( 194 address common.Address, 195 ) (cadence.Value, error) { 196 return sys.Invoke( 197 accountAvailableBalanceSpec, 198 []cadence.Value{ 199 cadence.BytesToAddress(address.Bytes()), 200 }, 201 ) 202 } 203 204 var accountBalanceInvocationSpec = ContractFunctionSpec{ 205 AddressFromChain: ServiceAddress, 206 LocationName: systemcontracts.ContractServiceAccount, 207 FunctionName: systemcontracts.ContractServiceAccountFunction_defaultTokenBalance, 208 ArgumentTypes: []sema.Type{ 209 sema.PublicAccountType, 210 }, 211 } 212 213 // AccountBalance executes the get available balance contract on the service 214 // account. 215 func (sys *SystemContracts) AccountBalance( 216 address common.Address, 217 ) (cadence.Value, error) { 218 return sys.Invoke( 219 accountBalanceInvocationSpec, 220 []cadence.Value{ 221 cadence.BytesToAddress(address.Bytes()), 222 }, 223 ) 224 } 225 226 var accountStorageCapacitySpec = ContractFunctionSpec{ 227 AddressFromChain: ServiceAddress, 228 LocationName: systemcontracts.ContractStorageFees, 229 FunctionName: systemcontracts.ContractStorageFeesFunction_calculateAccountCapacity, 230 ArgumentTypes: []sema.Type{ 231 &sema.AddressType{}, 232 }, 233 } 234 235 // AccountStorageCapacity executes the get storage capacity contract on the 236 // service account. 237 func (sys *SystemContracts) AccountStorageCapacity( 238 address common.Address, 239 ) (cadence.Value, error) { 240 return sys.Invoke( 241 accountStorageCapacitySpec, 242 []cadence.Value{ 243 cadence.BytesToAddress(address.Bytes()), 244 }, 245 ) 246 } 247 248 // AccountsStorageCapacity gets storage capacity for multiple accounts at once. 249 func (sys *SystemContracts) AccountsStorageCapacity( 250 addresses []common.Address, 251 payer common.Address, 252 maxTxFees uint64, 253 ) (cadence.Value, error) { 254 arrayValues := make([]cadence.Value, len(addresses)) 255 for i, address := range addresses { 256 arrayValues[i] = cadence.BytesToAddress(address.Bytes()) 257 } 258 259 return sys.Invoke( 260 ContractFunctionSpec{ 261 AddressFromChain: ServiceAddress, 262 LocationName: systemcontracts.ContractStorageFees, 263 FunctionName: systemcontracts.ContractStorageFeesFunction_getAccountsCapacityForTransactionStorageCheck, 264 ArgumentTypes: []sema.Type{ 265 sema.NewConstantSizedType( 266 nil, 267 &sema.AddressType{}, 268 int64(len(arrayValues)), 269 ), 270 &sema.AddressType{}, 271 sema.UFix64Type, 272 }, 273 }, 274 []cadence.Value{ 275 cadence.NewArray(arrayValues), 276 cadence.BytesToAddress(payer.Bytes()), 277 cadence.UFix64(maxTxFees), 278 }, 279 ) 280 } 281 282 var useContractAuditVoucherSpec = ContractFunctionSpec{ 283 AddressFromChain: ServiceAddress, 284 LocationName: systemcontracts.ContractDeploymentAudits, 285 FunctionName: systemcontracts.ContractDeploymentAuditsFunction_useVoucherForDeploy, 286 ArgumentTypes: []sema.Type{ 287 &sema.AddressType{}, 288 sema.StringType, 289 }, 290 } 291 292 // UseContractAuditVoucher executes the use a contract deployment audit voucher 293 // contract. 294 func (sys *SystemContracts) UseContractAuditVoucher( 295 address common.Address, 296 code string, 297 ) (bool, error) { 298 resultCdc, err := sys.Invoke( 299 useContractAuditVoucherSpec, 300 []cadence.Value{ 301 cadence.BytesToAddress(address.Bytes()), 302 cadence.String(code), 303 }, 304 ) 305 if err != nil { 306 return false, err 307 } 308 result := resultCdc.(cadence.Bool).ToGoValue().(bool) 309 return result, nil 310 }