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

[MoveosStd] Refactor Object & ObjectRef, unify Object APIs and support Object public transfer #1001

Closed
Tracked by #1000 ...
jolestar opened this issue Oct 19, 2023 · 4 comments · Fixed by #1074
Closed
Tracked by #1000 ...
Labels
area::move-language Move language relative issue, verifier,prover,VM area:stdlib Move stdlib or framework issues skill::move Need the Move language skill to complete the issue status::design The issue need to do more detail design
Milestone

Comments

@jolestar
Copy link
Contributor

jolestar commented Oct 19, 2023

Motivation

Currently, Object & ObjectRef provides APIs that make developers to get confused when using them.

For example:

  1. when to use ObjectID and when to use ObjectRef.
  2. Should a module provide Object, or ObjectRef, or T-related operation API to the outside caller?
  3. What permissions does the owner of an Object have? If all current Object-related APIs are protected by private_generics, and the owner can't transfer the Object directly, what does the owner stand for? Is it possible to provide an API similar to Sui's public_transfer? [Object] Proposal for an Owner method to directly operate on Objects #80 [Move Object] Public Object transfer, borrow, borrow_mut #989
  4. How to express an Object owned by code?

This refactoring tries to solve the above problems.

Solution

We define two kinds of Object owner:

  1. CodeOwner: 0x0.
  2. UserOwner: represented by the user's address.

When an Object is created, it is the CodeOwner by default until it is explicitly transferred to a user.

When an Object is created, an ObjectRef is created at the same time, which cannot be copy, and cannot be drop. There are two cases when an ObjectRef is dropped:

  1. The object is converted to a UserOwner.
  2. The object is deleted.

That is, if any Object is referenced by an ObjectRef, it belongs to the code that references it (usually another struct). Otherwise, it must belong to some user.

The User Owner's Object can be passed as an argument to the entry function, &ObjectRef<T>, &mut ObjectRef<T>. That is, the ObjectRef of the UserOwner Object is actually referenced externally.

Example Code

module moveos_std::context{
  
  public fun new_object<T: key>(ctx: &mut Context, t: T): ObjectRef<T>;
  // We can not construct an `ObjectRef` and return `&ObjectRef` in Move
  //public fun borrow_user_owner_object(ctx, signer, object_id): &ObjectRef<T>;
  public fun remove_object<T: key>(ctx: &mut Context, object_ref: ObjectRef<T>): T;
}

We can remove all ObjectID functions from Context, such as: borrow_object(ObjectID), and borrow_object_mut(ObjectID). We do not provide function for handle Object via ObjectID.

module moveos_std::ObjectRef{
  
  #[private_generic(T)]
  public fun to_user_owner<T: key>(self: ObjectRef<T>, owner: address);
  
  #[private_generic(T)]
  public fun to_code_owner<T: key>(self: &mut ObjectRef<T>): ObjectRef<T>;

  #[private_generic(T)]
  public fun transfer_extend<T: key>(self: &mut ObjectRef<T>, to: address);
  
  #[private_generic(T)]
  public fun borrow_extend<T: key>(self: &ObjectRef<T>) : &T;
  
  #[private_generic(T)]
  public fun borrow_mut_extend<T: key>(self: &ObjectRef<T>) : &T;

  public fun transfer<T: key + store>(self: &mut ObjectRef<T>, to: address);
  public fun borrow<T: key + store>(self: &ObjectRef<T>) : &T;
  public fun borrow_mut<T: key + store>(self: &mut ObjectRef<T>) : &mut T;
}

If the T of Object has key + store, the Object is public. Otherwise, it is private.

The public Object can be directly handled with transfer, borrow, borrow_mut functions.
The private Object needs the T module to extend the transfer_extend,borrow_extend, borrow_mut_extend functions.

module rooch_framework:transfer{
   
   entry fun transfer_object<T: key+store>(object_ref: &mut ObjectRef<T>, to: address){
      object_ref::transfer(object_ref, to);
   }
   entry fun remove_object<T: key+store>(ctx: &mut Context, object_ref: &mut ObjectRef<T>){
      let object_ref = object_ref::to_code_owner(object_ref);
      context::remove_object(ctx, object_ref);
   }
}

When the ObjectRef<T> is an entry function argument, it needs to satisfy the following requirements:

  1. The Object must be a UserOwner object.
  2. The owner of the Object must be the same as the Transaction sender.

Relative issues

@jolestar jolestar added status::design The issue need to do more detail design skill::move Need the Move language skill to complete the issue labels Oct 19, 2023
@jolestar jolestar added this to the Rooch v0.3 milestone Oct 19, 2023
@jolestar jolestar added this to Rooch Oct 19, 2023
@jolestar jolestar mentioned this issue Oct 19, 2023
12 tasks
@jolestar jolestar changed the title [MoveosStd] Object as entry function argument and support public transfer [MoveosStd] Refactor Object & ObjectRef, unify Object APIs and support Object public transfer Oct 22, 2023
@jolestar
Copy link
Contributor Author

Write a draft solution: @WGB5445 @pause125 @baichuan3 @stevenlaw123

@jolestar jolestar added area::move-language Move language relative issue, verifier,prover,VM area:stdlib Move stdlib or framework issues labels Oct 23, 2023
@jolestar
Copy link
Contributor Author

jolestar commented Oct 23, 2023

  1. ObjectRef or ObjectHandle? Or rename ObjectRef to Object
  2. The owner of the UserOwner Object can be a resource account?

@jolestar
Copy link
Contributor Author

Naming solution

  1. Keep of Object&ObjectRef
  2. Rename ObjectRef to ObjectHandle, because there is usually only one Handle, while there is usually more than one Ref.
  3. Rename Object to ObjectCore or ObjectInfo, and ObjectRef to Object, because after refactoring Object's external API is ObjectRef, and developers won't be able to manipulate Object directly. Challenge: if we name it this way, Object in Rust code will also need to be named ObjectInfo, which is a big change.

@jolestar
Copy link
Contributor Author

Solution in #1026

  1. Anyone can obtain &ObjectRef<T> by ObjectID, and then get &T. This can be achieved through the entry function arguments or context::borrow_object(ctx, ObjectID).
  2. Only the owner can obtain &mut ObjectRef<T> by ObjectID, and then get &mut T. This can be achieved through the entry function arguments or context::borrow_mut_object(ctx,signer,ObjectID).
  3. If T has both key and store ability, anyone can transfer ownership by object_ref::transfer(&mut Object<T>, address).
  4. The module where T is defined can use context::borrow_mut_object_extend to obtain any &mut ObjectRef<T>, and can transfer ownership by using object_ref::transfer_extend(&mut Object<T>, address).
  5. Only the module where T is defined can call the object_ref::remove(ObjectRef<T>) method to remove the Object.
  6. The object_ref::to_permanent method is provided to drop ObjectRef<T>, but once ObjectRef<T> is dropped, the Object cannot be removed from object storage.
  7. Provide to_shared, to_frozen function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area::move-language Move language relative issue, verifier,prover,VM area:stdlib Move stdlib or framework issues skill::move Need the Move language skill to complete the issue status::design The issue need to do more detail design
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

1 participant