Skip to content

Commit

Permalink
Merge pull request #3103 from onflow/bastian/3102-decode-published-pa…
Browse files Browse the repository at this point in the history
…th-capability-values
  • Loading branch information
turbolent authored Feb 14, 2024
2 parents 9129538 + 27d2386 commit 7536efb
Show file tree
Hide file tree
Showing 19 changed files with 358 additions and 89 deletions.
4 changes: 2 additions & 2 deletions migrations/capcons/linkmigration.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (m *LinkValueMigration) Migrate(
var borrowStaticType *interpreter.ReferenceStaticType

switch readValue := value.(type) {
case *interpreter.CapabilityValue:
case *interpreter.IDCapabilityValue:
// Already migrated
return nil, nil

Expand Down Expand Up @@ -300,7 +300,7 @@ func (m *LinkValueMigration) getPathCapabilityFinalTarget(
interpreter.UnauthorizedAccess,
nil

case *interpreter.CapabilityValue:
case *interpreter.IDCapabilityValue:

// Follow ID capability values which are published in the public or private domain.
// This is needed for two reasons:
Expand Down
246 changes: 245 additions & 1 deletion migrations/capcons/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,7 @@ func testLinkMigration(
expectedMigrations,
reporter.migrations,
)
assert.Equal(t,
assert.Empty(t,
expectedErrors,
reporter.errors,
)
Expand Down Expand Up @@ -1865,3 +1865,247 @@ func TestLinkMigration(t *testing.T) {
test(linkTestCase)
}
}

func TestPublishedPathCapabilityValueMigration(t *testing.T) {

t.Parallel()

// Equivalent to: &Int
borrowType := interpreter.NewReferenceStaticType(
nil,
interpreter.UnauthorizedAccess,
interpreter.PrimitiveStaticTypeInt,
)

// Equivalent to: getCapability<&Int>(/public/test)
capabilityValue := &interpreter.PathCapabilityValue{ //nolint:staticcheck
BorrowType: borrowType,
Path: interpreter.PathValue{
Domain: common.PathDomainPublic,
Identifier: testPathIdentifier,
},
Address: interpreter.AddressValue(testAddress),
}

pathLinks := []testLink{
// Equivalent to:
// link<&Int>(/public/test, target: /private/test)
{
sourcePath: interpreter.PathValue{
Domain: common.PathDomainPublic,
Identifier: testPathIdentifier,
},
targetPath: interpreter.PathValue{
Domain: common.PathDomainPrivate,
Identifier: testPathIdentifier,
},
borrowType: borrowType,
},
// Equivalent to:
// link<&Int>(/private/test, target: /storage/test)
{
sourcePath: interpreter.PathValue{
Domain: common.PathDomainPrivate,
Identifier: testPathIdentifier,
},
targetPath: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: testPathIdentifier,
},
borrowType: borrowType,
},
}

expectedMigrations := []testMigration{
{
storageKey: interpreter.StorageKey{
Address: testAddress,
Key: common.PathDomainPrivate.Identifier(),
},
storageMapKey: interpreter.StringStorageMapKey(testPathIdentifier),
migration: "LinkValueMigration",
},
{
storageKey: interpreter.StorageKey{
Address: testAddress,
Key: common.PathDomainPublic.Identifier(),
},
storageMapKey: interpreter.StringStorageMapKey(testPathIdentifier),
migration: "LinkValueMigration",
},
{
storageKey: interpreter.StorageKey{
Address: testAddress,
Key: stdlib.InboxStorageDomain,
},
storageMapKey: interpreter.StringStorageMapKey("foo"),
migration: "CapabilityValueMigration",
},
}

expectedPathMigrations := []testCapConsPathCapabilityMigration{
{
accountAddress: testAddress,
addressPath: interpreter.AddressPath{
Address: testAddress,
Path: interpreter.NewUnmeteredPathValue(
common.PathDomainPublic,
testPathIdentifier,
),
},
borrowType: borrowType,
},
}

rt := NewTestInterpreterRuntime()

var events []cadence.Event

runtimeInterface := &TestRuntimeInterface{
Storage: NewTestLedger(nil, nil),
OnGetSigningAccounts: func() ([]runtime.Address, error) {
return []runtime.Address{testAddress}, nil
},
OnEmitEvent: func(event cadence.Event) error {
events = append(events, event)
return nil
},
}

nextTransactionLocation := NewTransactionLocationGenerator()
nextScriptLocation := NewScriptLocationGenerator()

// Setup

setupTransactionLocation := nextTransactionLocation()

environment := runtime.NewScriptInterpreterEnvironment(runtime.Config{})

// Inject the path capability value.
//
// We don't have a way to create a path capability value in a Cadence program anymore,
// so we have to inject it manually.

environment.DeclareValue(
stdlib.StandardLibraryValue{
Name: "cap",
Type: &sema.CapabilityType{},
Kind: common.DeclarationKindConstant,
Value: capabilityValue,
},
setupTransactionLocation,
)

// Create and store path links

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

storeTestPathLinks(t, pathLinks, storage, inter)

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

// Save capability values into account

// language=cadence
setupTx := `
transaction {
prepare(signer: auth(PublishInboxCapability) &Account) {
signer.inbox.publish(cap, name: "foo", recipient: 0x2)
}
}
`

err = rt.ExecuteTransaction(
runtime.Script{
Source: []byte(setupTx),
},
runtime.Context{
Interface: runtimeInterface,
Environment: environment,
Location: setupTransactionLocation,
},
)
require.NoError(t, err)

// Migrate

migration := migrations.NewStorageMigration(inter, storage)

capabilityIDs := &CapabilityIDMapping{}

reporter := &testMigrationReporter{}

migration.Migrate(
&migrations.AddressSliceIterator{
Addresses: []common.Address{
testAddress,
},
},
migration.NewValueMigrationsPathMigrator(
reporter,
&LinkValueMigration{
CapabilityIDs: capabilityIDs,
AccountIDGenerator: &testAccountIDGenerator{},
Reporter: reporter,
},
),
)

migration.Migrate(
&migrations.AddressSliceIterator{
Addresses: []common.Address{
testAddress,
},
},
migration.NewValueMigrationsPathMigrator(
reporter,
&CapabilityValueMigration{
CapabilityIDs: capabilityIDs,
Reporter: reporter,
},
),
)

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

// Check migrated capabilities

assert.Equal(t,
expectedMigrations,
reporter.migrations,
)
assert.Empty(t, reporter.errors)
assert.Equal(t,
expectedPathMigrations,
reporter.pathCapabilityMigrations,
)
require.Nil(t, reporter.missingCapabilityIDs)

// Check

// language=cadence
checkScript := `
access(all)
fun main() {
getAuthAccount<auth(ClaimInboxCapability) &Account>(0x2)
.inbox.claim<&Int>("foo", provider: 0x1)!
}
`

_, err = rt.ExecuteScript(
runtime.Script{
Source: []byte(checkScript),
},
runtime.Context{
Interface: runtimeInterface,
Location: nextScriptLocation(),
},
)
require.NoError(t, err)

}
2 changes: 1 addition & 1 deletion migrations/entitlements/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ func ConvertValueToEntitlements(
values...,
), nil

case *interpreter.CapabilityValue:
case *interpreter.IDCapabilityValue:
semaType := inter.MustConvertStaticToSemaType(staticType)
entitledType, converted := ConvertToEntitledType(semaType)
if !converted {
Expand Down
38 changes: 24 additions & 14 deletions migrations/entitlements/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1684,7 +1684,7 @@ func TestMigratePublishedValue(t *testing.T) {
require.Equal(t, inboxStorageMap.Count(), uint64(1))

cap1 := storageMap.ReadValue(nil, interpreter.StringStorageMapKey("cap"))
capValue := cap1.(*interpreter.CapabilityValue)
capValue := cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref := capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand All @@ -1700,8 +1700,13 @@ func TestMigratePublishedValue(t *testing.T) {
)

publishedValue := inboxStorageMap.ReadValue(nil, interpreter.StringStorageMapKey("r_cap"))

require.IsType(t, &interpreter.PublishedValue{}, publishedValue)
capabilityValue := publishedValue.(*interpreter.PublishedValue).Value
publishedValueValue := publishedValue.(*interpreter.PublishedValue).Value

require.IsType(t, &interpreter.IDCapabilityValue{}, publishedValueValue)
capabilityValue := publishedValueValue.(*interpreter.IDCapabilityValue)

require.IsType(t, &interpreter.ReferenceStaticType{}, capabilityValue.BorrowType)
ref = capabilityValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand Down Expand Up @@ -1916,7 +1921,7 @@ func TestMigratePublishedValueAcrossTwoAccounts(t *testing.T) {
)

cap1 := storageMap.ReadValue(nil, interpreter.StringStorageMapKey("cap"))
capValue := cap1.(*interpreter.CapabilityValue)
capValue := cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref := capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand All @@ -1932,8 +1937,13 @@ func TestMigratePublishedValueAcrossTwoAccounts(t *testing.T) {
)

publishedValue := inboxStorageMap.ReadValue(nil, interpreter.StringStorageMapKey("r_cap"))

require.IsType(t, &interpreter.PublishedValue{}, publishedValue)
capabilityValue := publishedValue.(*interpreter.PublishedValue).Value
publishedValueValue := publishedValue.(*interpreter.PublishedValue).Value

require.IsType(t, &interpreter.IDCapabilityValue{}, publishedValueValue)
capabilityValue := publishedValueValue.(*interpreter.IDCapabilityValue)

require.IsType(t, &interpreter.ReferenceStaticType{}, capabilityValue.BorrowType)
ref = capabilityValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand Down Expand Up @@ -2152,8 +2162,8 @@ func TestMigrateAcrossContracts(t *testing.T) {

field := tValue.GetMember(inter, interpreter.EmptyLocationRange, "cap")

require.IsType(t, &interpreter.CapabilityValue{}, field)
cap := field.(*interpreter.CapabilityValue)
require.IsType(t, &interpreter.IDCapabilityValue{}, field)
cap := field.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, cap.BorrowType)
ref := cap.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand Down Expand Up @@ -2382,8 +2392,8 @@ func TestMigrateArrayOfValues(t *testing.T) {
)

cap1 := arrValue.Get(inter, interpreter.EmptyLocationRange, 0)
require.IsType(t, &interpreter.CapabilityValue{}, cap1)
capValue := cap1.(*interpreter.CapabilityValue)
require.IsType(t, &interpreter.IDCapabilityValue{}, cap1)
capValue := cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref = capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand All @@ -2399,8 +2409,8 @@ func TestMigrateArrayOfValues(t *testing.T) {
)

cap2 := arrValue.Get(inter, interpreter.EmptyLocationRange, 1)
require.IsType(t, &interpreter.CapabilityValue{}, cap2)
capValue = cap1.(*interpreter.CapabilityValue)
require.IsType(t, &interpreter.IDCapabilityValue{}, cap2)
capValue = cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref = capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand Down Expand Up @@ -2631,8 +2641,8 @@ func TestMigrateDictOfValues(t *testing.T) {
interpreter.NewUnmeteredStringValue("a"),
)
require.True(t, present)
require.IsType(t, &interpreter.CapabilityValue{}, cap1)
capValue := cap1.(*interpreter.CapabilityValue)
require.IsType(t, &interpreter.IDCapabilityValue{}, cap1)
capValue := cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref = capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand All @@ -2651,8 +2661,8 @@ func TestMigrateDictOfValues(t *testing.T) {
interpreter.NewUnmeteredStringValue("b"),
)
require.True(t, present)
require.IsType(t, &interpreter.CapabilityValue{}, cap2)
capValue = cap1.(*interpreter.CapabilityValue)
require.IsType(t, &interpreter.IDCapabilityValue{}, cap2)
capValue = cap1.(*interpreter.IDCapabilityValue)
require.IsType(t, &interpreter.ReferenceStaticType{}, capValue.BorrowType)
ref = capValue.BorrowType.(*interpreter.ReferenceStaticType)
require.Equal(t,
Expand Down
2 changes: 1 addition & 1 deletion migrations/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ func (m *StorageMigration) MigrateNestedValue(
reporter,
)
if newInnerValue != nil {
newInnerCapability := newInnerValue.(*interpreter.CapabilityValue)
newInnerCapability := newInnerValue.(*interpreter.IDCapabilityValue)
return interpreter.NewPublishedValue(
m.interpreter,
value.Recipient,
Expand Down
Loading

0 comments on commit 7536efb

Please sign in to comment.