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

FLIP for entitlements and safe reference downcasting #54

Merged
merged 34 commits into from
May 23, 2023
Merged
Changes from 2 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
15865cd
beginning of FLIP
dsainati1 Dec 14, 2022
7d033d4
add more details
dsainati1 Dec 15, 2022
73b0757
add section on interface inheritance
dsainati1 Dec 16, 2022
be521b9
fix formatting
dsainati1 Dec 16, 2022
74551c7
fix formatting
dsainati1 Dec 16, 2022
8a5cfa1
typo
dsainati1 Dec 16, 2022
fd62422
Apply suggestions from code review
dsainati1 Jan 3, 2023
ba6a3d0
Merge branch 'sainati/auth-fields' of github.com:onflow/flips into sa…
dsainati1 Jan 3, 2023
040d35f
respond to review
dsainati1 Jan 3, 2023
85edfaa
add an alternatives considered section
dsainati1 Jan 3, 2023
c92d088
clarify auth types are subtypes of non-auth references
dsainati1 Jan 4, 2023
8fe43e9
add section about potentially removing restricted types
dsainati1 Jan 4, 2023
590fbe3
Apply suggestions from code review
dsainati1 Jan 5, 2023
f7f7079
add section about rollout
dsainati1 Jan 10, 2023
1192f36
update rollout section to remove reference to versioned references
dsainati1 Jan 20, 2023
bbff7fc
update FLIP to incorporate new entitlements idea, currently generated…
dsainati1 Feb 2, 2023
f842b76
add section about standalone entitlements
dsainati1 Feb 2, 2023
30ed8e2
update FLIP to refer to separate entitlement language objects
dsainati1 Feb 17, 2023
8dba175
update FLIP to improve subtyping model for interfaces
dsainati1 Feb 21, 2023
7e3ac2b
add info about conjuctive and disjunctive entitlement sets
dsainati1 Mar 9, 2023
e7844ee
Merge branch 'main' of github.com:onflow/flips into sainati/auth-fields
dsainati1 Mar 9, 2023
b959350
add sections about entitlement mappings
dsainati1 Mar 14, 2023
5ad5053
fix minor mistake
dsainati1 Mar 14, 2023
2951197
fix typo
dsainati1 Mar 15, 2023
0e4e857
fix formula typo
dsainati1 Mar 17, 2023
9554833
remove section about restrictions on which entitlements may appear on…
dsainati1 Mar 31, 2023
1990033
Merge branch 'main' of github.com:onflow/flips into sainati/auth-fields
dsainati1 Apr 25, 2023
a362d9c
rewrite attachments section to use new proposed idea
dsainati1 Apr 25, 2023
c5d0eae
remove dynamic behavior for entitlements
dsainati1 Apr 25, 2023
cf4b8d6
respond to review
dsainati1 May 2, 2023
3ae4318
respond to review
dsainati1 May 10, 2023
b156ed4
Apply suggestions from code review
dsainati1 May 18, 2023
f6fba22
add more detail to example
dsainati1 May 19, 2023
7d6ab3c
Merge branch 'sainati/auth-fields' of github.com:onflow/flips into sa…
dsainati1 May 19, 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
12 changes: 6 additions & 6 deletions cadence/2022-12-14-auth-remodel.md
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file name should be 20221214-...

Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ since if this were to typecheck, anybody with a `&R` reference could upcast it t
The second, more complex part of this proposal, is a change to the behavior of references to allow the `auth` modifier not to
refer to the entire referenced value, but to the specific set of interfaces to which the referenced value has `auth` permissions.
To express this, the `auth` keyword can now be used with similar syntax to that of restricted types: `auth{T1, T2, ...}`, where the `T`s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will the old syntax (i.e: without curly braces) continue to be supported, say for restricted types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally the old syntax would become deprecated eventually, as currently the only reasonable way to interpret it is as a reference that is auth over the entirety of the referenced type, which in the new model would be a very dangerous behavior to have as a default. What would be the use case for keeping the old auth syntax that does not require a restriction set?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sweet, then we can reuse the restricted types syntax when we add algebraic effects 🥲

in the curly braces denote the interface types to which that reference has `auth` acccess. This permits these references
in the curly braces denote the interface types to which that reference has `auth` access. This permits these references
to access `auth` members on the interfaces to which they have `auth` access. So, for example, given three interface definitions and
a composite definition:

Expand Down Expand Up @@ -219,7 +219,7 @@ pub resource Vault: Provider, Receiver, Balance {
```

Then, someone with a `&{Balance}` reference would be able to cast this to a `&{Receiver}` and call `deposit` on it.
They would also be able to cast this to a `&Vault` refrence, but because this reference is non-`auth` for `Provider`,
They would also be able to cast this to a `&Vault` reference, but because this reference is non-`auth` for `Provider`,
they would be unable to call the `withdraw` function. However, if a user possessed a `auth{Provider} &{Balance}` reference,
they would be able to cast this to `auth{Provider} &{Provider}` and call `withdraw`.
Copy link
Member

@SupunS SupunS Jan 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auth{T} &{U} syntax is a bit confusing to me.

My first concern is, in a concrete type (struct/resource) scenario, the reference-taking syntax is let ref = &r as auth &T, but for a restricted type, the user has to specify the type twice let ref = &r as auth{T} &{T}. Maybe make the T in auth{T} optional if both the auth-type and the restricted type are the same? Anyway they can't downcast it further I guess.

The second concern is it is easy to confuse the type of the resulting reference. For eg: auth{Provider} &{Balance} made me wonder whether I can (or why I can't) call withdraw on the resulting reference.
I don't really have any suggestions for an alternative syntax, but if we can find one/improve this to iron out any potential confusion, that would be great.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the syntax is a little bit confusing; at first glance it seems like you have to specify the type twice (once in the auth{T} and once in the &{T}, but they are really doing quite different things. I think it is going to be quite rare for users to want to declare a reference value this way, however. In fact, with these changes there is little reason to ever actually create a reference value with anything other than its underlying concrete type: let ref = &r as auth{Provider} &Vault makes a lot more sense than let ref = &r as auth{Provider} &{Provider, Receiver} given that reference types can now be downcast. The "security" aspect of restricted types is effectively being moved to the auth part of the type, while the actual reference type itself is now only being used for interface conformance checking.

I suspect that if we implemented this change, we would only really see restricted types being used as supertypes; i.e. if I want to write a function that operates over all Providers I would write it as fun(_ p: {Provider}).

Copy link
Member

@turbolent turbolent Jan 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially had feedback similar to Supun's, but ended up not posting it, so it's great it came up again:

Restrictions (Us in T{Us}) are not really restrictions anymore, as downcasting is now allowed.

We still might want to express something like T{Us} (where Us is a set of interfaces) for the case where T is AnyStruct/AnyResource. Maybe we should just make the syntax {Us} and call it an "interface set"?

The continued existence of restricted types (T{Us}) maybe cause confusion for developers, so maybe we should just get rid of them along the way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I really like this idea; the interface set type makes a lot of sense and is more intuitive than restricted types anyways.

Copy link
Member

@SupunS SupunS Jan 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With restricted types gone, {Us} sounds more like an 'intersection type' 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, {Us} has been always pretty much like TypeScript's intersection types. Swift has protocol composition, a similar feature (even uses the same U1 & U2 syntax as TS), though there such a type is not first class (e.g a variable cannot have such a type)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for changing restricted types to intersection types. Allowing interfaces in type position (even if they need to be qualified somehow) would obviate the need for a separate Interface proxy type, making Cadence issue #2233 trivial to implement

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe replacing restricted types with standalone intersection types should be its own FLIP?


Expand All @@ -243,7 +243,7 @@ to call `pub` members like `withdraw` unless those methods were updated to be `a
## Questions and Discussion Topics

* The upcoming proposed changes to permit interfaces to conform to other interfaces will necessarily change the subtyping rules
for `auth` refrences, as it would no longer be sufficient to compare the sets for the two `auth` references just based on membership.
for `auth` references, as it would no longer be sufficient to compare the sets for the two `auth` references just based on membership.
The membership check would still exist, but it would function as a width subtyping rule, in addition to a depth rule based on
interface chains. I.e. it would be the case that for two auth references, `auth{U} &X <: auth{T1} &X`, if `U <: T`.

Expand All @@ -263,7 +263,7 @@ whenever `∀T ∈ {T1, T2, ... }, ∃U ∈ {U1, U2, ... }, U <: T`.

we would have `auth{E} &R <: auth{C} &R <: auth{A} &R <: &R` and `auth{E} &R <: auth{D} &R <: auth{B} &R <: &R`.
It would also be the case that `auth{D, C} &R <: auth{A} &R` as well, because `C <: A`, and that `auth{E} &R <: auth{B, C} &R`,
beacuse `E <: B` and `E <: C`.
because `E <: B` and `E <: C`.

* It is unclear how this should interact with the new attachments feature. Prior to this proposal a functional mental model
for attachments was to treat them as implicit type-disambiguated `pub` fields on the resource or struct to which they were attached.
Expand All @@ -272,7 +272,7 @@ would have access to functions like `withdraw` via the `base` reference) if they
would be visible with such a reference.

One simple approach would be to allow attachments to be accessed only on values that have `auth` access to the attachment's `base` type.
I.e. given an `attachment A for I`, `v[A]` would be permissable when `v` has type `auth{I} &R` but not when `v` is just a regular `&R`,
I.e. given an `attachment A for I`, `v[A]` would be permissible when `v` has type `auth{I} &R` but not when `v` is just a regular `&R`,
or even an `&{I}`. Functionally this would mean that attachments would become `auth` fields in the mental model described above.

This approach is simple but very restrictive. In the motivating `KittyHat` use case for example, only users with an `auth`-reference
Expand All @@ -283,7 +283,7 @@ would be visible with such a reference.

An alternative would be to implicitly parameterize the attachment's `auth` access over the `auth` access of its base value. In this model,
attachments would remain `pub` accessible, but would themselves permit the declaration of `auth` members. The `base` value,
which currently is simply a `&R` reference for an attachment `attachment A for R` in any of `A`'s member functions, would now have it's `auth`-ness
which currently is simply a `&R` reference for an attachment `attachment A for R` in any of `A`'s member functions, would now have its `auth`-ness
depend on the `auth`-ness of the member function in question. In a member declaration `access(auth) fun foo()` in `A`, the `base` variable would have
type `auth &R`, while in a member declaration in `A` `pub fun bar()`, `base` would just be an `&R`. This would effectively mean that the `auth`-access
members of the `base` would only be available to the attachment author in `auth`-access members on the attachment. Similarly, in an `auth`-access
Expand Down