github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/fvm/environment/accounts_status.go (about)

     1  package environment
     2  
     3  import (
     4  	"encoding/binary"
     5  	"encoding/hex"
     6  
     7  	"github.com/onflow/atree"
     8  
     9  	"github.com/onflow/flow-go/fvm/errors"
    10  )
    11  
    12  const (
    13  	flagSize             = 1
    14  	storageUsedSize      = 8
    15  	storageIndexSize     = 8
    16  	publicKeyCountsSize  = 8
    17  	addressIdCounterSize = 8
    18  
    19  	// oldAccountStatusSize is the size of the account status before the address
    20  	// id counter was added. After v0.32.0 check if it can be removed as all accounts
    21  	// should then have the new status sile len.
    22  	oldAccountStatusSize = flagSize +
    23  		storageUsedSize +
    24  		storageIndexSize +
    25  		publicKeyCountsSize
    26  
    27  	accountStatusSize = flagSize +
    28  		storageUsedSize +
    29  		storageIndexSize +
    30  		publicKeyCountsSize +
    31  		addressIdCounterSize
    32  
    33  	flagIndex                  = 0
    34  	storageUsedStartIndex      = flagIndex + flagSize
    35  	storageIndexStartIndex     = storageUsedStartIndex + storageUsedSize
    36  	publicKeyCountsStartIndex  = storageIndexStartIndex + storageIndexSize
    37  	addressIdCounterStartIndex = publicKeyCountsStartIndex + publicKeyCountsSize
    38  )
    39  
    40  // AccountStatus holds meta information about an account
    41  //
    42  // currently modelled as a byte array with on-demand encoding/decoding of sub arrays
    43  // the first byte captures flags
    44  // the next 8 bytes (big-endian) captures storage used by an account
    45  // the next 8 bytes (big-endian) captures the storage index of an account
    46  // the next 8 bytes (big-endian) captures the number of public keys stored on this account
    47  // the next 8 bytes (big-endian) captures the current address id counter
    48  type AccountStatus [accountStatusSize]byte
    49  
    50  // NewAccountStatus returns a new AccountStatus
    51  // sets the storage index to the init value
    52  func NewAccountStatus() *AccountStatus {
    53  	return &AccountStatus{
    54  		0,                      // initial empty flags
    55  		0, 0, 0, 0, 0, 0, 0, 0, // init value for storage used
    56  		0, 0, 0, 0, 0, 0, 0, 1, // init value for storage index
    57  		0, 0, 0, 0, 0, 0, 0, 0, // init value for public key counts
    58  		0, 0, 0, 0, 0, 0, 0, 0, // init value for address id counter
    59  	}
    60  }
    61  
    62  // ToBytes converts AccountStatus to a byte slice
    63  //
    64  // this has been kept this way in case one day
    65  // we decided to move on to use a struct to represent
    66  // account status.
    67  func (a *AccountStatus) ToBytes() []byte {
    68  	return a[:]
    69  }
    70  
    71  // AccountStatusFromBytes constructs an AccountStatus from the given byte slice
    72  func AccountStatusFromBytes(inp []byte) (*AccountStatus, error) {
    73  	var as AccountStatus
    74  
    75  	if len(inp) == oldAccountStatusSize {
    76  		// pad the input with zeros
    77  		// this is to migrate old account status to new account status on the fly
    78  		// TODO: remove this whole block after v0.32.0, when a full migration will
    79  		// be made.
    80  		sizeIncrease := uint64(accountStatusSize - oldAccountStatusSize)
    81  
    82  		// But we also need to fix the storage used by the appropriate size because
    83  		// the storage used is part of the account status itself.
    84  		copy(as[:], inp)
    85  		used := as.StorageUsed()
    86  		as.SetStorageUsed(used + sizeIncrease)
    87  		return &as, nil
    88  	}
    89  
    90  	if len(inp) != accountStatusSize {
    91  		return &as, errors.NewValueErrorf(hex.EncodeToString(inp), "invalid account status size")
    92  	}
    93  	copy(as[:], inp)
    94  	return &as, nil
    95  }
    96  
    97  // SetStorageUsed updates the storage used by the account
    98  func (a *AccountStatus) SetStorageUsed(used uint64) {
    99  	binary.BigEndian.PutUint64(a[storageUsedStartIndex:storageUsedStartIndex+storageUsedSize], used)
   100  }
   101  
   102  // StorageUsed returns the storage used by the account
   103  func (a *AccountStatus) StorageUsed() uint64 {
   104  	return binary.BigEndian.Uint64(a[storageUsedStartIndex : storageUsedStartIndex+storageUsedSize])
   105  }
   106  
   107  // SetStorageIndex updates the storage index of the account
   108  func (a *AccountStatus) SetStorageIndex(index atree.SlabIndex) {
   109  	copy(a[storageIndexStartIndex:storageIndexStartIndex+storageIndexSize], index[:storageIndexSize])
   110  }
   111  
   112  // StorageIndex returns the storage index of the account
   113  func (a *AccountStatus) StorageIndex() atree.SlabIndex {
   114  	var index atree.SlabIndex
   115  	copy(index[:], a[storageIndexStartIndex:storageIndexStartIndex+storageIndexSize])
   116  	return index
   117  }
   118  
   119  // SetPublicKeyCount updates the public key count of the account
   120  func (a *AccountStatus) SetPublicKeyCount(count uint64) {
   121  	binary.BigEndian.PutUint64(a[publicKeyCountsStartIndex:publicKeyCountsStartIndex+publicKeyCountsSize], count)
   122  }
   123  
   124  // PublicKeyCount returns the public key count of the account
   125  func (a *AccountStatus) PublicKeyCount() uint64 {
   126  	return binary.BigEndian.Uint64(a[publicKeyCountsStartIndex : publicKeyCountsStartIndex+publicKeyCountsSize])
   127  }
   128  
   129  // SetAccountIdCounter updates id counter of the account
   130  func (a *AccountStatus) SetAccountIdCounter(id uint64) {
   131  	binary.BigEndian.PutUint64(a[addressIdCounterStartIndex:addressIdCounterStartIndex+addressIdCounterSize], id)
   132  }
   133  
   134  // AccountIdCounter returns id counter of the account
   135  func (a *AccountStatus) AccountIdCounter() uint64 {
   136  	return binary.BigEndian.Uint64(a[addressIdCounterStartIndex : addressIdCounterStartIndex+addressIdCounterSize])
   137  }