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  }