Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
8 changes: 4 additions & 4 deletions 8 cmd/util/cmd/check-storage/account_key_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,20 @@ func validateAccountStatusRegister(
accountPublicKeyCount = accountStatus.AccountPublicKeyCount()

if accountPublicKeyCount <= 1 {
if len(encodedAccountStatus) != environment.AccountStatusMinSizeV4 {
err = fmt.Errorf("account status register size is %d, expect %d bytes", len(encodedAccountStatus), environment.AccountStatusMinSizeV4)
if len(encodedAccountStatus) != environment.AccountStatusMinSize {
err = fmt.Errorf("account status register size is %d, expect %d bytes", len(encodedAccountStatus), environment.AccountStatusMinSize)
return
}
storedKeyCount = accountPublicKeyCount
return
}

weightAndRevokedStatus, startKeyIndexForMapping, accountPublicKeyMappings, startKeyIndexForDigests, digests, err := accountkeymetadata.DecodeKeyMetadata(
encodedAccountStatus[environment.AccountStatusMinSizeV4:],
encodedAccountStatus[environment.AccountStatusMinSize:],
deduplicated,
)
if err != nil {
err = fmt.Errorf("failed to parse key metadata %x: %s", encodedAccountStatus[environment.AccountStatusMinSizeV4:], err)
err = fmt.Errorf("failed to parse key metadata %x: %s", encodedAccountStatus[environment.AccountStatusMinSize:], err)
return
}

Expand Down
64 changes: 0 additions & 64 deletions 64 cmd/util/ledger/migrations/storage_used_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,70 +71,6 @@ func TestAccountStatusMigration(t *testing.T) {
require.Error(t, err)
})

t.Run("status register v1", func(t *testing.T) {
t.Parallel()

accountPublicKeyCount := uint32(5)
statusPayloadAndSequenceNubmerSize := sizeOfTheStatusPayload +
predefinedSequenceNumberPayloadSizes(string(address[:]), 1, accountPublicKeyCount)

payloads := []*ledger.Payload{
ledger.NewPayload(
ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: []byte(flow.AccountStatusKey)}}),
[]byte{
0, // flags
0, 0, 0, 0, 0, 0, 0, 7, // storage used
0, 0, 0, 0, 0, 0, 0, 6, // storage index
0, 0, 0, 0, 0, 0, 0, 5, // public key counts
},
),
}

migrated, err := migrate(payloads)
require.NoError(t, err)
require.Len(t, migrated, 1)

accountStatus, err := environment.AccountStatusFromBytes(migrated[0].Value())
require.NoError(t, err)

require.Equal(t, statusPayloadAndSequenceNubmerSize, accountStatus.StorageUsed())
require.Equal(t, atree.SlabIndex{0, 0, 0, 0, 0, 0, 0, 6}, accountStatus.SlabIndex())
require.Equal(t, accountPublicKeyCount, accountStatus.AccountPublicKeyCount())
require.Equal(t, uint64(0), accountStatus.AccountIdCounter())
})
t.Run("status register v2", func(t *testing.T) {
t.Parallel()

accountPublicKeyCount := uint32(5)
statusPayloadAndSequenceNubmerSize := sizeOfTheStatusPayload +
predefinedSequenceNumberPayloadSizes(string(address[:]), 1, accountPublicKeyCount)

payloads := []*ledger.Payload{
ledger.NewPayload(
ledger.NewKey([]ledger.KeyPart{ownerKey, {Type: 2, Value: []byte(flow.AccountStatusKey)}}),
[]byte{
0, // flags
0, 0, 0, 0, 0, 0, 0, 100, // storage used
0, 0, 0, 0, 0, 0, 0, 6, // storage index
0, 0, 0, 0, 0, 0, 0, 5, // public key counts
0, 0, 0, 0, 0, 0, 0, 3, // account id counter
},
),
}

migrated, err := migrate(payloads)
require.NoError(t, err)
require.Len(t, migrated, 1)

accountStatus, err := environment.AccountStatusFromBytes(migrated[0].Value())
require.NoError(t, err)

require.Equal(t, statusPayloadAndSequenceNubmerSize, accountStatus.StorageUsed())
require.Equal(t, atree.SlabIndex{0, 0, 0, 0, 0, 0, 0, 6}, accountStatus.SlabIndex())
require.Equal(t, accountPublicKeyCount, accountStatus.AccountPublicKeyCount())
require.Equal(t, uint64(3), accountStatus.AccountIdCounter())
})

t.Run("status register v3", func(t *testing.T) {
t.Parallel()

Expand Down
166 changes: 32 additions & 134 deletions 166 fvm/environment/accounts_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,13 @@ import (
)

const (
flagSize = 1
storageUsedSize = 8
storageIndexSize = 8
oldAccountPublicKeyCountsSize = 8
accountPublicKeyCountsSize = 4
addressIdCounterSize = 8

// accountStatusSizeV1 is the size of the account status before the address
// id counter was added. After Crescendo check if it can be removed as all accounts
// should then have the new status sile len.
accountStatusSizeV1 = flagSize +
storageUsedSize +
storageIndexSize +
oldAccountPublicKeyCountsSize

// accountStatusSizeV2 is the size of the account status before
// the public key count was changed from 8 to 4 bytes long.
// After Crescendo check if it can be removed as all accounts
// should then have the new status sile len.
accountStatusSizeV2 = flagSize +
storageUsedSize +
storageIndexSize +
oldAccountPublicKeyCountsSize +
addressIdCounterSize
flagSize = 1
storageUsedSize = 8
storageIndexSize = 8
accountPublicKeyCountsSize = 4
addressIdCounterSize = 8

accountStatusSizeV3 = flagSize +
AccountStatusMinSize = flagSize +
storageUsedSize +
storageIndexSize +
accountPublicKeyCountsSize +
Expand All @@ -53,8 +34,6 @@ const (
deduplicationFlagMask = 0x01

accountStatusV4DefaultVersionAndFlag = 0x40

AccountStatusMinSizeV4 = accountStatusSizeV3
)

const (
Expand All @@ -69,25 +48,25 @@ const (
// the next 8 bytes (big-endian) captures the storage index of an account
// the next 4 bytes (big-endian) captures the number of public keys stored on this account
// the next 8 bytes (big-endian) captures the current address id counter
type accountStatusV3 [accountStatusSizeV3]byte
type accountStatusPacked [AccountStatusMinSize]byte

type AccountStatus struct {
accountStatusV3
accountStatusPacked
keyMetadataBytes []byte
}

// NewAccountStatus returns a new AccountStatus
// sets the storage index to the init value
func NewAccountStatus() *AccountStatus {
as := accountStatusV3{
as := accountStatusPacked{
accountStatusV4DefaultVersionAndFlag, // initial empty flags
0, 0, 0, 0, 0, 0, 0, 0, // init value for storage used
0, 0, 0, 0, 0, 0, 0, 1, // init value for storage index
0, 0, 0, 0, // init value for public key counts
0, 0, 0, 0, 0, 0, 0, 0, // init value for address id counter
}
return &AccountStatus{
accountStatusV3: as,
accountStatusPacked: as,
}
}

Expand All @@ -98,169 +77,88 @@ func NewAccountStatus() *AccountStatus {
// account status.
func (a *AccountStatus) ToBytes() []byte {
if len(a.keyMetadataBytes) == 0 {
return a.accountStatusV3[:]
return a.accountStatusPacked[:]
}
return append(a.accountStatusV3[:], a.keyMetadataBytes...)
return append(a.accountStatusPacked[:], a.keyMetadataBytes...)
}

// AccountStatusFromBytes constructs an AccountStatus from the given byte slice
func AccountStatusFromBytes(inp []byte) (*AccountStatus, error) {
asv3, rest, err := accountStatusV3FromBytes(inp)
as, rest, err := accountStatusFromBytes(inp)
if err != nil {
return nil, err
}

// NOTE: both accountStatusV3 and keyMetadataBytes are copies.
// NOTE: both accountStatusPacked and keyMetadataBytes are copies.
return &AccountStatus{
accountStatusV3: asv3,
keyMetadataBytes: append([]byte(nil), rest...),
accountStatusPacked: as,
keyMetadataBytes: append([]byte(nil), rest...),
}, nil
}

func accountStatusV3FromBytes(inp []byte) (accountStatusV3, []byte, error) {
sizeChange := int64(0)

// this is to migrate old account status to new account status on the fly
// TODO: remove this whole block after Crescendo, when a full migration will be made.
if len(inp) == accountStatusSizeV1 {
// migrate v1 to v2
inp2 := make([]byte, accountStatusSizeV2)

// pad the input with zeros
sizeIncrease := int64(accountStatusSizeV2 - accountStatusSizeV1)

// But we also need to fix the storage used by the appropriate size because
// the storage used is part of the account status itself.
copy(inp2, inp)
sizeChange = sizeIncrease

inp = inp2
func accountStatusFromBytes(inp []byte) (accountStatusPacked, []byte, error) {
if len(inp) < AccountStatusMinSize {
return accountStatusPacked{}, nil, errors.NewValueErrorf(hex.EncodeToString(inp), "invalid account status size")
}

// this is to migrate old account status to new account status on the fly
// TODO: remove this whole block after Crescendo, when a full migration will be made.
if len(inp) == accountStatusSizeV2 {
// migrate v2 to v3

inp2 := make([]byte, accountStatusSizeV2)
// copy the old account status first, so that we don't slice the input
copy(inp2, inp)

// cut leading 4 bytes of old public key count.
cutStart := flagSize +
storageUsedSize +
storageIndexSize

cutEnd := flagSize +
storageUsedSize +
storageIndexSize +
(oldAccountPublicKeyCountsSize - accountPublicKeyCountsSize)

// check if the public key count is larger than 4 bytes
for i := cutStart; i < cutEnd; i++ {
if inp2[i] != 0 {
return accountStatusV3{}, nil, fmt.Errorf("cannot migrate account status from v2 to v3: public key count is larger than 4 bytes %v, %v", hex.EncodeToString(inp2[flagSize+
storageUsedSize+
storageIndexSize:flagSize+
storageUsedSize+
storageIndexSize+
oldAccountPublicKeyCountsSize]), inp2[i])
}
}

inp2 = append(inp2[:cutStart], inp2[cutEnd:]...)

sizeDecrease := int64(accountStatusSizeV2 - accountStatusSizeV3)

// But we also need to fix the storage used by the appropriate size because
// the storage used is part of the account status itself.
sizeChange -= sizeDecrease

inp = inp2
}

if len(inp) < accountStatusSizeV3 {
return accountStatusV3{}, nil, errors.NewValueErrorf(hex.EncodeToString(inp), "invalid account status size")
}

inp, rest := inp[:accountStatusSizeV3], inp[accountStatusSizeV3:]

var as accountStatusV3
inp, rest := inp[:AccountStatusMinSize], inp[AccountStatusMinSize:]
var as accountStatusPacked
copy(as[:], inp)

if sizeChange != 0 {
used := as.StorageUsed()

if sizeChange < 0 {
// check if the storage used is smaller than the size change
if used < uint64(-sizeChange) {
return accountStatusV3{}, nil, errors.NewValueErrorf(hex.EncodeToString(inp), "account would have negative storage used after migration")
}

used = used - uint64(-sizeChange)
}

if sizeChange > 0 {
used = used + uint64(sizeChange)
}

as.SetStorageUsed(used)
}

return as, rest, nil
}

func (a *accountStatusV3) Version() uint8 {
func (a *accountStatusPacked) Version() uint8 {
return (a[0] & versionMask) >> 4
}

func (a *accountStatusV3) IsAccountKeyDeduplicated() bool {
func (a *accountStatusPacked) IsAccountKeyDeduplicated() bool {
return (a[0] & deduplicationFlagMask) != 0
}

func (a *accountStatusV3) setAccountKeyDeduplicationFlag() {
func (a *accountStatusPacked) setAccountKeyDeduplicationFlag() {
a[0] |= deduplicationFlagMask
}

// SetStorageUsed updates the storage used by the account
func (a *accountStatusV3) SetStorageUsed(used uint64) {
func (a *accountStatusPacked) SetStorageUsed(used uint64) {
binary.BigEndian.PutUint64(a[storageUsedStartIndex:storageUsedStartIndex+storageUsedSize], used)
}

// StorageUsed returns the storage used by the account
func (a *accountStatusV3) StorageUsed() uint64 {
func (a *accountStatusPacked) StorageUsed() uint64 {
return binary.BigEndian.Uint64(a[storageUsedStartIndex : storageUsedStartIndex+storageUsedSize])
}

// SetStorageIndex updates the storage index of the account
func (a *accountStatusV3) SetStorageIndex(index atree.SlabIndex) {
func (a *accountStatusPacked) SetStorageIndex(index atree.SlabIndex) {
copy(a[storageIndexStartIndex:storageIndexStartIndex+storageIndexSize], index[:storageIndexSize])
}

// SlabIndex returns the storage index of the account
func (a *accountStatusV3) SlabIndex() atree.SlabIndex {
func (a *accountStatusPacked) SlabIndex() atree.SlabIndex {
var index atree.SlabIndex
copy(index[:], a[storageIndexStartIndex:storageIndexStartIndex+storageIndexSize])
return index
}

// SetAccountPublicKeyCount updates the account public key count of the account
func (a *accountStatusV3) SetAccountPublicKeyCount(count uint32) {
func (a *accountStatusPacked) SetAccountPublicKeyCount(count uint32) {
binary.BigEndian.PutUint32(a[accountPublicKeyCountsStartIndex:accountPublicKeyCountsStartIndex+accountPublicKeyCountsSize], count)
}

// AccountPublicKeyCount returns the account public key count of the account
func (a *accountStatusV3) AccountPublicKeyCount() uint32 {
func (a *accountStatusPacked) AccountPublicKeyCount() uint32 {
return binary.BigEndian.Uint32(a[accountPublicKeyCountsStartIndex : accountPublicKeyCountsStartIndex+accountPublicKeyCountsSize])
}

// SetAccountIdCounter updates id counter of the account
func (a *accountStatusV3) SetAccountIdCounter(id uint64) {
func (a *accountStatusPacked) SetAccountIdCounter(id uint64) {
binary.BigEndian.PutUint64(a[addressIdCounterStartIndex:addressIdCounterStartIndex+addressIdCounterSize], id)
}

// AccountIdCounter returns id counter of the account
func (a *accountStatusV3) AccountIdCounter() uint64 {
func (a *accountStatusPacked) AccountIdCounter() uint64 {
return binary.BigEndian.Uint64(a[addressIdCounterStartIndex : addressIdCounterStartIndex+addressIdCounterSize])
}

Expand Down
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.