github.com/koko1123/flow-go-1@v0.29.6/fvm/transactionStorageLimiter.go (about) 1 package fvm 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence" 7 "github.com/onflow/cadence/runtime/common" 8 9 "github.com/koko1123/flow-go-1/fvm/environment" 10 "github.com/koko1123/flow-go-1/fvm/errors" 11 "github.com/koko1123/flow-go-1/model/flow" 12 "github.com/koko1123/flow-go-1/module/trace" 13 ) 14 15 type TransactionStorageLimiter struct{} 16 17 // CheckStorageLimits checks each account that had its storage written to during a transaction, that its storage used 18 // is less than its storage capacity. 19 // Storage used is an FVM register and is easily accessible. 20 // Storage capacity is calculated by the FlowStorageFees contract from the account's flow balance. 21 // 22 // The payers balance is considered to be maxTxFees lower that its actual balance, due to the fact that 23 // the fee deduction step happens after the storage limit check. 24 func (d TransactionStorageLimiter) CheckStorageLimits( 25 env environment.Environment, 26 addresses []flow.Address, 27 payer flow.Address, 28 maxTxFees uint64, 29 ) error { 30 if !env.LimitAccountStorage() { 31 return nil 32 } 33 34 defer env.StartChildSpan(trace.FVMTransactionStorageUsedCheck).End() 35 36 err := d.checkStorageLimits(env, addresses, payer, maxTxFees) 37 if err != nil { 38 return fmt.Errorf("storage limit check failed: %w", err) 39 } 40 return nil 41 } 42 43 func (d TransactionStorageLimiter) checkStorageLimits( 44 env environment.Environment, 45 addresses []flow.Address, 46 payer flow.Address, 47 maxTxFees uint64, 48 ) error { 49 // in case the payer is not already part of the check, include it here. 50 // If the maxTxFees is zero, it doesn't matter if the payer is included or not. 51 if maxTxFees > 0 { 52 commonAddressesContainPayer := false 53 for _, address := range addresses { 54 if address == payer { 55 commonAddressesContainPayer = true 56 break 57 } 58 } 59 60 if !commonAddressesContainPayer { 61 addresses = append(addresses, payer) 62 } 63 } 64 65 commonAddresses := make([]common.Address, len(addresses)) 66 usages := make([]uint64, len(commonAddresses)) 67 68 for i, address := range addresses { 69 ca := common.Address(address) 70 u, err := env.GetStorageUsed(ca) 71 if err != nil { 72 return err 73 } 74 75 commonAddresses[i] = ca 76 usages[i] = u 77 } 78 79 result, invokeErr := env.AccountsStorageCapacity( 80 commonAddresses, 81 common.Address(payer), 82 maxTxFees, 83 ) 84 85 // This error only occurs in case of implementation errors. The InvokeAccountsStorageCapacity 86 // already handles cases where the default vault is missing. 87 if invokeErr != nil { 88 return invokeErr 89 } 90 91 // the resultArray elements are in the same order as the addresses and the addresses are deterministically sorted 92 resultArray, ok := result.(cadence.Array) 93 if !ok { 94 return fmt.Errorf("AccountsStorageCapacity did not return an array") 95 } 96 97 for i, value := range resultArray.Values { 98 capacity := environment.StorageMBUFixToBytesUInt(value) 99 100 if usages[i] > capacity { 101 return errors.NewStorageCapacityExceededError(flow.BytesToAddress(addresses[i].Bytes()), usages[i], capacity) 102 } 103 } 104 105 return nil 106 }