How could I understand the keyword "acquires"?

Question: How could I understand “acquires” in the code? For example, in the following code, I can’t understand the “acquires” in line 4 and " _ = move(x); " in line 7.

module A {
    resource T1{v: u64}

    public test(addr: address) acquires T1 {
        let x: &mut Self.T1;
        x = borrow_global<T1>(get_txn_sender());
        _ = move(x);
        Self.acquires_t1();

        return;
    }

    acquires_t1() acquires T1 {
        let v: u64;
        T1 { v } = move_from<T1>(get_txn_sender());
        return;
    }
}

How could I understand “acquires” in the code?

This is an annotation that tells the bytecode verifier which types a procedure (or its callees) may borrow or move from global state. These annotations allow the bytecode verifier to ensure that there are no dangling references to values in global state. The docs for the bytecode verifier that uses these annotations might be helpful.

From a programmer perspective, this means that you must add acquires T for any procedure that

  • performs borrow_global<T>
  • performs move_from<T>
  • calls a procedure annotated with acquires T

and " _ = move(x); " in line 7.

This code moves the value stored in x to the stack and then pops the stack. Functionally, it is destroying the global reference to a T1 stored in X to allow a call to acquires_t1() to proceed successfully. If the reference in x still existed at the time acquires_t1() was called, it would cause a dangling reference inside of acquires_t1() (and the bytecode verifier would complain).

1 Like

Thank you very much for your answer. Besides, I have two questions to ask.

  1. Does the builtin create_account create only the LibraAccount? Can I use create_account to create the account resources which is defined by myself?
  2. Does sending a resource to the address which calls the procedure with move_to_sender mean that the resource corresponds to that address in the block chain and can be read or modified later by move_from or borrow_global?
  1. Does the builtin create_account create only the LibraAccount?

Yes, create_account(addr) creates and publishes a LibraAccount.T resource under addr.

Can I use create_account to create the account resources which is defined by myself?

No. Resources defined in custom modules must be created using the Pack bytecode (in IR, the Pack syntax is T { f: 6 } to create a resource named T with an integer field f). Once a resource of type T has been created, it can added to the sender’s address using move_to_sender<T>.

Does sending a resource to the address which calls the procedure with move_to_sender mean that the resource corresponds to that address in the block chain and can be read or modified later by move_from or borrow_global ?

Yes (if I understand correctly). If I run move_to_sender<T> in a transaction sent by address adr, that resource can later be accessed via move_from<T>(addr) and borrow_global<T>(addr) (even if these accesses occur in a transaction not sent by addr).

Thank you very much for your answer, which helps me a lot!