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

Type checking for authorized references #2405

Merged
merged 52 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
475c13a
refactor skeleton
dsainati1 Mar 21, 2023
837c44f
encode and decode authorizations
dsainati1 Mar 21, 2023
230cb69
populate ReferenceType{} constructors with necessary Authorization fi…
dsainati1 Mar 21, 2023
70af68f
populate ReferenceType{} constructors with necessary Authorization fi…
dsainati1 Mar 21, 2023
472f6e3
reference subtyping is no longer special cased
dsainati1 Mar 21, 2023
5048129
implement permission checking for entitlement set member access
dsainati1 Mar 22, 2023
cef512f
implement image computation for entitlement maps
dsainati1 Mar 22, 2023
bd13146
check that mapped reference fields are initialized with the full codo…
dsainati1 Mar 23, 2023
3649391
entitlement mapping authorization can only be used in reference fields
dsainati1 Mar 23, 2023
6f91ca2
update casting tests for new reference semantics
dsainati1 Mar 23, 2023
0ea531d
implement entitlements checking for attachment declarations
dsainati1 Mar 24, 2023
ad50de0
type checking for entitled attachment access
dsainati1 Mar 24, 2023
e33a84c
update runtime reference type constructor function type
dsainati1 Mar 27, 2023
545d7dc
improve test case
dsainati1 Mar 27, 2023
9ed1392
refactor declaration modifier checking for simplicity
dsainati1 Mar 27, 2023
05b5e78
add more detail to test
dsainati1 Mar 27, 2023
20953d5
all entitlement set and entitlement map authorizations must contain e…
dsainati1 Mar 28, 2023
d6be409
the result value in postconditions is fully entitled to the returned …
dsainati1 Mar 28, 2023
fdeffc3
fix tests
dsainati1 Mar 29, 2023
171716b
don't create empty entitled references for result variables
dsainati1 Mar 30, 2023
c8bd592
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 Mar 30, 2023
fa4f302
prevent creating references with runtime disjoint entitlement sets
dsainati1 Mar 31, 2023
5cbe93a
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 Apr 3, 2023
0e4741f
mapped entitlements can also be used in the return types of accessor …
dsainati1 Apr 3, 2023
e33fa44
implement type checking for uses of mapped entitlement references in …
dsainati1 Apr 3, 2023
28b9852
fix comment
dsainati1 Apr 4, 2023
f6cde91
add tests for optional chained access
dsainati1 Apr 4, 2023
b2704c3
fix optional chaining mapped access
dsainati1 Apr 4, 2023
1e05696
yet more tests
dsainati1 Apr 4, 2023
9d37521
add tests to ensure mutation and writes are not allowed on entitled f…
dsainati1 Apr 4, 2023
4d2575f
add more comments
dsainati1 Apr 14, 2023
6439a7a
add test for cast from map to set
dsainati1 Apr 21, 2023
a7ef3c2
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 Apr 28, 2023
2f6b9a4
update attachment self and base typing to simpler version
dsainati1 Apr 28, 2023
f95e33a
permit the creation of runtime disjoint sets
dsainati1 May 1, 2023
dc767d6
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 May 5, 2023
89294e8
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 May 15, 2023
ae67ae8
Update runtime/interpreter/statictype.go
dsainati1 May 15, 2023
7e50da3
Merge branch 'sainati/entitled-references' of github.com:onflow/caden…
dsainati1 May 15, 2023
184fcd2
respond to review
dsainati1 May 15, 2023
f305da3
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 May 17, 2023
71aef60
Merge branch 'sainati/entitlements-checking' of github.com:onflow/cad…
dsainati1 May 19, 2023
7ac88ad
uncomment test
dsainati1 May 19, 2023
0437965
respond to review
dsainati1 May 22, 2023
48b133c
fix lint
dsainati1 May 24, 2023
a1822df
Update runtime/interpreter/statictype.go
dsainati1 May 24, 2023
6dbf7ab
respond to review
dsainati1 May 24, 2023
8eb0dc3
Merge branch 'sainati/entitled-references' of github.com:onflow/caden…
dsainati1 May 24, 2023
d7f7ec3
respond to review
dsainati1 May 31, 2023
88b36ac
respond to review
dsainati1 Jun 1, 2023
08d6d84
remove outdated subtyping doc
dsainati1 Jun 1, 2023
f9b39e2
dummies for compilation failures to be fixed later
dsainati1 Jun 1, 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
82 changes: 57 additions & 25 deletions encoding/json/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,29 +111,30 @@ func (d *Decoder) Decode() (value cadence.Value, err error) {
}

const (
typeKey = "type"
kindKey = "kind"
valueKey = "value"
keyKey = "key"
nameKey = "name"
fieldsKey = "fields"
initializersKey = "initializers"
idKey = "id"
targetPathKey = "targetPath"
borrowTypeKey = "borrowType"
domainKey = "domain"
identifierKey = "identifier"
staticTypeKey = "staticType"
addressKey = "address"
pathKey = "path"
authorizedKey = "authorized"
sizeKey = "size"
typeIDKey = "typeID"
restrictionsKey = "restrictions"
labelKey = "label"
parametersKey = "parameters"
returnKey = "return"
purityKey = "purity"
typeKey = "type"
kindKey = "kind"
valueKey = "value"
keyKey = "key"
nameKey = "name"
fieldsKey = "fields"
initializersKey = "initializers"
idKey = "id"
targetPathKey = "targetPath"
borrowTypeKey = "borrowType"
domainKey = "domain"
identifierKey = "identifier"
staticTypeKey = "staticType"
addressKey = "address"
pathKey = "path"
authorizationKey = "authorization"
entitlementsKey = "entitlements"
sizeKey = "size"
typeIDKey = "typeID"
restrictionsKey = "restrictions"
labelKey = "label"
parametersKey = "parameters"
returnKey = "return"
purityKey = "purity"
)

func (d *Decoder) decodeJSON(v any) cadence.Value {
Expand Down Expand Up @@ -917,6 +918,38 @@ func (d *Decoder) decodeFunctionType(returnValue, parametersValue, id any, purit
).WithID(toString(id))
}

func (d *Decoder) decodeAuthorization(authorizationJSON any) cadence.Authorization {
obj := toObject(authorizationJSON)
kind := obj.Get(kindKey)

switch kind {
case "Unauthorized":
return cadence.UnauthorizedAccess
case "EntitlementMapAuthorization":
entitlements := toSlice(obj.Get(entitlementsKey))
m := toString(toObject(entitlements[0]).Get("typeID"))
return cadence.NewEntitlementMapAuthorization(d.gauge, common.TypeID(m))
case "EntitlementConjunctionSet":
var typeIDs []common.TypeID
entitlements := toSlice(obj.Get(entitlementsKey))
for _, entitlement := range entitlements {
id := toString(toObject(entitlement).Get("typeID"))
typeIDs = append(typeIDs, common.TypeID(id))
}
return cadence.NewEntitlementSetAuthorization(d.gauge, typeIDs, cadence.Conjunction)
case "EntitlementDisjunctionSet":
var typeIDs []common.TypeID
entitlements := toSlice(obj.Get(entitlementsKey))
for _, entitlement := range entitlements {
id := toString(toObject(entitlement).Get("typeID"))
typeIDs = append(typeIDs, common.TypeID(id))
}
return cadence.NewEntitlementSetAuthorization(d.gauge, typeIDs, cadence.Disjunction)
}

panic(errors.NewDefaultUserError("invalid kind in authorization: %s", kind))
}

func (d *Decoder) decodeNominalType(
obj jsonObject,
kind, typeID string,
Expand Down Expand Up @@ -1125,10 +1158,9 @@ func (d *Decoder) decodeType(valueJSON any, results typeDecodingResults) cadence
d.decodeType(obj.Get(typeKey), results),
)
case "Reference":
auth := toBool(obj.Get(authorizedKey))
return cadence.NewMeteredReferenceType(
d.gauge,
auth,
d.decodeAuthorization(obj.Get(authorizationKey)),
d.decodeType(obj.Get(typeKey), results),
)
case "Any":
Expand Down
51 changes: 45 additions & 6 deletions encoding/json/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,15 @@ type jsonDictionaryType struct {
Kind string `json:"kind"`
}

type jsonAuthorization struct {
Kind string `json:"kind"`
Entitlements []jsonNominalType `json:"entitlements"`
}

type jsonReferenceType struct {
Type jsonValue `json:"type"`
Kind string `json:"kind"`
Authorized bool `json:"authorized"`
Type jsonValue `json:"type"`
Kind string `json:"kind"`
Authorization jsonAuthorization `json:"authorization"`
}

type jsonRestrictedType struct {
Expand Down Expand Up @@ -593,6 +598,40 @@ func prepareComposite(kind, id string, fieldTypes []cadence.Field, fields []cade
}
}

func prepareAuthorization(auth cadence.Authorization) jsonAuthorization {
SupunS marked this conversation as resolved.
Show resolved Hide resolved
var kind string
var entitlements []jsonNominalType
switch auth := auth.(type) {
case cadence.Unauthorized:
kind = "Unauthorized"
case cadence.EntitlementMapAuthorization:
kind = "EntitlementMapAuthorization"
entitlements = []jsonNominalType{
{
Kind: "EntitlementMap",
TypeID: string(auth.TypeID),
},
}
case cadence.EntitlementSetAuthorization:
for _, entitlement := range auth.Entitlements {
entitlements = append(entitlements, jsonNominalType{
Kind: "Entitlement",
TypeID: string(entitlement),
})
}
switch auth.Kind {
case cadence.Conjunction:
kind = "EntitlementConjunctionSet"
case cadence.Disjunction:
kind = "EntitlementDisjunctionSet"
}
}
return jsonAuthorization{
Kind: kind,
Entitlements: entitlements,
}
}

func preparePath(x cadence.Path) jsonValue {
return jsonValueObject{
Type: pathTypeStr,
Expand Down Expand Up @@ -810,9 +849,9 @@ func prepareType(typ cadence.Type, results typePreparationResults) jsonValue {
return typeJson
case *cadence.ReferenceType:
return jsonReferenceType{
Kind: "Reference",
Authorized: typ.Authorized,
Type: prepareType(typ.Type, results),
Kind: "Reference",
Authorization: prepareAuthorization(typ.Authorization),
Type: prepareType(typ.Type, results),
}
case *cadence.RestrictedType:
restrictions := make([]jsonValue, 0)
Expand Down
148 changes: 145 additions & 3 deletions encoding/json/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/onflow/cadence/runtime"
"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/interpreter"
"github.com/onflow/cadence/runtime/tests/checker"

Expand Down Expand Up @@ -2326,8 +2327,8 @@ func TestEncodeType(t *testing.T) {
t,
cadence.TypeValue{
StaticType: &cadence.ReferenceType{
Authorized: false,
Type: cadence.IntType{},
Authorization: cadence.UnauthorizedAccess,
Type: cadence.IntType{},
},
},
// language=json
Expand All @@ -2340,13 +2341,154 @@ func TestEncodeType(t *testing.T) {
"type": {
"kind": "Int"
},
"authorized": false
"authorization": {
"kind": "Unauthorized",
"entitlements": null
}
}
}
}
`,
)
})

t.Run("with static auth(foo) &int", func(t *testing.T) {

testEncodeAndDecode(
t,
cadence.TypeValue{
StaticType: &cadence.ReferenceType{
Authorization: cadence.EntitlementMapAuthorization{
TypeID: "foo",
},
Type: cadence.IntType{},
},
},
// language=json
`
{
"type": "Type",
"value": {
"staticType": {
"kind": "Reference",
"type": {
"kind": "Int"
},
"authorization": {
"kind": "EntitlementMapAuthorization",
"entitlements": [
{
"kind": "EntitlementMap",
"typeID": "foo",
"type": null,
"fields": null,
"initializers": null
}
]
}
}
}
}
`,
)
})

t.Run("with static auth(X, Y) &int", func(t *testing.T) {

testEncodeAndDecode(
t,
cadence.TypeValue{
StaticType: &cadence.ReferenceType{
Authorization: cadence.EntitlementSetAuthorization{
Kind: cadence.Conjunction,
Entitlements: []common.TypeID{"X", "Y"},
},
Type: cadence.IntType{},
},
},
// language=json
`
{
"type": "Type",
"value": {
"staticType": {
"kind": "Reference",
"type": {
"kind": "Int"
},
"authorization": {
"kind": "EntitlementConjunctionSet",
"entitlements": [
{
"kind": "Entitlement",
"typeID": "X",
"type": null,
"fields": null,
"initializers": null
},
{
"kind": "Entitlement",
"typeID": "Y",
"type": null,
"fields": null,
"initializers": null
}
]
}
}
}
}
`,
)
})

t.Run("with static auth(X | Y) &int", func(t *testing.T) {

testEncodeAndDecode(
t,
cadence.TypeValue{
StaticType: &cadence.ReferenceType{
Authorization: cadence.EntitlementSetAuthorization{
Kind: cadence.Disjunction,
Entitlements: []common.TypeID{"X", "Y"},
},
Type: cadence.IntType{},
},
},
// language=json
`
{
"type": "Type",
"value": {
"staticType": {
"kind": "Reference",
"type": {
"kind": "Int"
},
"authorization": {
"kind": "EntitlementDisjunctionSet",
"entitlements": [
{
"kind": "Entitlement",
"typeID": "X",
"type": null,
"fields": null,
"initializers": null
},
{
"kind": "Entitlement",
"typeID": "Y",
"type": null,
"fields": null,
"initializers": null
}
]
}
}
}
}
`,
)
})

t.Run("with static function", func(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions runtime/common/memorykind.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ const (
MemoryKindDictionaryStaticType
MemoryKindOptionalStaticType
MemoryKindRestrictedStaticType
MemoryKindUnauthorizedStaticAccess
MemoryKindEntitlementSetStaticAccess
MemoryKindEntitlementMapStaticAccess
MemoryKindReferenceStaticType
MemoryKindCapabilityStaticType
MemoryKindFunctionStaticType
Expand Down Expand Up @@ -122,6 +125,8 @@ const (
MemoryKindCadenceResourceInterfaceType
MemoryKindCadenceContractInterfaceType
MemoryKindCadenceFunctionType
MemoryKindCadenceEntitlementSetAccess
MemoryKindCadenceEntitlementMapAccess
MemoryKindCadenceReferenceType
MemoryKindCadenceRestrictedType
MemoryKindCadenceCapabilityType
Expand Down
Loading