github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/account_info.go (about) 1 package environment 2 3 import ( 4 "fmt" 5 6 "github.com/onflow/cadence" 7 "github.com/onflow/cadence/runtime/common" 8 9 "github.com/onflow/flow-go/fvm/storage/state" 10 "github.com/onflow/flow-go/fvm/tracing" 11 "github.com/onflow/flow-go/model/flow" 12 "github.com/onflow/flow-go/module/trace" 13 ) 14 15 // AccountInfo exposes various account balance and storage statistics. 16 type AccountInfo interface { 17 // Cadence's runtime APIs. 18 GetStorageUsed(runtimeaddress common.Address) (uint64, error) 19 GetStorageCapacity(runtimeAddress common.Address) (uint64, error) 20 GetAccountBalance(runtimeAddress common.Address) (uint64, error) 21 GetAccountAvailableBalance(runtimeAddress common.Address) (uint64, error) 22 23 GetAccount(address flow.Address) (*flow.Account, error) 24 } 25 26 type ParseRestrictedAccountInfo struct { 27 txnState state.NestedTransactionPreparer 28 impl AccountInfo 29 } 30 31 func NewParseRestrictedAccountInfo( 32 txnState state.NestedTransactionPreparer, 33 impl AccountInfo, 34 ) AccountInfo { 35 return ParseRestrictedAccountInfo{ 36 txnState: txnState, 37 impl: impl, 38 } 39 } 40 41 func (info ParseRestrictedAccountInfo) GetStorageUsed( 42 runtimeAddress common.Address, 43 ) ( 44 uint64, 45 error, 46 ) { 47 return parseRestrict1Arg1Ret( 48 info.txnState, 49 trace.FVMEnvGetStorageUsed, 50 info.impl.GetStorageUsed, 51 runtimeAddress) 52 } 53 54 func (info ParseRestrictedAccountInfo) GetStorageCapacity( 55 runtimeAddress common.Address, 56 ) ( 57 uint64, 58 error, 59 ) { 60 return parseRestrict1Arg1Ret( 61 info.txnState, 62 trace.FVMEnvGetStorageCapacity, 63 info.impl.GetStorageCapacity, 64 runtimeAddress) 65 } 66 67 func (info ParseRestrictedAccountInfo) GetAccountBalance( 68 runtimeAddress common.Address, 69 ) ( 70 uint64, 71 error, 72 ) { 73 return parseRestrict1Arg1Ret( 74 info.txnState, 75 trace.FVMEnvGetAccountBalance, 76 info.impl.GetAccountBalance, 77 runtimeAddress) 78 } 79 80 func (info ParseRestrictedAccountInfo) GetAccountAvailableBalance( 81 runtimeAddress common.Address, 82 ) ( 83 uint64, 84 error, 85 ) { 86 return parseRestrict1Arg1Ret( 87 info.txnState, 88 trace.FVMEnvGetAccountAvailableBalance, 89 info.impl.GetAccountAvailableBalance, 90 runtimeAddress) 91 } 92 93 func (info ParseRestrictedAccountInfo) GetAccount( 94 address flow.Address, 95 ) ( 96 *flow.Account, 97 error, 98 ) { 99 return parseRestrict1Arg1Ret( 100 info.txnState, 101 trace.FVMEnvGetAccount, 102 info.impl.GetAccount, 103 address) 104 } 105 106 type accountInfo struct { 107 tracer tracing.TracerSpan 108 meter Meter 109 110 accounts Accounts 111 systemContracts *SystemContracts 112 113 serviceAccountEnabled bool 114 } 115 116 func NewAccountInfo( 117 tracer tracing.TracerSpan, 118 meter Meter, 119 accounts Accounts, 120 systemContracts *SystemContracts, 121 serviceAccountEnabled bool, 122 ) AccountInfo { 123 return &accountInfo{ 124 tracer: tracer, 125 meter: meter, 126 accounts: accounts, 127 systemContracts: systemContracts, 128 serviceAccountEnabled: serviceAccountEnabled, 129 } 130 } 131 132 func (info *accountInfo) GetStorageUsed( 133 runtimeAddress common.Address, 134 ) ( 135 uint64, 136 error, 137 ) { 138 defer info.tracer.StartChildSpan(trace.FVMEnvGetStorageUsed).End() 139 140 err := info.meter.MeterComputation(ComputationKindGetStorageUsed, 1) 141 if err != nil { 142 return 0, fmt.Errorf("get storage used failed: %w", err) 143 } 144 145 value, err := info.accounts.GetStorageUsed( 146 flow.ConvertAddress(runtimeAddress)) 147 if err != nil { 148 return 0, fmt.Errorf("get storage used failed: %w", err) 149 } 150 151 return value, nil 152 } 153 154 // StorageMBUFixToBytesUInt converts the return type of storage capacity which 155 // is a UFix64 with the unit of megabytes to UInt with the unit of bytes 156 func StorageMBUFixToBytesUInt(result cadence.Value) uint64 { 157 // Divide the unsigned int by (1e8 (the scale of Fix64) / 1e6 (for mega)) 158 // to get bytes (rounded down) 159 return uint64(result.(cadence.UFix64) / 100) 160 } 161 162 func (info *accountInfo) GetStorageCapacity( 163 runtimeAddress common.Address, 164 ) ( 165 uint64, 166 error, 167 ) { 168 defer info.tracer.StartChildSpan(trace.FVMEnvGetStorageCapacity).End() 169 170 err := info.meter.MeterComputation(ComputationKindGetStorageCapacity, 1) 171 if err != nil { 172 return 0, fmt.Errorf("get storage capacity failed: %w", err) 173 } 174 175 result, invokeErr := info.systemContracts.AccountStorageCapacity( 176 flow.ConvertAddress(runtimeAddress)) 177 if invokeErr != nil { 178 return 0, invokeErr 179 } 180 181 // Return type is actually a UFix64 with the unit of megabytes so some 182 // conversion is necessary divide the unsigned int by (1e8 (the scale of 183 // Fix64) / 1e6 (for mega)) to get bytes (rounded down) 184 return StorageMBUFixToBytesUInt(result), nil 185 } 186 187 func (info *accountInfo) GetAccountBalance( 188 runtimeAddress common.Address, 189 ) ( 190 uint64, 191 error, 192 ) { 193 defer info.tracer.StartChildSpan(trace.FVMEnvGetAccountBalance).End() 194 195 err := info.meter.MeterComputation(ComputationKindGetAccountBalance, 1) 196 if err != nil { 197 return 0, fmt.Errorf("get account balance failed: %w", err) 198 } 199 200 result, invokeErr := info.systemContracts.AccountBalance(flow.ConvertAddress(runtimeAddress)) 201 if invokeErr != nil { 202 return 0, invokeErr 203 } 204 205 return uint64(result.(cadence.UFix64)), nil 206 } 207 208 func (info *accountInfo) GetAccountAvailableBalance( 209 runtimeAddress common.Address, 210 ) ( 211 uint64, 212 error, 213 ) { 214 defer info.tracer.StartChildSpan( 215 trace.FVMEnvGetAccountAvailableBalance).End() 216 217 err := info.meter.MeterComputation( 218 ComputationKindGetAccountAvailableBalance, 219 1) 220 if err != nil { 221 return 0, fmt.Errorf("get account available balance failed: %w", err) 222 } 223 224 result, invokeErr := info.systemContracts.AccountAvailableBalance(flow.ConvertAddress(runtimeAddress)) 225 if invokeErr != nil { 226 return 0, invokeErr 227 } 228 229 return uint64(result.(cadence.UFix64)), nil 230 } 231 232 func (info *accountInfo) GetAccount( 233 address flow.Address, 234 ) ( 235 *flow.Account, 236 error, 237 ) { 238 defer info.tracer.StartChildSpan(trace.FVMEnvGetAccount).End() 239 240 account, err := info.accounts.Get(address) 241 if err != nil { 242 return nil, err 243 } 244 245 if info.serviceAccountEnabled { 246 balance, err := info.GetAccountBalance( 247 common.MustBytesToAddress(address.Bytes())) 248 if err != nil { 249 return nil, err 250 } 251 252 account.Balance = balance 253 } 254 255 return account, nil 256 }