Object programming
object ownership

Object Ownership

Mỗi object đều có một trường chủ sở hữu(owner field) cho biết object này đang được sở hữu như thế nào. Quyền ownership quy định cách một đối tượng có thể được sử dụng trong các transaction. Có các loại object:

  1. Address-owner
  2. Immutable
  3. Share
  4. Wrapped object - Dynamic fields

Owned by an address

  1. Object thuộc sở hữu của address là object được sở hữu bởi một địa chỉ 32-byte, có thể là địa chỉ account hoặc ID của một object khác.

  2. Chỉ có chủ sở hữu mới có quyền truy cập vào object đó.

  3. Khi một đối tượng Move được tạo ra, nó có thể được chuyển cho một địa chỉ. Sau đó, địa chỉ này sẽ trở thành chủ sở hữu( owner) của object đó. Chỉ có owner mới có thể sử dụng đối tượng của mình trong các transaction.

  4. Khi sử dụng, đối tượng có thể được truyền vào theo 3 cách:

    • read-only reference (&T)
    • mutable reference (&mut T) và
    • by-value (T)

Đây làm một số cách để bạn tạo một address-owned object:

sui::transfer::transfer(obj: T, recipient: address)
sui::transfer::public_transfer(obj: T, recipient: address)

Câu hỏi: Phân biệt giữa transferpublic_transfer

Link docs: https://docs.sui.io/concepts/transfers (opens in a new tab)

Immutable objects

  • Sau khi được tạo ra, trạng thái của các đối tượng này không thể thay đổi.

  • Chúng không thể bị sửa đổi, transfer, hoặc xóa và không có chủ sở hữu( ownership), nghĩa là bất kỳ ai cũng có thể sử dụng object này.

  • Các đối tượng immutable sẽ cung cấp tính bền vững và độ tin cậy, phù hợp với dữ liệu cần duy trì không đổi theo thời gian.

Ví dụ: Metadata của token Coin trên Sui, nơi mà các thông tin như tên, ký hiệu và số thập phân cần được cố định ngay từ khi tạo ra.

Đây là function giúp tạo một object immutable:

public native fun public_freeze_object(obj: T)
 
// ta sẽ dùng 
transfer::freeze_object(obj);

Sau lệnh gọi này, obj sẽ trở thành bất biến( immutable) , nghĩa là bạn không thể sửa đổi hoặc xóa nó. Quá trình này cũng không thể đảo ngược: một khi object đã bị frozen, nó sẽ mãi mãi ở trạng thái đó. Bất kỳ ai cũng có thể sử dụng đối tượng bất biến này như một tham chiếu trong lệnh call Move.

→ Tất cả các packages và modules đã được publish trong Sui đều là immutable objects

Bạn có thể đọc thêm tài liệu về immutable: https://docs.sui.io/concepts/object-ownership/immutable (opens in a new tab)

Shared object

Như vậy immutable object trên ở cũng có thể coi là Shared object. Nhưng sự khác biệt là Shared object có thể được read và mutate (thay đổi được bởi bất kì ai).

Để tạo share object thì ta cần phải gọi:

transfer::share_object(obj);

Khi một object được chia sẻ, nó vẫn có thể thay đổi được và bất kỳ ai cũng có thể truy cập để gửi transaction chỉnh sửa object đó. Share object vẫn sẽ có UID của mình. Ví dụ:

public struct SharedObject has key {
   id: UID,
}

Ta có thể create object:

public fun convert_to_share_object(object: SharedObject) {
 transfer::share_object(object);
}
 
// hoặc là 
 
public fun create_shared_object(ctx: &mut TxContext) {
 let shared_object = SharedObject {
     id: object::new(ctx),
 };
	 convert_to_share_object(shared_object);
}
 

Share_object<T: key>(obj: T): method này biến một object có key thành shared và chỉ có thể được sử dụng trong module nơi object được định nghĩa. Nếu object không được tạo ra trong transaction hiện tại thì thao tác sẽ abort.

public fun share_object<T: key>(obj: T) {
    share_object_impl(obj)
}

Ngoài ra chúng ta còn có public_share_object<T: key + store>(obj: T) một function tương tự với share_object nhưng sẽ có thêm store cho phép object share với các module khác.

⇒ Các bạn sẽ có thắc mắc là sự tương đồng và khác nhau giữa Immutable và share object là gì ?

Trade-Offs giữa Shared và Owned Objects

Owned Objects

Xử lý nhanh hơn vì không cần qua quá trình đồng thuận( consesus).

Tuy nhiên, có hai hạn chế:

  • Chỉ chủ sở hữu mới có thể sử dụng object, nên khó thực hiện các giao dịch cần nhiều người tham gia
  • Khi nhiều người muốn truy cập cùng một object thường xuyên (hot object), việc điều phối phải thực hiện bên ngoài blockchain

Shared objects

  • Việc sử dụng shared object trong các transaction yêu cầu phải đồng thuận(consensus) về cách đọc và write chúng. Điều này có nghĩa là bạn sẽ phải trả nhiều phí gas hơn một chút và đợi lâu hơn một chút để giao dịch hoàn tất.

  • Khi nhiều người cùng cố gắng sử dụng các shared object một lúc, thời gian chờ có thể sẽ còn lâu hơn nữa. Tuy nhiên, lợi ích là shared object mang lại cho bạn nhiều sự linh hoạt hơn trong cách sử dụng.

So sánh giữa OwnedShared Object

Như vậy Điểm tương đồng: Cả hai đều thay đổi trạng thái của object. Cả hai đều có abilities là key và store, được sử dụng cho các thao tác bên trong và bên ngoài module.

Owned ObjectsShared Objects
Tính sở hữuchỉ có owner mới có thể sử dụng objectbất kỳ ai cũng có thể sử dụng object
Tốc độ truy cậpNhanhChậm hơn
Tính linh hoạtKhông linh hoạtLinh hoạt hơn
Tính chia sẻChia sẻ khi sử dụng freeze object -> immutable sharingChia sẻ cho bất kỳ ai có nhu cậu sử dụng thông qua share_object -> mutable sharing

Ví dụ:

module sui_boootcamp::transfer_example_a {
    public struct Object_share has key, store { id: UID }
}
 
module sui_boootcamp::transfer_example_b {
		// import 
    use sui_boootcamp::transfer_example_a ::{Object_share};
 
    // Fails!  bởi vì Object share ko nằm trong intenrl 
        public fun transfer_ks(ks: Object_share, to: address) {
        transfer::transfer(ks, to);
    }
 
    // Works! Object_share is not internal but the function is public
    public fun public_transfer_ks(y: Object_share, to: address) {
        transfer::public_transfer(y, to);
    }

Wrapped Objects ( hay Owned by another object)

Wrapped Objects: Các object trong Sui không tồn tại độc lập; chúng có thể được nhóm lại với nhau để đáp ứng các trường hợp sử dụng phức tạp.

Wrapped objects là ví dụ về điều này, khi được chứa bởi một object khác. Sui cũng hỗ trợ Dynamic Object Fields, cho phép các object nhúng các object khác vào trong nó, từ đó cho phép xây dựng các logic và cấu trúc dữ liệu phức tạp hơn.

Quyền sở hữu của wrapped objects được xác định bởi object đang chứa chúng, tạo ra một cách tiếp cận linh hoạt trong việc quản lý object.

struct Foo has key {
    id: UID,
    bar: Bar,
}
 
struct Bar has store {
    value: u64,
}
 

Đối tượng Sui Foo với khả năng key có một instance bar với kiểu dữ liệu Bar, là một struct. Ở đây, Bar không phải là một đối tượng Sui vì nó không có key abilities . Bạn có thể biến nó thành một đối tượng Sui và sử dụng nó trong Foo.

Trong bài học sắp tới bạn sẽ học về dynamic object field. Đơn giản là chúng ta gọi object được sỡ hữu bởi object khác thì là object con( child).