Skip to content

Commit

Permalink
Merge pull request #3072 from onflow/bastian/support-link-value-migra…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
turbolent authored Feb 5, 2024
2 parents 119f7cd + b235b73 commit 55925d1
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 175 deletions.
118 changes: 0 additions & 118 deletions migrations/capcons/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1865,121 +1865,3 @@ func TestLinkMigration(t *testing.T) {
test(linkTestCase)
}
}

func TestClearPrivateDomain(t *testing.T) {

t.Parallel()

pathLinks := []testLink{
{
// Equivalent to:
// link<&Test.R>(/public/test1, target: /private/test2)
sourcePath: interpreter.PathValue{
Domain: common.PathDomainPublic,
Identifier: "test1",
},
targetPath: interpreter.PathValue{
Domain: common.PathDomainPrivate,
Identifier: "test2",
},
borrowType: testRReferenceStaticType,
},
{
// Equivalent to:
// link<&Test.R>(/private/test3, target: /storage/test4)
sourcePath: interpreter.PathValue{
Domain: common.PathDomainPrivate,
Identifier: "test3",
},
targetPath: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: "test4",
},
borrowType: testRReferenceStaticType,
},
}

accountLinks := []interpreter.PathValue{
// Equivalent to:
// linkAccount(/public/test5)
{
Domain: common.PathDomainPublic,
Identifier: "test5",
},
// Equivalent to:
// linkAccount(/private/test6)
{
Domain: common.PathDomainPrivate,
Identifier: "test6",
},
}

rt := NewTestInterpreterRuntime()

runtimeInterface := &TestRuntimeInterface{
Storage: NewTestLedger(nil, nil),
}

// Create and store path and account links

storage, inter, err := rt.Storage(runtime.Context{
Interface: runtimeInterface,
})
require.NoError(t, err)

storeTestPathLinks(t, pathLinks, storage, inter)

storeTestAccountLinks(accountLinks, storage, inter)

require.Equal(t,
uint64(2),
storage.GetStorageMap(testAddress, common.PathDomainPublic.Identifier(), false).Count(),
)
require.Equal(t,
uint64(2),
storage.GetStorageMap(testAddress, common.PathDomainPrivate.Identifier(), false).Count(),
)

err = storage.Commit(inter, false)
require.NoError(t, err)

// Migrate

migration := migrations.NewStorageMigration(inter, storage)

migration.Migrate(
&migrations.AddressSliceIterator{
Addresses: []common.Address{
testAddress,
},
},
ClearPrivateDomain,
)

err = migration.Commit()
require.NoError(t, err)

// Assert

// Check that the private domain was cleared

privateStorageMap := storage.GetStorageMap(
testAddress,
common.PathDomainPrivate.Identifier(),
false,
)

assert.Zero(t, privateStorageMap.Count())

// Check that the public domain was not cleared

publicStorageMap := storage.GetStorageMap(
testAddress,
common.PathDomainPublic.Identifier(),
false,
)

assert.Equal(t, uint64(2), publicStorageMap.Count())
assert.True(t, publicStorageMap.ValueExists(interpreter.StringStorageMapKey("test1")))
assert.True(t, publicStorageMap.ValueExists(interpreter.StringStorageMapKey("test5")))
}
36 changes: 0 additions & 36 deletions migrations/capcons/privatemigration.go

This file was deleted.

29 changes: 18 additions & 11 deletions migrations/entitlements/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (EntitlementsMigration) Name() string {
return "EntitlementsMigration"
}

// Converts its input to an entitled type according to the following rules:
// ConvertToEntitledType converts the given type to an entitled type according to the following rules:
// * `ConvertToEntitledType(&T) ---> auth(Entitlements(T)) &T`
// * `ConvertToEntitledType(Capability<T>) ---> Capability<ConvertToEntitledType(T)>`
// * `ConvertToEntitledType(T?) ---> ConvertToEntitledType(T)?
Expand Down Expand Up @@ -128,7 +128,7 @@ func ConvertToEntitledType(t sema.Type) (sema.Type, bool) {
}
}

// Converts the input value into a version compatible with the new entitlements feature,
// ConvertValueToEntitlements converts the input value into a version compatible with the new entitlements feature,
// with the same members/operations accessible on any references as would have been accessible in the past.
func ConvertValueToEntitlements(
inter *interpreter.Interpreter,
Expand All @@ -151,13 +151,6 @@ func ConvertValueToEntitlements(
interpreter.ConvertSemaToStaticType(inter, referenceValue.BorrowedType),
)

case interpreter.LinkValue: //nolint:staticcheck
// Link values are not supposed to reach here.
// But it could, if the type used in the link is not migrated,
// then the link values would be left un-migrated.
// These need to be skipped specifically, otherwise `v.StaticType(inter)` will panic.
return nil, nil

default:
staticType = v.StaticType(inter)
}
Expand Down Expand Up @@ -364,14 +357,28 @@ func ConvertValueToEntitlements(
v.CapabilityID,
v.TargetPath,
), nil

case interpreter.PathLinkValue: //nolint:staticcheck
semaType := inter.MustConvertStaticToSemaType(staticType)
entitledType, converted := ConvertToEntitledType(semaType)
if !converted {
return nil, nil
}

entitledCapabilityValue := entitledType.(*sema.CapabilityType)
referenceStaticType := interpreter.ConvertSemaToStaticType(inter, entitledCapabilityValue.BorrowType)
return interpreter.PathLinkValue{ //nolint:staticcheck
TargetPath: v.TargetPath,
Type: referenceStaticType,
}, nil
}

return nil, nil
}

func (mig EntitlementsMigration) Migrate(
storageKey interpreter.StorageKey,
storageMapKey interpreter.StorageMapKey,
_ interpreter.StorageKey,
_ interpreter.StorageMapKey,
value interpreter.Value,
_ *interpreter.Interpreter,
) (
Expand Down
18 changes: 18 additions & 0 deletions migrations/entitlements/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,8 @@ func TestConvertToEntitledValue(t *testing.T) {
Name string
}

testPathValue := interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "test")

tests := []testCase{
{
Input: rValue,
Expand Down Expand Up @@ -1149,6 +1151,22 @@ func TestConvertToEntitledValue(t *testing.T) {
),
Name: "&{Int: R}",
},
{
Input: interpreter.PathLinkValue{ //nolint:staticcheck
TargetPath: testPathValue,
Type: unentitledSRefStaticType,
},
Output: interpreter.PathLinkValue{ //nolint:staticcheck
TargetPath: testPathValue,
Type: entitledSRefStaticType,
},
Name: "PathLink<&S>(/storage/test)",
},
{
Input: interpreter.AccountLinkValue{}, //nolint:staticcheck
Output: interpreter.AccountLinkValue{}, //nolint:staticcheck
Name: "AccountLink()",
},
}

getStaticType := func(v interpreter.Value) interpreter.StaticType {
Expand Down
14 changes: 14 additions & 0 deletions migrations/statictypes/account_type_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,20 @@ func TestMigratingValuesWithAccountStaticType(t *testing.T) {
interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "v1"),
),
},
"path_link_value": {
storedValue: interpreter.PathLinkValue{ //nolint:staticcheck
TargetPath: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "v1"),
Type: interpreter.PrimitiveStaticTypePublicAccount, //nolint:staticcheck
},
expectedValue: interpreter.PathLinkValue{ //nolint:staticcheck
TargetPath: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "v1"),
Type: unauthorizedAccountReferenceType,
},
},
"account_link_value": {
storedValue: interpreter.AccountLinkValue{}, //nolint:staticcheck
expectedValue: interpreter.AccountLinkValue{}, //nolint:staticcheck
},
}

// Store values
Expand Down
10 changes: 10 additions & 0 deletions migrations/statictypes/statictype_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ func (m *StaticTypeMigration) Migrate(
}
return interpreter.NewUnmeteredCapabilityValue(value.ID, value.Address, convertedBorrowType), nil

case interpreter.PathLinkValue: //nolint:staticcheck
convertedBorrowType := m.maybeConvertStaticType(value.Type)
if convertedBorrowType == nil {
return
}
return interpreter.PathLinkValue{ //nolint:staticcheck
Type: convertedBorrowType,
TargetPath: value.TargetPath,
}, nil

case *interpreter.AccountCapabilityControllerValue:
convertedBorrowType := m.maybeConvertStaticType(value.BorrowType)
if convertedBorrowType == nil {
Expand Down
50 changes: 40 additions & 10 deletions runtime/interpreter/value_link.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package interpreter

import (
"fmt"

"github.com/onflow/atree"

"github.com/onflow/cadence/runtime/common"
Expand Down Expand Up @@ -58,20 +60,31 @@ func (v PathLinkValue) Walk(_ *Interpreter, _ func(Value)) {
panic(errors.NewUnreachableError())
}

func (v PathLinkValue) StaticType(_ *Interpreter) StaticType {
panic(errors.NewUnreachableError())
func (v PathLinkValue) StaticType(interpreter *Interpreter) StaticType {
// When iterating over public/private paths,
// the values at these paths are PathLinkValues,
// placed there by the `link` function.
//
// These are loaded as links, however,
// for the purposes of checking their type,
// we treat them as capabilities
return NewCapabilityStaticType(interpreter, v.Type)
}

func (PathLinkValue) IsImportable(_ *Interpreter) bool {
panic(errors.NewUnreachableError())
}

func (v PathLinkValue) String() string {
panic(errors.NewUnreachableError())
return v.RecursiveString(SeenReferences{})
}

func (v PathLinkValue) RecursiveString(_ SeenReferences) string {
panic(errors.NewUnreachableError())
func (v PathLinkValue) RecursiveString(seenReferences SeenReferences) string {
return fmt.Sprintf(
"PathLink<%s>(%s)",
v.Type.String(),
v.TargetPath.RecursiveString(seenReferences),
)
}

func (v PathLinkValue) MeteredString(_ common.MemoryGauge, _ SeenReferences) string {
Expand Down Expand Up @@ -126,8 +139,11 @@ func (v PathLinkValue) Transfer(
return v
}

func (v PathLinkValue) Clone(_ *Interpreter) Value {
panic(errors.NewUnreachableError())
func (v PathLinkValue) Clone(inter *Interpreter) Value {
return PathLinkValue{
Type: v.Type,
TargetPath: v.TargetPath.Clone(inter).(PathValue),
}
}

func (PathLinkValue) DeepRemove(_ *Interpreter) {
Expand Down Expand Up @@ -168,16 +184,30 @@ func (AccountLinkValue) Walk(_ *Interpreter, _ func(Value)) {
panic(errors.NewUnreachableError())
}

func (v AccountLinkValue) StaticType(_ *Interpreter) StaticType {
panic(errors.NewUnreachableError())
func (v AccountLinkValue) StaticType(interpreter *Interpreter) StaticType {
// When iterating over public/private paths,
// the values at these paths are AccountLinkValues,
// placed there by the `linkAccount` function.
//
// These are loaded as links, however,
// for the purposes of checking their type,
// we treat them as capabilities
return NewCapabilityStaticType(
interpreter,
NewReferenceStaticType(
interpreter,
FullyEntitledAccountAccess,
PrimitiveStaticTypeAccount,
),
)
}

func (AccountLinkValue) IsImportable(_ *Interpreter) bool {
panic(errors.NewUnreachableError())
}

func (v AccountLinkValue) String() string {
panic(errors.NewUnreachableError())
return "AccountLink()"
}

func (v AccountLinkValue) RecursiveString(_ SeenReferences) string {
Expand Down

0 comments on commit 55925d1

Please sign in to comment.