Skip to content

Commit

Permalink
Merge pull request #2492 from darkdrag00nv2/check_authaccount_564
Browse files Browse the repository at this point in the history
  • Loading branch information
turbolent authored May 29, 2023
2 parents a9e18c2 + 2757868 commit b24a708
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 7 deletions.
44 changes: 44 additions & 0 deletions runtime/interpreter/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4043,6 +4043,50 @@ func (interpreter *Interpreter) authAccountBorrowFunction(addressValue AddressVa
)
}

func (interpreter *Interpreter) authAccountCheckFunction(addressValue AddressValue) *HostFunctionValue {

// Converted addresses can be cached and don't have to be recomputed on each function invocation
address := addressValue.ToAddress()

return NewHostFunctionValue(
interpreter,
sema.AuthAccountTypeCheckFunctionType,
func(invocation Invocation) Value {
interpreter := invocation.Interpreter

path, ok := invocation.Arguments[0].(PathValue)
if !ok {
panic(errors.NewUnreachableError())
}

domain := path.Domain.Identifier()
identifier := path.Identifier

storageMapKey := StringStorageMapKey(identifier)

value := interpreter.ReadStored(address, domain, storageMapKey)

if value == nil {
return FalseValue
}

// If there is value stored for the given path,
// check that it satisfies the type given as the type argument.

typeParameterPair := invocation.TypeParameterTypes.Oldest()
if typeParameterPair == nil {
panic(errors.NewUnreachableError())
}

ty := typeParameterPair.Value

valueStaticType := value.StaticType(interpreter)

return AsBoolValue(interpreter.IsSubTypeOfSemaType(valueStaticType, ty))
},
)
}

func (interpreter *Interpreter) authAccountLinkFunction(addressValue AddressValue) *HostFunctionValue {

// Converted addresses can be cached and don't have to be recomputed on each function invocation
Expand Down
7 changes: 7 additions & 0 deletions runtime/interpreter/value_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func NewAuthAccountValue(
var copyFunction *HostFunctionValue
var saveFunction *HostFunctionValue
var borrowFunction *HostFunctionValue
var checkFunction *HostFunctionValue
var linkFunction *HostFunctionValue
var linkAccountFunction *HostFunctionValue
var unlinkFunction *HostFunctionValue
Expand Down Expand Up @@ -188,6 +189,12 @@ func NewAuthAccountValue(
}
return borrowFunction

case sema.AuthAccountTypeCheckFunctionName:
if checkFunction == nil {
checkFunction = inter.authAccountCheckFunction(address)
}
return checkFunction

case sema.AuthAccountTypeLinkFunctionName:
if linkFunction == nil {
linkFunction = inter.authAccountLinkFunction(address)
Expand Down
8 changes: 8 additions & 0 deletions runtime/sema/authaccount.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ pub struct AuthAccount {
/// The path must be a storage path, i.e., only the domain `storage` is allowed
pub fun borrow<T: &Any>(from: StoragePath): T?

/// Returns true if the object in account storage under the given path satisfies the given type,
/// i.e. could be borrowed using the given type.
///
/// The given type must not necessarily be exactly the same as the type of the borrowed object.
///
/// The path must be a storage path, i.e., only the domain `storage` is allowed.
pub fun check<T: Any>(from: StoragePath): Bool

/// **DEPRECATED**: Instead, use `capabilities.storage.issue`, and `capabilities.publish` if the path is public.
///
/// Creates a capability at the given public or private path,
Expand Down
38 changes: 38 additions & 0 deletions runtime/sema/authaccount.gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

93 changes: 86 additions & 7 deletions runtime/tests/interpreter/account_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,10 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {
account.save(<-r, to: /storage/r)
}
fun checkR(): Bool {
return account.check<@R>(from: /storage/r)
}
fun borrowR(): &R? {
return account.borrow<&R>(from: /storage/r)
}
Expand All @@ -652,10 +656,18 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {
return account.borrow<&R>(from: /storage/r)!.foo
}
fun checkR2(): Bool {
return account.check<@R2>(from: /storage/r)
}
fun borrowR2(): &R2? {
return account.borrow<&R2>(from: /storage/r)
}
fun checkR2WithInvalidPath(): Bool {
return account.check<@R2>(from: /storage/wrongpath)
}
fun changeAfterBorrow(): Int {
let ref = account.borrow<&R>(from: /storage/r)!
Expand All @@ -680,7 +692,15 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {

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

// first borrow
// first check & borrow
checkRes, err := inter.Invoke("checkR")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(true),
checkRes,
)

value, err := inter.Invoke("borrowR")
require.NoError(t, err)
Expand Down Expand Up @@ -711,7 +731,15 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {

// TODO: should fail, i.e. return nil

// second borrow
// second check & borrow
checkRes, err = inter.Invoke("checkR")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(true),
checkRes,
)

value, err = inter.Invoke("borrowR")
require.NoError(t, err)
Expand All @@ -727,8 +755,16 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {
})

t.Run("borrow R2", func(t *testing.T) {
checkRes, err := inter.Invoke("checkR2")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(false),
checkRes,
)

_, err := inter.Invoke("borrowR2")
_, err = inter.Invoke("borrowR2")
RequireError(t, err)

require.ErrorAs(t, err, &interpreter.ForceCastTypeMismatchError{})
Expand All @@ -744,6 +780,17 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {

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

t.Run("check R2 with wrong path", func(t *testing.T) {
checkRes, err := inter.Invoke("checkR2WithInvalidPath")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(false),
checkRes,
)
})
})

t.Run("struct", func(t *testing.T) {
Expand Down Expand Up @@ -778,15 +825,23 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {
account.save(s, to: /storage/s)
}
fun checkS(): Bool {
return account.check<S>(from: /storage/s)
}
fun borrowS(): &S? {
return account.borrow<&S>(from: /storage/s)
}
fun foo(): Int {
return account.borrow<&S>(from: /storage/s)!.foo
}
fun borrowS2(): &S2? {
fun checkS2(): Bool {
return account.check<S2>(from: /storage/s)
}
fun borrowS2(): &S2? {
return account.borrow<&S2>(from: /storage/s)
}
Expand Down Expand Up @@ -821,7 +876,15 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {

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

// first borrow
// first check & borrow
checkRes, err := inter.Invoke("checkS")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(true),
checkRes,
)

value, err := inter.Invoke("borrowS")
require.NoError(t, err)
Expand Down Expand Up @@ -852,7 +915,15 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {

// TODO: should fail, i.e. return nil

// second borrow
// second check & borrow
checkRes, err = inter.Invoke("checkS")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(true),
checkRes,
)

value, err = inter.Invoke("borrowS")
require.NoError(t, err)
Expand All @@ -868,6 +939,14 @@ func TestInterpretAuthAccount_borrow(t *testing.T) {
})

t.Run("borrow S2", func(t *testing.T) {
checkRes, err := inter.Invoke("checkS2")
require.NoError(t, err)
AssertValuesEqual(
t,
inter,
interpreter.AsBoolValue(false),
checkRes,
)

_, err = inter.Invoke("borrowS2")
RequireError(t, err)
Expand Down

0 comments on commit b24a708

Please sign in to comment.