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  }