Skip to content

Commit

Permalink
Merge pull request #3503 from onflow/bastian/migrate-storage-path-cap…
Browse files Browse the repository at this point in the history
…abilities
  • Loading branch information
turbolent authored Jul 31, 2024
2 parents c187291 + 6f6ee81 commit be44a84
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 43 deletions.
109 changes: 77 additions & 32 deletions migrations/capcons/capabilitymigration.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import (
"github.com/onflow/cadence/runtime/errors"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
)

type CapabilityMigrationReporter interface {
MigratedPathCapability(
accountAddress common.Address,
addressPath interpreter.AddressPath,
borrowType *interpreter.ReferenceStaticType,
capabilityID interpreter.UInt64Value,
)
MissingCapabilityID(
accountAddress common.Address,
Expand All @@ -42,6 +44,7 @@ type CapabilityMigrationReporter interface {
// using the path to ID capability controller mapping generated by LinkValueMigration.
type CapabilityValueMigration struct {
CapabilityMapping *CapabilityMapping
IssueHandler stdlib.CapabilityControllerIssueHandler
Reporter CapabilityMigrationReporter
}

Expand All @@ -67,65 +70,107 @@ func (m *CapabilityValueMigration) Migrate(
storageKey interpreter.StorageKey,
_ interpreter.StorageMapKey,
value interpreter.Value,
_ *interpreter.Interpreter,
inter *interpreter.Interpreter,
_ migrations.ValueMigrationPosition,
) (
interpreter.Value,
error,
) {

// Migrate path capabilities to ID capabilities
if pathCapabilityValue, ok := value.(*interpreter.PathCapabilityValue); ok { //nolint:staticcheck
return m.migratePathCapabilityValue(pathCapabilityValue, storageKey, inter)
}

return nil, nil
}

func (m *CapabilityValueMigration) migratePathCapabilityValue(
oldCapability *interpreter.PathCapabilityValue, //nolint:staticcheck
storageKey interpreter.StorageKey,
inter *interpreter.Interpreter,
) (interpreter.Value, error) {

reporter := m.Reporter

switch value := value.(type) {
case *interpreter.PathCapabilityValue: //nolint:staticcheck
capabilityAddressPath := oldCapability.AddressPath()

// Migrate the path capability to an ID capability
var capabilityID interpreter.UInt64Value
var controllerBorrowType sema.Type

oldCapability := value
targetPath := capabilityAddressPath.Path

capabilityAddressPath := oldCapability.AddressPath()
capabilityID, controllerBorrowType, ok := m.CapabilityMapping.Get(capabilityAddressPath)
switch targetPath.Domain {
case common.PathDomainPublic,
common.PathDomainPrivate:

var ok bool
capabilityID, controllerBorrowType, ok = m.CapabilityMapping.Get(capabilityAddressPath)
if !ok {
if reporter != nil {
reporter.MissingCapabilityID(
storageKey.Address,
capabilityAddressPath,
)
}
break
return nil, nil
}

oldBorrowType := oldCapability.BorrowType
case common.PathDomainStorage:
// The capability may incorrectly target a storage path,
// due to an incorrect implementation of the link function in an early version of Cadence.
// This bug was fixed in https://github.com/onflow/cadence/pull/865,
// and subsequent capabilities created by the link function have correct targets,
// but networks may still have capabilities with incorrect targets.
//
// In this case, there is no corresponding capability controller in the mapping,
// so issue a new capability controller.

borrowType := inter.MustConvertStaticToSemaType(oldCapability.BorrowType).(*sema.ReferenceType)
controllerBorrowType = borrowType

capabilityID, _ = stdlib.IssueStorageCapabilityController(
inter,
interpreter.EmptyLocationRange,
m.IssueHandler,
common.Address(oldCapability.Address),
borrowType,
targetPath,
)

// Convert untyped path capability value to typed ID capability value
// by using capability controller's borrow type
if oldBorrowType == nil {
oldBorrowType = interpreter.ConvertSemaToStaticType(nil, controllerBorrowType)
}
default:
panic(errors.NewUnexpectedError("unexpected capability target path: %s", targetPath))
}

newBorrowType, ok := oldBorrowType.(*interpreter.ReferenceStaticType)
if !ok {
panic(errors.NewUnexpectedError("unexpected non-reference borrow type: %T", oldBorrowType))
}
oldBorrowType := oldCapability.BorrowType

newCapability := interpreter.NewUnmeteredCapabilityValue(
capabilityID,
oldCapability.Address,
newBorrowType,
)
// Convert untyped path capability value to typed ID capability value
// by using capability controller's borrow type
if oldBorrowType == nil {
oldBorrowType = interpreter.ConvertSemaToStaticType(nil, controllerBorrowType)
}

if reporter != nil {
reporter.MigratedPathCapability(
storageKey.Address,
capabilityAddressPath,
newBorrowType,
)
}
newBorrowType, ok := oldBorrowType.(*interpreter.ReferenceStaticType)
if !ok {
panic(errors.NewUnexpectedError("unexpected non-reference borrow type: %T", oldBorrowType))
}

return newCapability, nil
newCapability := interpreter.NewUnmeteredCapabilityValue(
capabilityID,
oldCapability.Address,
newBorrowType,
)

if reporter != nil {
reporter.MigratedPathCapability(
storageKey.Address,
capabilityAddressPath,
newBorrowType,
capabilityID,
)
}

return nil, nil
return newCapability, nil
}

func (m *CapabilityValueMigration) CanSkip(valueType interpreter.StaticType) bool {
Expand Down
72 changes: 61 additions & 11 deletions migrations/capcons/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type testCapConsPathCapabilityMigration struct {
accountAddress common.Address
addressPath interpreter.AddressPath
borrowType *interpreter.ReferenceStaticType
capabilityID interpreter.UInt64Value
}

type testCapConsMissingCapabilityID struct {
Expand Down Expand Up @@ -140,13 +141,15 @@ func (t *testMigrationReporter) MigratedPathCapability(
accountAddress common.Address,
addressPath interpreter.AddressPath,
borrowType *interpreter.ReferenceStaticType,
capabilityID interpreter.UInt64Value,
) {
t.pathCapabilityMigrations = append(
t.pathCapabilityMigrations,
testCapConsPathCapabilityMigration{
accountAddress: accountAddress,
addressPath: addressPath,
borrowType: borrowType,
capabilityID: capabilityID,
},
)
}
Expand Down Expand Up @@ -508,6 +511,7 @@ func testPathCapabilityValueMigration(
reporter,
&CapabilityValueMigration{
CapabilityMapping: capabilityMapping,
IssueHandler: handler,
Reporter: reporter,
},
),
Expand Down Expand Up @@ -689,7 +693,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
borrowType: testRReferenceStaticType,
capabilityID: 2,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -744,7 +749,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
borrowType: testRReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -798,7 +804,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
borrowType: testRReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -878,7 +885,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
borrowType: testRReferenceStaticType,
capabilityID: 2,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -935,7 +943,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
borrowType: testRReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -1065,6 +1074,39 @@ func TestPathCapabilityValueMigration(t *testing.T) {
},
expectedEvents: []string{},
},
{
name: "Path link, storage path",
// Equivalent to: getCapability<&Test.R>(/storage/test)
capabilityValue: &interpreter.PathCapabilityValue{ //nolint:staticcheck
BorrowType: testRReferenceStaticType,
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: testPathIdentifier,
},
Address: interpreter.AddressValue(testAddress),
},
pathLinks: nil,
expectedMigrations: []testMigration{
expectedWrappedCapabilityValueMigration,
},
expectedPathMigrations: []testCapConsPathCapabilityMigration{
{
accountAddress: testAddress,
addressPath: interpreter.AddressPath{
Address: testAddress,
Path: interpreter.NewUnmeteredPathValue(
common.PathDomainStorage,
testPathIdentifier,
),
},
borrowType: testRReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
`flow.StorageCapabilityControllerIssued(id: 1, address: 0x0000000000000001, type: Type<&A.0000000000000001.Test.R>(), path: /storage/test)`,
},
},
{
name: "Account link, working chain (public), unauthorized",
// Equivalent to: getCapability<&Account>(/public/test)
Expand Down Expand Up @@ -1105,7 +1147,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: unauthorizedAccountReferenceStaticType,
borrowType: unauthorizedAccountReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -1156,7 +1199,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: fullyEntitledAccountReferenceStaticType,
borrowType: fullyEntitledAccountReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -1203,7 +1247,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: unauthorizedAccountReferenceStaticType,
borrowType: unauthorizedAccountReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -1250,7 +1295,8 @@ func TestPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: fullyEntitledAccountReferenceStaticType,
borrowType: fullyEntitledAccountReferenceStaticType,
capabilityID: 1,
},
},
expectedEvents: []string{
Expand Down Expand Up @@ -2216,7 +2262,8 @@ func TestPublishedPathCapabilityValueMigration(t *testing.T) {
testPathIdentifier,
),
},
borrowType: borrowType,
borrowType: borrowType,
capabilityID: 2,
},
}

Expand Down Expand Up @@ -2322,6 +2369,7 @@ func TestPublishedPathCapabilityValueMigration(t *testing.T) {
reporter,
&CapabilityValueMigration{
CapabilityMapping: capabilityMapping,
IssueHandler: handler,
Reporter: reporter,
},
),
Expand Down Expand Up @@ -2466,7 +2514,8 @@ func TestUntypedPathCapabilityValueMigration(t *testing.T) {
),
},
// NOTE: link / cap con's borrow type is used
borrowType: linkBorrowType,
borrowType: linkBorrowType,
capabilityID: 2,
},
}

Expand Down Expand Up @@ -2573,6 +2622,7 @@ func TestUntypedPathCapabilityValueMigration(t *testing.T) {
reporter,
&CapabilityValueMigration{
CapabilityMapping: capabilityMapping,
IssueHandler: handler,
Reporter: reporter,
},
),
Expand Down

0 comments on commit be44a84

Please sign in to comment.