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