Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add external mutability improvements #2718

Merged
merged 102 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
9743293
Change member access result type to a reference
SupunS Jun 9, 2023
ece3d8f
Fix attachment 'self' access
SupunS Jun 9, 2023
ccc053e
Update interpreter member access
SupunS Jun 12, 2023
e26ff54
Update tests
SupunS Jun 13, 2023
ab854e2
Fix more tests
SupunS Jun 13, 2023
85d294a
Add member-acess expr to static reference validity checking
SupunS Jun 14, 2023
0421eb0
Add test for static attachment invalidation
SupunS Jun 14, 2023
b965147
Refactor code
SupunS Jun 14, 2023
aabca06
Add more tests
SupunS Jun 14, 2023
fc5ea48
Merge branch 'feature/entitlements' of https://github.com/onflow/cade…
SupunS Jun 15, 2023
04e7ac8
Update to match entitlements
SupunS Jun 15, 2023
f0f77d2
Add built-in entitlements
SupunS Jun 15, 2023
5845813
Auto regiter generated entitlements
SupunS Jun 16, 2023
9b9c937
Add builtin entitlements to array functions
SupunS Jun 19, 2023
5c8ea34
Re-use pre-computed results from checker
SupunS Jun 19, 2023
eca92df
Improve tests
SupunS Jun 19, 2023
498c63a
Add test for index expression resource loss
SupunS Jun 19, 2023
5dceaa6
Refactor checking access modifiers
SupunS Jun 19, 2023
b5e26fc
Pass authorization to members
SupunS Jun 19, 2023
5157711
Simplify reference creation
SupunS Jun 19, 2023
81a8c8f
Merge branch 'supun/member-access-semantics' into supun/entitlement-i…
SupunS Jun 19, 2023
dadf1c3
Simplify reference creation for index expressions
SupunS Jun 19, 2023
8b45a77
Merge branch 'supun/member-access-semantics' into supun/entitlement-i…
SupunS Jun 20, 2023
b33b86c
Pass down proper authorization for member-access on reference
SupunS Jun 20, 2023
5165954
Fix tests
SupunS Jun 20, 2023
bd13b6e
Pass proper entitlements to index expression members
SupunS Jun 20, 2023
0970761
Merge branch 'supun/entitlement-improvements' into supun/use-builtin-…
SupunS Jun 20, 2023
388d662
Add identity mapping
SupunS Jun 20, 2023
f7b554c
Merge branch 'supun/identity-mapping' into supun/use-builtin-entitlem…
SupunS Jun 20, 2023
c2699ab
Update tests
SupunS Jun 20, 2023
efce305
Fix tests
SupunS Jun 20, 2023
3e8e30e
Merge branch 'supun/identity-mapping' into supun/use-builtin-entitlem…
SupunS Jun 20, 2023
630b7ca
Merge branch 'supun/builtin-entitlements' into supun/mutability-changes
SupunS Jun 20, 2023
bbe5bb9
Merge branch 'supun/identity-mapping' into supun/mutability-changes
SupunS Jun 20, 2023
533cbb4
Return unauthorized reference for array/dictionary elements
SupunS Jun 21, 2023
bb86a41
Merge branch 'supun/entitlement-improvements' into supun/use-builtin-…
SupunS Jun 21, 2023
2508590
Merge branch 'supun/entitlement-improvements' into supun/mutability-c…
SupunS Jun 21, 2023
6eed27b
Merge branch 'supun/mutability-changes' of https://github.com/onflow/…
SupunS Jun 21, 2023
a073e17
Test redeclaring built-in entitlements
SupunS Jun 21, 2023
7a4ff32
ADd more tests for identity mapping
SupunS Jun 21, 2023
b35e6a8
Replace 'pub' with 'access(all)'
SupunS Jun 21, 2023
5d6babd
Add more tests
SupunS Jun 22, 2023
6bd53e9
Add entitlements to dictionary functions
SupunS Jun 22, 2023
03197ec
Require insertable/mutatble refrence for index assignment
SupunS Jun 22, 2023
7cf1c65
Remove external mutation checks
SupunS Jun 22, 2023
20d2125
Update tests
SupunS Jun 22, 2023
354e042
Merge branch 'supun/allow-external-mutation' into supun/entitled-assi…
SupunS Jun 22, 2023
37c0667
Merge branch 'supun/sync-mutability-restrictions' into supun/member-a…
SupunS Jun 22, 2023
ade5bba
Update test
SupunS Jun 22, 2023
fa638ae
Fix swap statement
SupunS Jun 22, 2023
10dbec2
Merge branch 'supun/member-access-semantics' into supun/entitlement-i…
SupunS Jun 22, 2023
3ff9208
Merge branch 'supun/builtin-entitlements' into supun/identity-mapping
SupunS Jun 22, 2023
efd6db1
Merge branch 'supun/identity-mapping' into supun/mutability-changes
SupunS Jun 22, 2023
1df5774
Merge branch 'supun/mutability-changes' into supun/use-builtin-entitl…
SupunS Jun 22, 2023
9c97207
Merge branch 'supun/member-access-semantics' into supun/builtin-entit…
SupunS Jun 22, 2023
a82ff3d
Merge branch 'supun/builtin-entitlements' into supun/identity-mapping
SupunS Jun 22, 2023
665397a
Merge branch 'supun/entitlement-improvements' into supun/mutability-c…
SupunS Jun 22, 2023
282b0c2
Merge branch 'supun/mutability-changes' of https://github.com/onflow/…
SupunS Jun 22, 2023
a2eead4
Adjust tests
SupunS Jun 22, 2023
ba6e193
Merge branch 'supun/use-builtin-entitlements' into supun/allow-extern…
SupunS Jun 22, 2023
c5c6f01
Merge branch 'supun/allow-external-mutation' into supun/entitled-assi…
SupunS Jun 22, 2023
351673b
Merge pull request #2600 from onflow/supun/sync-mutability-restrictions
SupunS Jun 22, 2023
651f4b5
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jun 22, 2023
8b909b3
Update tests
SupunS Jun 23, 2023
a80ac51
Lint
SupunS Jun 23, 2023
7cfcc05
Move is-container check to the type itself
SupunS Jun 23, 2023
99d7541
Merge branch 'supun/member-access-semantics' into supun/entitlement-i…
SupunS Jun 23, 2023
c16e568
Update tests
SupunS Jun 23, 2023
84e7e0f
Rename MemberInfo to MemberAccessInfo
SupunS Jul 4, 2023
b72a3b1
Update tests
SupunS Jul 4, 2023
26149a0
Fix tidy
SupunS Jul 4, 2023
fe2a7be
Return a reference with entitlements, when access through owned values
SupunS Jul 5, 2023
e47f451
Rename 'MemberAccessible' to 'ContainFieldsOrElements'
SupunS Jul 5, 2023
2a08798
Merge pull request #2573 from onflow/supun/member-access-semantics
SupunS Jul 6, 2023
0726316
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
21c47ab
Add licence header
SupunS Jul 6, 2023
3a298b0
Merge pull request #2586 from onflow/supun/builtin-entitlements
SupunS Jul 6, 2023
3d4dc10
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
77a8b23
Merge pull request #2587 from onflow/supun/entitlement-improvements
SupunS Jul 6, 2023
6e58924
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
e9508ca
Merge pull request #2588 from onflow/supun/identity-mapping
SupunS Jul 6, 2023
aaef3a3
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
750be9f
Merge pull request #2598 from onflow/supun/use-builtin-entitlements
SupunS Jul 6, 2023
73c9b97
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
8fe5295
Merge pull request #2599 from onflow/supun/allow-external-mutation
SupunS Jul 6, 2023
899a0fa
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 6, 2023
a54cad8
Return all supported entitlements for owned value's fields
SupunS Jul 6, 2023
842a9cd
Add more tests
SupunS Jul 10, 2023
e8c73bd
Merge pull request #2637 from onflow/supun/identity-mapping-improvement
SupunS Jul 18, 2023
b7d6df2
Merge branch 'feature/mutability-restrictions' of https://github.com/…
SupunS Jul 18, 2023
97ab8c0
Update tests
SupunS Jul 18, 2023
57821ec
Add more tests
SupunS Jul 18, 2023
34b30d5
Requrie mutablity entitlements for index assignment
SupunS Jul 19, 2023
ae64ba2
Conform dictionaries and arrays to EntitlementSupportingType
SupunS Aug 1, 2023
c142c39
Remove redundant nil check
SupunS Aug 1, 2023
5b47d1a
Merge pull request #2664 from onflow/supun/entitled-assigment
SupunS Aug 2, 2023
5d40cd1
Rename mutability entitlements
SupunS Aug 2, 2023
894095b
Merge pull request #2690 from onflow/supun/rename-entitlements
SupunS Aug 2, 2023
9093316
Merge branch 'feature/stable-cadence' into bastian/mutability-restric…
turbolent Aug 11, 2023
01186e8
lint: delete unused code
turbolent Aug 11, 2023
7f32297
lint
turbolent Aug 11, 2023
4acc8de
Merge pull request #2714 from onflow/bastian/mutability-restrictions
turbolent Aug 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 35 additions & 14 deletions runtime/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1451,10 +1451,23 @@ func TestRuntimePublicKey(t *testing.T) {
}
addPublicKeyValidation(runtimeInterface, nil)

_, err := executeScript(script, runtimeInterface)
errs := checker.RequireCheckerErrors(t, err, 1)
value, err := executeScript(script, runtimeInterface)
require.NoError(t, err)

assert.IsType(t, &sema.ExternalMutationError{}, errs[0])
expected := cadence.Struct{
StructType: PublicKeyType,
Fields: []cadence.Value{
// Public key (bytes)
newBytesValue([]byte{1, 2}),

// Signature Algo
newSignAlgoValue(sema.SignatureAlgorithmECDSA_P256),
},
}

expected = cadence.ValueWithCachedTypeID(expected)

assert.Equal(t, expected, value)
})

t.Run("raw-key reference mutability", func(t *testing.T) {
Expand All @@ -1467,7 +1480,7 @@ func TestRuntimePublicKey(t *testing.T) {
signatureAlgorithm: SignatureAlgorithm.ECDSA_P256
)

var publickeyRef = &publicKey.publicKey as &[UInt8]
var publickeyRef = &publicKey.publicKey as auth(Mutate) &[UInt8]
publickeyRef[0] = 3

return publicKey
Expand Down Expand Up @@ -1885,9 +1898,7 @@ func TestAuthAccountContracts(t *testing.T) {
Location: nextTransactionLocation(),
},
)
errs := checker.RequireCheckerErrors(t, err, 1)

assert.IsType(t, &sema.ExternalMutationError{}, errs[0])
require.NoError(t, err)
})

t.Run("update names through reference", func(t *testing.T) {
Expand All @@ -1898,7 +1909,7 @@ func TestAuthAccountContracts(t *testing.T) {
script := []byte(`
transaction {
prepare(signer: AuthAccount) {
var namesRef = &signer.contracts.names as &[String]
var namesRef = &signer.contracts.names as auth(Mutate) &[String]
namesRef[0] = "baz"

assert(signer.contracts.names[0] == "foo")
Expand Down Expand Up @@ -2097,7 +2108,7 @@ func TestPublicAccountContracts(t *testing.T) {
},
}

_, err := rt.ExecuteScript(
result, err := rt.ExecuteScript(
Script{
Source: script,
},
Expand All @@ -2106,9 +2117,14 @@ func TestPublicAccountContracts(t *testing.T) {
Location: common.ScriptLocation{},
},
)
errs := checker.RequireCheckerErrors(t, err, 1)
require.NoError(t, err)

require.IsType(t, cadence.Array{}, result)
array := result.(cadence.Array)

assert.IsType(t, &sema.ExternalMutationError{}, errs[0])
require.Len(t, array.Values, 2)
assert.Equal(t, cadence.String("foo"), array.Values[0])
assert.Equal(t, cadence.String("bar"), array.Values[1])
})

t.Run("append names", func(t *testing.T) {
Expand All @@ -2133,7 +2149,7 @@ func TestPublicAccountContracts(t *testing.T) {
},
}

_, err := rt.ExecuteScript(
result, err := rt.ExecuteScript(
Script{
Source: script,
},
Expand All @@ -2142,9 +2158,14 @@ func TestPublicAccountContracts(t *testing.T) {
Location: common.ScriptLocation{},
},
)
errs := checker.RequireCheckerErrors(t, err, 1)
require.NoError(t, err)

require.IsType(t, cadence.Array{}, result)
array := result.(cadence.Array)

assert.IsType(t, &sema.ExternalMutationError{}, errs[0])
require.Len(t, array.Values, 2)
assert.Equal(t, cadence.String("foo"), array.Values[0])
assert.Equal(t, cadence.String("bar"), array.Values[1])
})
}

Expand Down
12 changes: 11 additions & 1 deletion runtime/attachments_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,20 @@ func TestAccountAttachmentExportFailure(t *testing.T) {
import Test from 0x1
access(all) fun main(): &Test.A? {
let r <- Test.makeRWithA()
let a = r[Test.A]
var a = r[Test.A]

// Life span of attachments (references) are validated statically.
// This indirection helps to trick the checker and causes to perform the validation at runtime,
// which is the intention of this test.
a = returnSameRef(a)

destroy r
return a
}

access(all) fun returnSameRef(_ ref: &Test.A?): &Test.A? {
return ref
}
`)

runtimeInterface1 := &testRuntimeInterface{
Expand Down
19 changes: 10 additions & 9 deletions runtime/capabilitycontrollers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
/// > Our version of quicksort is not the fastest possible,
/// > but it's one of the simplest.
///
access(all) fun quickSort(_ items: &[AnyStruct], isLess: fun(Int, Int): Bool) {
access(all) fun quickSort(_ items: auth(Mutate) &[AnyStruct], isLess: fun(Int, Int): Bool) {

fun quickSortPart(leftIndex: Int, rightIndex: Int) {

Expand All @@ -92,6 +92,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {

let pivotIndex = (leftIndex + rightIndex) / 2

items[pivotIndex] <-> items[leftIndex]
items[pivotIndex] <-> items[leftIndex]

var lastIndex = leftIndex
Expand Down Expand Up @@ -1195,7 +1196,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
assert(controllers1.length == 3)

Test.quickSort(
&controllers1 as &[AnyStruct],
&controllers1 as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers1[i]
let b = controllers1[j]
Expand Down Expand Up @@ -1293,7 +1294,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
assert(controllers1.length == 3)

Test.quickSort(
&controllers1 as &[AnyStruct],
&controllers1 as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers1[i]
let b = controllers1[j]
Expand Down Expand Up @@ -1644,7 +1645,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
assert(controllers.length == 3)

Test.quickSort(
&controllers as &[AnyStruct],
&controllers as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers[i]
let b = controllers[j]
Expand Down Expand Up @@ -1722,7 +1723,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {
assert(controllers.length == 3)

Test.quickSort(
&controllers as &[AnyStruct],
&controllers as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers[i]
let b = controllers[j]
Expand Down Expand Up @@ -1977,7 +1978,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {

let controllers1Before = signer.capabilities.storage.getControllers(forPath: storagePath1)
Test.quickSort(
&controllers1Before as &[AnyStruct],
&controllers1Before as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers1Before[i]
let b = controllers1Before[j]
Expand All @@ -1991,7 +1992,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {

let controllers2Before = signer.capabilities.storage.getControllers(forPath: storagePath2)
Test.quickSort(
&controllers2Before as &[AnyStruct],
&controllers2Before as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers2Before[i]
let b = controllers2Before[j]
Expand All @@ -2015,7 +2016,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {

let controllers1After = signer.capabilities.storage.getControllers(forPath: storagePath1)
Test.quickSort(
&controllers1After as &[AnyStruct],
&controllers1After as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers1After[i]
let b = controllers1After[j]
Expand All @@ -2028,7 +2029,7 @@ func TestRuntimeCapabilityControllers(t *testing.T) {

let controllers2After = signer.capabilities.storage.getControllers(forPath: storagePath2)
Test.quickSort(
&controllers2After as &[AnyStruct],
&controllers2After as auth(Mutate) &[AnyStruct],
isLess: fun(i: Int, j: Int): Bool {
let a = controllers2After[i]
let b = controllers2After[j]
Expand Down
4 changes: 2 additions & 2 deletions runtime/convertValues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1912,7 +1912,7 @@ func TestExportReferenceValue(t *testing.T) {
var v:[AnyStruct] = []
acct.save(v, to: /storage/x)

var ref = acct.borrow<&[AnyStruct]>(from: /storage/x)!
var ref = acct.borrow<auth(Insert) &[AnyStruct]>(from: /storage/x)!
ref.append(ref)
return ref
}
Expand Down Expand Up @@ -1947,7 +1947,7 @@ func TestExportReferenceValue(t *testing.T) {
var v:[AnyStruct] = []
acct.save(v, to: /storage/x)

var ref1 = acct.borrow<&[AnyStruct]>(from: /storage/x)!
var ref1 = acct.borrow<auth(Insert) &[AnyStruct]>(from: /storage/x)!
var ref2 = acct.borrow<&[AnyStruct]>(from: /storage/x)!

ref1.append(ref2)
Expand Down
66 changes: 59 additions & 7 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4451,7 +4451,22 @@ var AuthAccountReferenceStaticType = ReferenceStaticType{
}

func (interpreter *Interpreter) getEntitlement(typeID common.TypeID) (*sema.EntitlementType, error) {
location, _, _ := common.DecodeTypeID(interpreter, string(typeID))
location, qualifiedIdentifier, err := common.DecodeTypeID(interpreter, string(typeID))
if err != nil {
return nil, err
}

if location == nil {
ty := sema.BuiltinEntitlements[qualifiedIdentifier]
if ty == nil {
return nil, TypeLoadingError{
TypeID: typeID,
}
}

return ty, nil
}

elaboration := interpreter.getElaboration(location)
if elaboration == nil {
return nil, TypeLoadingError{
Expand All @@ -4470,7 +4485,22 @@ func (interpreter *Interpreter) getEntitlement(typeID common.TypeID) (*sema.Enti
}

func (interpreter *Interpreter) getEntitlementMapType(typeID common.TypeID) (*sema.EntitlementMapType, error) {
location, _, _ := common.DecodeTypeID(interpreter, string(typeID))
location, qualifiedIdentifier, err := common.DecodeTypeID(interpreter, string(typeID))
if err != nil {
return nil, err
}

if location == nil {
ty := sema.BuiltinEntitlementMappings[qualifiedIdentifier]
if ty == nil {
return nil, TypeLoadingError{
TypeID: typeID,
}
}

return ty, nil
}

elaboration := interpreter.getElaboration(location)
if elaboration == nil {
return nil, TypeLoadingError{
Expand Down Expand Up @@ -4691,10 +4721,17 @@ func (interpreter *Interpreter) getAccessOfMember(self Value, identifier string)
return &member.Resolve(interpreter, identifier, ast.EmptyRange, func(err error) {}).Access
}

func (interpreter *Interpreter) mapMemberValueAuthorization(self Value, memberAccess *sema.Access, resultValue Value) Value {
func (interpreter *Interpreter) mapMemberValueAuthorization(
self Value,
memberAccess *sema.Access,
resultValue Value,
resultingType sema.Type,
) Value {

if memberAccess == nil {
return resultValue
}

if mappedAccess, isMappedAccess := (*memberAccess).(sema.EntitlementMapAccess); isMappedAccess {
var auth Authorization
switch selfValue := self.(type) {
Expand All @@ -4706,7 +4743,16 @@ func (interpreter *Interpreter) mapMemberValueAuthorization(self Value, memberAc
}
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, imageAccess)
default:
auth = ConvertSemaAccesstoStaticAuthorization(interpreter, mappedAccess.Codomain())
var access sema.Access
if mappedAccess.Type == sema.IdentityMappingType {
access = sema.AllSupportedEntitlements(resultingType)
}

if access == nil {
access = mappedAccess.Codomain()
}

auth = ConvertSemaAccesstoStaticAuthorization(interpreter, access)
}

switch refValue := resultValue.(type) {
Expand All @@ -4721,15 +4767,21 @@ func (interpreter *Interpreter) mapMemberValueAuthorization(self Value, memberAc
return resultValue
}

func (interpreter *Interpreter) getMemberWithAuthMapping(self Value, locationRange LocationRange, identifier string) Value {
func (interpreter *Interpreter) getMemberWithAuthMapping(
self Value,
locationRange LocationRange,
identifier string,
memberAccessInfo sema.MemberAccessInfo,
) Value {

result := interpreter.getMember(self, locationRange, identifier)
if result == nil {
return nil
}
// once we have obtained the member, if it was declared with entitlement-mapped access, we must compute the output of the map based
// on the runtime authorizations of the acccessing reference or composite
// on the runtime authorizations of the accessing reference or composite
memberAccess := interpreter.getAccessOfMember(self, identifier)
return interpreter.mapMemberValueAuthorization(self, memberAccess, result)
return interpreter.mapMemberValueAuthorization(self, memberAccess, result, memberAccessInfo.ResultingType)
}

// getMember gets the member value by the given identifier from the given Value depending on its type.
Expand Down
Loading