How could I access the resource in a resource type?

I know that by borrowing and dereference I could access the value of the field of a resource. But I can’t use this method to access a resource in a resource. In the following code, fun1 can access a resource’s variable (u64) , but fun2 cannot access that resource’s variable(resource) .

resource T1 {
	a: u64
}
resource T2 {
	t1: T1,
	b: u64
}
//ok
public fun1(): u64 acquires T2
{
    let add: address;
    let ref: &mut Self.T2;     
    let x: u64;   
    add = get_txn_sender();
    ref = borrow_global_mut<T2>(copy(add));
    x = *&move(ref).b;
    return move(b);
}
//error
public fun2(): Self.T1 acquires T2
{
    let add: address;
    let ref: &mut Self.T2;     
    let t: T1;   
    add = get_txn_sender();
    ref = borrow_global_mut<T2>(copy(add));
    t = *&move(ref).t1;
    return move(t);
}

So how could I access the field (resource) in a resource type?

fun2 is using the correct scheme for accessing a child resource: acquire a reference to the parent resource, then acquire a reference to the field that holds the child resource.

The problem with fun2 is that it’s copying a resource via t = *&move(ref).t1. This statement is actually doing two things:

  • acquire a reference to the t1 field of t (ok)
  • dereference it (not ok, because it copies the resource)

The things you can do with the reference to a resource (e.g., t1) are:

  • Call a procedure that takes a &Self.T1
  • Acquire a reference to a field of the Self.T1 resource (but only because T1 is defined in the current module; this wouldn’t work if T1 were a resource defined elsewhere)
  • Return it (though not in this case, because it’s a reference to a global. This would be allowed if ref were a formal of fun2).

Hope this is useful! If you share some context on what you are trying to do in fun2, we can try to help.

1 Like

Thank you very much for your answer. It helped me a lot.
I’ve summarized several resource usage scenarios as follows:

  1. access a field (u64) in a resource
module T
{
    resource T1
    {
        a: u64
    }
    resource T2
    {
        b: u64,
        t1: Self.T1
    }
    public fun1(): u64 acquires T1
    {
        let add: address;
        let ref: &mut Self.T1;
        let x: u64;
        add = get_txn_sender();
        ref = borrow_global_mut<T1>(move(add));
        x = *&move(ref).a;
        return move(x);
    }
}
  1. modify a field(u64) in a resource
module T
{
    resource T1
    {
        a: u64
    }
    resource T2
    {
        b: u64,
        t1: Self.T1
    }
    public fun2() acquires T1
    {
        let add: address;
        let ref: &mut Self.T1;
        let x: u64;
        add = get_txn_sender();
        ref = borrow_global_mut<T1>(move(add));
        x = *&copy(ref).a;
        *(&mut move(ref).a) = move(x) + 1;
        return;
    }
}
  1. access a field (u64) in a child resource of the resource
module T
{
    resource T1
    {
        a: u64
    }
    resource T2
    {
        b: u64,
        t1: Self.T1
    }
    public fun3(): u64 acquires T2
    {
        let add: address;
        let ref: &mut Self.T2;     
        let t: &mut Self.T1;   
        let x: u64;  
        add = get_txn_sender();
        ref = borrow_global_mut<T2>(move(add));
        t = &mut move(ref).t1;
        x = *&copy(t).a;
        return move(x);
    }
}
  1. modify a field (u64) in a child resource of a parent resource
module T
{
    resource T1
    {
        a: u64
    }
    resource T2
    {
        b: u64,
        t1: Self.T1
    }
    public fun4() acquires T2
    {
        let add: address;
        let ref: &mut Self.T2;     
        let t: &mut Self.T1;   
        let x: u64;  
        add = get_txn_sender();
        ref = borrow_global_mut<T2>(move(add));
        t = &mut move(ref).t1;
        x = *&copy(t).a;
        *(&mut move(t).a) = move(x) + 1;
        return;
    }
}

Is my method correct?
And when the child resource isn’t in the same module with the parent resource, like follow, what could I do to access the child resource and its member variables?

module Tt
{
    resource T3
    {
        c: u64
    }
}
module T
{
    import Transaction.Tt;
    resource T1
    {
        a: u64
    }
    resource T2
    {
        b: u64,
        t1: Self.T1,
        t3: Tt.T3
    }
    public fun5()
    {
        //I want to access or modify the value of c in resource T3 
    }
}
1 Like

Is my method correct?

Yes, the examples above all look correct to me.

And when the child resource isn’t in the same module with the parent resource, like follow, what could I do to access the child resource and its member variables?

A field f of a resource S can only be borrowed inside the module that declares S (i.e., “all fields are private”). This means that if you want to access f outside of S, you can only do it by calling a procedure of S.

Thank you very much. With your help, I successfully realized the function of accessing the child resource in different module.
And I still have a question: If I publish a resource T to address add , does that mean I publish the child resource of T to add at the same time?

And I still have a question: If I publish a resource T to address add , does that mean I publish the child resource of T to add at the same time?

If I understand your question correctly, the answer is yes. Each address has at most one resource of a given type published at the top level. However, top level resources can themselves store child resources.

For example, an account could store both a T1 and a T2 resource at the top level. The top-level T1 is distinct from the child T1 stored in T2.

1 Like

So, if I publish a resource T1 which has a child resource T2 to an account, could I get T2 from the account by borrow_global or move_from?

No. The T2 child can only be accessed via (1) a borrow_global<T1> followed by a borrow of the field of type T2, or (2) a move_from<T1> followed by an unpack to push the contents of T1 (including the field of type T2) onto the stack).

I got it. Thank you very much for your answer!