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

Convert generic container types on upcast #2567

Merged
merged 12 commits into from
Jun 21, 2023
319 changes: 319 additions & 0 deletions runtime/entitlements_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,3 +501,322 @@ func TestAccountEntitlementNamingConflict(t *testing.T) {
var accessError *sema.InvalidAccessError
require.ErrorAs(t, errs[0], &accessError)
}

func TestAccountEntitlementCapabilityCasting(t *testing.T) {
t.Parallel()

storage := newTestLedger(nil, nil)
rt := newTestInterpreterRuntimeWithAttachments()
accountCodes := map[Location][]byte{}

deployTx := DeploymentTransaction("Test", []byte(`
pub contract Test {
pub entitlement X
pub entitlement Y

pub resource R {}

pub fun createR(): @R {
return <-create R()
}
}
`))

transaction1 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let r <- Test.createR()
signer.save(<-r, to: /storage/foo)
signer.link<auth(Test.X) &Test.R>(/public/foo, target: /storage/foo)
}
}
`)

transaction2 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let capX = signer.getCapability<auth(Test.X) &Test.R>(/public/foo)
let upCap = capX as Capability<&Test.R>
let downCap = upCap as! Capability<auth(Test.X) &Test.R>
}
}
`)

runtimeInterface1 := &testRuntimeInterface{
storage: storage,
log: func(message string) {},
emitEvent: func(event cadence.Event) error {
return nil
},
resolveLocation: singleIdentifierLocationResolver(t),
getSigningAccounts: func() ([]Address, error) {
return []Address{[8]byte{0, 0, 0, 0, 0, 0, 0, 1}}, nil
},
updateAccountContractCode: func(location common.AddressLocation, code []byte) error {
accountCodes[location] = code
return nil
},
getAccountContractCode: func(location common.AddressLocation) (code []byte, err error) {
code = accountCodes[location]
return code, nil
},
}

nextTransactionLocation := newTransactionLocationGenerator()

err := rt.ExecuteTransaction(
Script{
Source: deployTx,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction1,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction2,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)

require.ErrorAs(t, err, &interpreter.ForceCastTypeMismatchError{})
}

func TestAccountEntitlementCapabilityDictionary(t *testing.T) {
t.Parallel()

storage := newTestLedger(nil, nil)
rt := newTestInterpreterRuntimeWithAttachments()
accountCodes := map[Location][]byte{}

deployTx := DeploymentTransaction("Test", []byte(`
pub contract Test {
pub entitlement X
pub entitlement Y

pub resource R {}

pub fun createR(): @R {
return <-create R()
}
}
`))

transaction1 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let r <- Test.createR()
signer.save(<-r, to: /storage/foo)
signer.link<auth(Test.X) &Test.R>(/public/foo, target: /storage/foo)

let r2 <- Test.createR()
signer.save(<-r2, to: /storage/bar)
signer.link<auth(Test.Y) &Test.R>(/public/bar, target: /storage/bar)
}
}
`)

transaction2 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let capX = signer.getCapability<auth(Test.X) &Test.R>(/public/foo)
let capY = signer.getCapability<auth(Test.Y) &Test.R>(/public/bar)

let dict: {Type: Capability<&Test.R>} = {}
dict[capX.getType()] = capX
dict[capY.getType()] = capY

let newCapX = dict[capX.getType()]!
let ref = newCapX.borrow()!
let downCast = ref as! auth(Test.X) &Test.R
}
}
`)

runtimeInterface1 := &testRuntimeInterface{
storage: storage,
log: func(message string) {},
emitEvent: func(event cadence.Event) error {
return nil
},
resolveLocation: singleIdentifierLocationResolver(t),
getSigningAccounts: func() ([]Address, error) {
return []Address{[8]byte{0, 0, 0, 0, 0, 0, 0, 1}}, nil
},
updateAccountContractCode: func(location common.AddressLocation, code []byte) error {
accountCodes[location] = code
return nil
},
getAccountContractCode: func(location common.AddressLocation) (code []byte, err error) {
code = accountCodes[location]
return code, nil
},
}

nextTransactionLocation := newTransactionLocationGenerator()

err := rt.ExecuteTransaction(
Script{
Source: deployTx,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction1,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction2,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)

require.ErrorAs(t, err, &interpreter.ForceCastTypeMismatchError{})
}

func TestAccountEntitlementGenericCapabilityDictionary(t *testing.T) {
t.Parallel()

storage := newTestLedger(nil, nil)
rt := newTestInterpreterRuntimeWithAttachments()
accountCodes := map[Location][]byte{}

deployTx := DeploymentTransaction("Test", []byte(`
pub contract Test {
pub entitlement X
pub entitlement Y

pub resource R {}

pub fun createR(): @R {
return <-create R()
}
}
`))

transaction1 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let r <- Test.createR()
signer.save(<-r, to: /storage/foo)
signer.link<auth(Test.X) &Test.R>(/public/foo, target: /storage/foo)

let r2 <- Test.createR()
signer.save(<-r2, to: /storage/bar)
signer.link<auth(Test.Y) &Test.R>(/public/bar, target: /storage/bar)
}
}
`)

transaction2 := []byte(`
import Test from 0x1
transaction {
prepare(signer: AuthAccount) {
let capX = signer.getCapability<auth(Test.X) &Test.R>(/public/foo)
let capY = signer.getCapability<auth(Test.Y) &Test.R>(/public/bar)

let dict: {Type: Capability} = {}
dict[capX.getType()] = capX
dict[capY.getType()] = capY

let newCapX = dict[capX.getType()]!
let ref = newCapX.borrow<auth(Test.X) &Test.R>()!
let downCast = ref as! auth(Test.X) &Test.R
dsainati1 marked this conversation as resolved.
Show resolved Hide resolved
}
}
`)

runtimeInterface1 := &testRuntimeInterface{
storage: storage,
log: func(message string) {},
emitEvent: func(event cadence.Event) error {
return nil
},
resolveLocation: singleIdentifierLocationResolver(t),
getSigningAccounts: func() ([]Address, error) {
return []Address{[8]byte{0, 0, 0, 0, 0, 0, 0, 1}}, nil
},
updateAccountContractCode: func(location common.AddressLocation, code []byte) error {
accountCodes[location] = code
return nil
},
getAccountContractCode: func(location common.AddressLocation) (code []byte, err error) {
code = accountCodes[location]
return code, nil
},
}

nextTransactionLocation := newTransactionLocationGenerator()

err := rt.ExecuteTransaction(
Script{
Source: deployTx,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction1,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)
require.NoError(t, err)

err = rt.ExecuteTransaction(
Script{
Source: transaction2,
},
Context{
Interface: runtimeInterface1,
Location: nextTransactionLocation(),
},
)

require.NoError(t, err)
}
Loading