Skip to content

Commit

Permalink
Add rehashing test for entitlements
Browse files Browse the repository at this point in the history
  • Loading branch information
SupunS committed Jan 18, 2024
1 parent ea9086c commit efd9620
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 0 deletions.
240 changes: 240 additions & 0 deletions migrations/entitlements/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/onflow/atree"

"github.com/onflow/cadence"
"github.com/onflow/cadence/migrations"
"github.com/onflow/cadence/migrations/account_type"
Expand Down Expand Up @@ -1958,3 +1960,241 @@ func TestConvertMigratedAccountTypes(t *testing.T) {
test(ty)
}
}

var testAddress = common.Address{0x42}

var _ migrations.Reporter = &testReporter{}

type testReporter struct {
migratedPaths map[interpreter.AddressPath]struct{}
}

func newTestReporter() *testReporter {
return &testReporter{
migratedPaths: map[interpreter.AddressPath]struct{}{},
}
}

func (t *testReporter) Migrated(
addressPath interpreter.AddressPath,
_ string,
) {
t.migratedPaths[addressPath] = struct{}{}
}

func (t *testReporter) Error(
_ interpreter.AddressPath,
_ string,
_ error,
) {
}

func TestRehash(t *testing.T) {

t.Parallel()

locationRange := interpreter.EmptyLocationRange

ledger := NewTestLedger(nil, nil)

storageMapKey := interpreter.StringStorageMapKey("dict")
newTestValue := func() interpreter.Value {
return interpreter.NewUnmeteredStringValue("test")
}

const fooBarQualifiedIdentifier = "Foo.Bar"
account := common.Address{0x42}
fooAddressLocation := common.NewAddressLocation(nil, account, "Foo")

newStorageAndInterpreter := func(t *testing.T) (*runtime.Storage, *interpreter.Interpreter) {
storage := runtime.NewStorage(ledger, nil)
inter, err := interpreter.NewInterpreter(
nil,
utils.TestLocation,
&interpreter.Config{
Storage: storage,
AtreeValueValidationEnabled: false,
AtreeStorageValidationEnabled: true,
},
)
require.NoError(t, err)

return storage, inter
}

newCompositeType := func() *interpreter.CompositeStaticType {
return interpreter.NewCompositeStaticType(
nil,
fooAddressLocation,
fooBarQualifiedIdentifier,
common.NewTypeIDFromQualifiedName(
nil,
fooAddressLocation,
fooBarQualifiedIdentifier,
),
)
}

entitlementSetAuthorization := sema.NewEntitlementSetAccess(
[]*sema.EntitlementType{
sema.NewEntitlementType(
nil,
fooAddressLocation,
"E",
),
},
sema.Conjunction,
)

t.Run("prepare", func(t *testing.T) {

storage, inter := newStorageAndInterpreter(t)

dictionaryStaticType := interpreter.NewDictionaryStaticType(
nil,
interpreter.PrimitiveStaticTypeMetaType,
interpreter.PrimitiveStaticTypeString,
)
dictValue := interpreter.NewDictionaryValue(inter, locationRange, dictionaryStaticType)

refType := interpreter.NewReferenceStaticType(
nil,
interpreter.UnauthorizedAccess,
newCompositeType(),
)
refType.LegacyIsAuthorized = true

legacyRefType := &migrations.LegacyReferenceType{
ReferenceStaticType: refType,
}

typeValue := interpreter.NewUnmeteredTypeValue(legacyRefType)

dictValue.Insert(
inter,
locationRange,
typeValue,
newTestValue(),
)

// Note: ID is in the old format
assert.Equal(t,
common.TypeID("auth&A.4200000000000000.Foo.Bar"),
legacyRefType.ID(),
)

storageMap := storage.GetStorageMap(
testAddress,
common.PathDomainStorage.Identifier(),
true,
)

storageMap.SetValue(inter,
storageMapKey,
dictValue.Transfer(
inter,
locationRange,
atree.Address(testAddress),
false,
nil,
nil,
),
)

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

t.Run("migrate", func(t *testing.T) {

storage, inter := newStorageAndInterpreter(t)

inter.SharedState.Config.CompositeTypeHandler = func(location common.Location, typeID interpreter.TypeID) *sema.CompositeType {

compositeType := &sema.CompositeType{
Location: fooAddressLocation,
Identifier: fooBarQualifiedIdentifier,
Kind: common.CompositeKindStructure,
}

compositeType.Members = sema.MembersAsMap([]*sema.Member{
sema.NewUnmeteredFunctionMember(
compositeType,
entitlementSetAuthorization,
"sayHello",
&sema.FunctionType{},
"",
),
})

return compositeType
}

migration := migrations.NewStorageMigration(inter, storage)

reporter := newTestReporter()

migration.Migrate(
&migrations.AddressSliceIterator{
Addresses: []common.Address{
testAddress,
},
},
migration.NewValueMigrationsPathMigrator(
reporter,
NewEntitlementsMigration(inter),
),
)

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

require.Equal(t,
map[interpreter.AddressPath]struct{}{
{
Address: testAddress,
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: string(storageMapKey),
},
}: {},
},
reporter.migratedPaths,
)
})

t.Run("load", func(t *testing.T) {

storage, inter := newStorageAndInterpreter(t)

storageMap := storage.GetStorageMap(testAddress, common.PathDomainStorage.Identifier(), false)
storedValue := storageMap.ReadValue(inter, storageMapKey)

require.IsType(t, &interpreter.DictionaryValue{}, storedValue)

dictValue := storedValue.(*interpreter.DictionaryValue)

refType := interpreter.NewReferenceStaticType(
nil,
interpreter.ConvertSemaAccessToStaticAuthorization(nil, entitlementSetAuthorization),
newCompositeType(),
)

typeValue := interpreter.NewUnmeteredTypeValue(refType)

// Note: ID is in the new format
assert.Equal(t,
common.TypeID("auth(A.4200000000000000.E)&A.4200000000000000.Foo.Bar"),
refType.ID(),
)

value, ok := dictValue.Get(inter, locationRange, typeValue)
require.True(t, ok)

require.IsType(t, &interpreter.StringValue{}, value)
require.Equal(t,
newTestValue(),
value.(*interpreter.StringValue),
)
})
}
27 changes: 27 additions & 0 deletions migrations/legacy_reference_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package migrations
import (
"strings"

"github.com/fxamacker/cbor/v2"

"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/interpreter"
)
Expand Down Expand Up @@ -54,3 +56,28 @@ func formatReferenceType(
builder.WriteString(typeString)
return builder.String()
}

func (t *LegacyReferenceType) Encode(e *cbor.StreamEncoder) error {
// Encode tag number and array head
err := e.EncodeRawBytes([]byte{
// tag number
0xd8, interpreter.CBORTagReferenceStaticType,
// array, 2 items follow
0x82,
})
if err != nil {
return err
}

Check warning on line 70 in migrations/legacy_reference_type.go

View check run for this annotation

Codecov / codecov/patch

migrations/legacy_reference_type.go#L69-L70

Added lines #L69 - L70 were not covered by tests

// Encode the `LegacyIsAuthorized` flag instead of the `Authorization`.
// This is how it was done in pre-1.0.
// Decode already supports decoding this flag, for backward compatibility.
// Encode authorized at array index encodedReferenceStaticTypeAuthorizedFieldKey
err = e.EncodeBool(t.LegacyIsAuthorized)
if err != nil {
return err
}

Check warning on line 79 in migrations/legacy_reference_type.go

View check run for this annotation

Codecov / codecov/patch

migrations/legacy_reference_type.go#L78-L79

Added lines #L78 - L79 were not covered by tests

// Encode type at array index encodedReferenceStaticTypeTypeFieldKey
return t.ReferencedType.Encode(e)
}

0 comments on commit efd9620

Please sign in to comment.