github.com/onflow/flow-go@v0.33.17/fvm/transactionPayerBalanceChecker.go (about) 1 package fvm 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence" 7 8 "github.com/onflow/flow-go/fvm/environment" 9 "github.com/onflow/flow-go/fvm/errors" 10 "github.com/onflow/flow-go/fvm/storage" 11 ) 12 13 type TransactionPayerBalanceChecker struct{} 14 15 func (_ TransactionPayerBalanceChecker) CheckPayerBalanceAndReturnMaxFees( 16 proc *TransactionProcedure, 17 txnState storage.TransactionPreparer, 18 env environment.Environment, 19 ) (uint64, error) { 20 if !env.TransactionFeesEnabled() { 21 // if the transaction fees are not enabled, 22 // the payer can pay for the transaction, 23 // and the max transaction fees are 0. 24 // This is also the condition that gets hit during bootstrapping. 25 return 0, nil 26 } 27 28 var resultValue cadence.Value 29 var err error 30 txnState.RunWithAllLimitsDisabled(func() { 31 // Don't meter the payer balance check. 32 // It has a static cost, and its cost should be part of the inclusion fees, not part of execution fees. 33 resultValue, err = env.CheckPayerBalanceAndGetMaxTxFees( 34 proc.Transaction.Payer, 35 proc.Transaction.InclusionEffort(), 36 uint64(txnState.TotalComputationLimit()), 37 ) 38 }) 39 if err != nil { 40 return 0, errors.NewPayerBalanceCheckFailure(proc.Transaction.Payer, err) 41 } 42 43 // parse expected result from the Cadence runtime 44 // https://github.com/onflow/flow-core-contracts/blob/7c70c6a1d33c2879b60c78e363fa68fc6fce13b9/contracts/FlowFees.cdc#L75 45 result, ok := resultValue.(cadence.Struct) 46 if ok && len(result.Fields) == 3 { 47 payerCanPay, okBool := result.Fields[0].(cadence.Bool) 48 requiredBalance, okBalance := result.Fields[1].(cadence.UFix64) 49 maxFees, okFees := result.Fields[2].(cadence.UFix64) 50 51 if okBool && okBalance && okFees { 52 if !payerCanPay { 53 return 0, errors.NewInsufficientPayerBalanceError(proc.Transaction.Payer, requiredBalance) 54 } 55 return uint64(maxFees), nil 56 } 57 } 58 59 return 0, errors.NewPayerBalanceCheckFailure(proc.Transaction.Payer, fmt.Errorf("invalid result type")) 60 }