diff --git a/pages/assets/Objects/coin_example.png b/pages/assets/Objects/coin_example.png new file mode 100644 index 0000000..fc9a5bc Binary files /dev/null and b/pages/assets/Objects/coin_example.png differ diff --git a/pages/assets/Objects/move_evolution.png b/pages/assets/Objects/move_evolution.png new file mode 100644 index 0000000..7f33243 Binary files /dev/null and b/pages/assets/Objects/move_evolution.png differ diff --git a/pages/object_programming/Intro_object_centric_design.mdx b/pages/object_programming/Intro_object_centric_design.mdx new file mode 100644 index 0000000..35e90f8 --- /dev/null +++ b/pages/object_programming/Intro_object_centric_design.mdx @@ -0,0 +1,41 @@ +> Trong computing, tất cả mọi thứ chỉ là bits và bytes đều có thể dễ dàng copied. Nhưng chúng ta cần **một ngôn ngữ lập trình có tính quyền sở hữu( ownership) **, tương tự như cách hoạt động của các objects trong thế giới thực. Điều này rất quan trọng vì lý do bảo mật. Đó là lý do tại sao chúng tôi đã tạo ra Move - một ngôn ngữ lập trình mới giải quyết vấn đề này. Các ngôn ngữ lập trình khác, n**gay cả những ngôn ngữ được sử dụng cho các ứng dụng blockchain,** không xử lý vấn đề này. Sui xây dựng Move đặc biệt để giúp các lập trình viên viết code bảo mật hơn, dễ dàng hơn, mà không cần phải tạo ra các giải pháp phức tạp từ đầu **—** +> +**Lời văn từ Sam Blackshear -** Creator of the Move programming language, Co-founder of Mysten Labs, Initial Contributor to Sui ( https://blog.sui.io/power-of-sui-move/ ) + + +
+ +Như giới thiệu từ section 1, Move, ban đầu được phát triển bởi Meta, là một ngôn ngữ lập trình được thiết kế cho **blockchain** và **smart contracts**, khởi đầu để **hỗ trợ dự án Libra** (sau đổi tên thành Diem). Thiết kế và triển khai của Move chịu ảnh hưởng từ ngôn ngữ Rust và có các kiểu dữ liệu nguyên thủy (primitive types) và mảng (arrays). Theo **Sam Blackshea**r - creator của Move lang, ngôn ngữ Move giải quyết các vấn đề sau: + +- **Tính sở hữu và khan hiếm(Ownership và Scarcity)**: Move cung cấp các trừu tượng (abstractions) cần thiết để biểu diễn bits và bytes trong máy tính, giúp chúng có tính chất sở hữu và khan hiếm như các vật thể trong thế giới thực. +- **Đảm bảo Bảo mật**: Move được thiết kế với các đảm bảo bảo mật cơ bản, cho phép dev viết code an toàn và hiệu quả mà không cần phải "phát minh lại bánh xe". +- **Hệ thống Kiểu Resource**: Hệ thống kiểu resource đảm bảo các tài nguyên không thể bị sao chép hoặc xóa bỏ và chỉ có thể được quản lý thông qua các transfer được phép. + +Move trên Sui là ngôn ngữ lập trình smart contract được phát triển bởi Mysten Labs cho blockchain Sui. Đây là phiên bản cải tiến của Move, được thiết kế để tích hợp với mô hình dữ liệu hướng đối tượng của Sui. + +Sơ đồ dưới đây sẽ thể hiện sự tiến hoá của ngôn ngữ Move: + + +![](../assets/Objects/move_evolution.png) + +## Các thành phần của một object trong object-centric data model? + +**Resource-Oriented Design Concept:** Sự độc đáo của Sui nằm ở thiết kế hướng tài nguyên (resource-oriented). Thiết kế này xem các tài nguyên **on-chain** như những objects có thể quản lý độc lập, cho phép sử dụng hiệu quả và quản lý chính xác các tài nguyên. + +- **Objects**: Trong Sui, mỗi tài nguyên on-chain được xem như một object. Các objects này có thể là **tokens**, **smart contracts**, **NFTs**, hoặc các loại tài sản khác. +- **State và lifecycle của Objects**: Mỗi object có state và lifecycle riêng. Trạng thái của object có thể được thay đổi bởi các transactions hoặc smart contracts, trong khi vòng đời của nó định nghĩa quá trình tạo, sử dụng và hủy object đó. + +
+ +Trong Sui, tất cả các transactions đều yêu cầu objects làm input và tạo ra các objects mới hoặc đã được chỉnh sửa làm output. Mỗi object lưu trữ hash của transaction cuối cùng đã tạo ra nó. Những objects có thể được sử dụng làm input được gọi là "active" objects. Bằng cách quan sát các active objects này, chúng ta có thể hiểu được trạng thái hiện tại của toàn bộ blockchain: + +- **Unique Identifier (objectId):** Mỗi object có một định danh duy nhất để phân biệt với các objects khác. ID này được tạo ra khi object được khởi tạo và không thể thay đổi (immutable) +- **Object Type (objType)**: Mỗi object có một kiểu xác định cấu trúc và hành vi của nó. +- **Owner (owner)**: Mỗi object gắn với một chủ sở hữu có quyền kiểm soát object đó. Trên Sui, objects có thể được sở hữu bởi một tài khoản, được chia sẻ giữa tất cả tài khoản, hoặc bị đóng băng - chỉ cho phép truy cập đọc mà không được sửa đổi hay transfer. +- **Version**: Mỗi khi object thay đổi trong Sui, một số phiên bản mới được tạo ra, đóng vai trò như một số ngẫu nhiên để ngăn chặn các tấn công replay. +- **Digest**: Mỗi object có một digest - một hash của dữ liệu object. Digest được dùng để xác minh tính toàn vẹn của dữ liệu object và đảm bảo nó không bị can thiệp. Digest được tính khi object được tạo và được cập nhật khi dữ liệu object thay đổi. +- **Content Fields**: Đây là vùng có kích thước thay đổi theo danh mục, chứa dữ liệu được mã hóa bằng Binary Canonical Serialization (BCS), ghi lại dữ liệu cụ thể của object. + + +![](../assets/Objects/coin_example.png) + diff --git a/pages/object_programming/_meta.json b/pages/object_programming/_meta.json new file mode 100644 index 0000000..ea9e8ac --- /dev/null +++ b/pages/object_programming/_meta.json @@ -0,0 +1,6 @@ +{ + "Intro_object_centric_design": "Object centric Model", + "what_is_object": "Object là gì", + "object_ownership": "object ownership" +} + diff --git a/pages/object_programming/object_ownership.mdx b/pages/object_programming/object_ownership.mdx new file mode 100644 index 0000000..668f9b1 --- /dev/null +++ b/pages/object_programming/object_ownership.mdx @@ -0,0 +1,148 @@ +# 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 ownershiop 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 +3. Immutable +3. Share +4. Wrapped object - Dynamic fields + +## Owned by an address + +**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. Chỉ có chủ sở hữu mới có quyền truy cập vào object đó. Có hai cách để tạo ra một object thuộc sở hữu của địa chỉ. 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 sigend. 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: +```rust +sui::transfer::transfer(obj: T, recipient: address) +sui::transfer::public_transfer(obj: T, recipient: address) +``` + +## 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ụ như 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: + +```rust +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 + +## 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à mutabed ( thay đổi) được bởi bất kì ai). + +Để tạo share object thì ta cần phải gọi: + +```rust +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ụ: +```rust +public struct SharedObject has key { + id: UID, +} +``` + + +Ta có thể create object: +```rust +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(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. + + +```rust +public fun share_object(obj: T) { + share_object_impl(obj) +} +``` + +Ngoài ra chúng ta còn có `public_share_object(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ì ? Giữa Freeze và Share khác nhau chỗ nào? + +## Trade-Offs giữa Shared và Owned Objects + +- Đối với **owned object**: 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 i 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. + +Như vậy **Điểm tương đồng**: Cả hai đều thay đổi trạng thái của object, làm cho nó immutable ở một mức độ nào đó. 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. + +**Điểm khác biệt**: freeze làm cho object hoàn toàn bất biến( immutable), không cho phép bất kỳ hình thức transfer hay modify nào. Có thể hiểu đây là **chia sẻ bất biến( immutable sharing)**. Ngược lại, share object làm cho object được chia sẻ, cho phép tất cả người dùng truy cập và sửa đổi. Có thể hiểu đây là **mutable sharing** . + +Ví dụ: + +```rust +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. + +```rust +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). \ No newline at end of file diff --git a/pages/object_programming/what_is_object.mdx b/pages/object_programming/what_is_object.mdx new file mode 100644 index 0000000..6fa48a2 --- /dev/null +++ b/pages/object_programming/what_is_object.mdx @@ -0,0 +1,297 @@ +# Object là gì ? + +Đơn vị lưu trữ cơ bản trên Sui là object (đối tượng). Khác với nhiều blockchain tập trung vào account chứa key-value store, storage model của Sui xoay quanh các objects, mỗi object có một ID duy nhất để định danh trên chain. Một smart contract là một object mà mọi người biết đó là package. Những smart contract giúp tương tác với các objects: + +* Sui Move Package: Một package là tập hợp các đoạn mã (code) có liên quan với nhau. Mỗi code trong package được gọi là module và có tên riêng. Để tìm một module cụ thể, bạn chỉ cần biết ID của package và tên module đó. Khi dev muốn publish smart contract lên Sui, nó tạo thành một package. Sau khi đưa lên, chỉ người có quyền( permissions) mới có thể upgrade package. Các package có thể kết nối và sử dụng lẫn nhau. + +* Sui Move Object: Là container dữ liệu được kiểm soát bởi module Move của Sui. Có thể hình dung nó như một Form với nhiều trường khác nhau - aka struct. Các trường này có thể lưu trữ dữ liệu đơn giản (như integer và address), các object khác… + +## Object metadata +Objects trong Sui có những đặc điểm cơ bản sau: +- Type: Mỗi object có một kiểu dữ liệu cụ thể định nghĩa object đó là gì và có thể làm gì. Giống như việc bạn không thể dùng chìa khóa ô tô để mở cửa nhà, các object khác type không thể thay thế cho nhau. +- Unique ID: Mỗi object có một ID riêng biệt, như dấu vân tay vậy. ID này được cấp khi object được tạo ra và không thể thay đổi. Nó giúp theo dõi từng object trong system. +- Owner: **Mỗi object đều thuộc về một người hoặc object khác đó**. Owner có thể là: + - Một tài khoản duy nhất (ví dụ: ví của bạn 0x….) + - Được chia sẻ với mọi người trên network ( shared object) + - Bị khóa để mọi người chỉ có thể xem nhưng không thể thay đổi (frozen object) +- Data: Objects chứa thông tin, như một container. Loại thông tin nào có thể chứa và có thể làm gì với nó phụ thuộc vào type của object. +- Version: Mỗi object theo dõi số lần nó bị thay đổi thông qua version number. Điều này giúp ngăn chặn việc sử dụng cùng một transaction nhiều lần. +- Digest: Mỗi object có một digets của data. digest này sẽ thay đổi nếu ai đó cố gắng sửa đổi data, giúp bảo mật object và chứng minh data không bị can thiệp. + +⇒ Dùng từ đơn giản, một object trong Sui sẽ là container lưu trữ data. Để tạo một object trong Sui move, bạn sẽ cần tạo `struct`, struct như một form đơn giản liệt kê những thông tin mà object sẽ lưu trữ. Ví dụ, nếu chúng ta có một struct Sum, nó đơn giản chỉ lưu trữ hai số: number_1 và number_2. + +```rust +struct Sum { + number_1: u8, + number_2: u8, +} +``` + +Như cái này vẫn chưa gọi là object. Để biến nó thành một object ở Sui, chúng ta cần thêm ability key và ID bằng cách sử dụng sui::object::UID để cung cấp một ID duy nhất cho mỗi đối tượng, giúp định danh đối tượng đó trên mạng Sui. + +```rust +use sui::object::UID; + +public struct SumObject has key { + id: UID, + number_1: u8, + number_2: u8, +} +``` + +Lưu ý: Tất cả code cần được viết bên trong module khi lập trình Move trên Sui. + +## **Create objects** + +Bạn đã học cách định nghĩa object trong Move trên Sui. Bây giờ chúng ta sẽ tìm hiểu cách tạo ra object đó. Mặc dù đã học qua rồi, nhưng hãy cùng nhau review phần này vì nó quan trọng. + +Để tạo một object, chúng ta cần fill vào tất cả các fields bắt buộc của nó. Mà ở đây field quan trọng đầu tiên là id. Vì điều ta cần cần phải là một mã định danh duy nhất (gọi là UID), chúng ta sử dụng hai module +1. Module `sui::object` +2. Module `sui::tx_context` + +Hai module này hoạt động cùng nhau để tạo ra một ID mới và duy nhất cho đối tượng. Module sui::object có một hàm new() tạo ra ID bằng cách sử dụng thông tin từ sui::tx_context. Ví dụ: + +```rust +module sum::sum { + use sui::object; + use sui::tx_context::TxContext; + + // Defining the SumObject + public struct SumObject has key { + id: UID, + number_1: u8, + number_2: u8, + } + // Constructor function used to iniatlize the SumObject + public fun new(num_1: u8, num_2: u8, ctx: &mut TxContext) { + SumObject { + id: object::new(ctx), + number_1: num_1, + number_2: num_2, + } + } +} +``` + +## Transaction context + +Bạn có thể thắc mắc về tham số `&TxContext` đóng vai trò gì trong ví dụ này đúng không ? Ví dụ minh hoạ là giống bạn cần bột để làm bánh thì bạn cần TxContext mới tạo được objects trong Sui. Không có nó sẽ không được !!! + +**Transaction Context** trong blockchain giống như **một sổ ghi chép thông tin** cho mỗi giao dịch. Để dễ hiểu, nó như một **phiếu ghi thông tin khi bạn gửi tiền ở ngân hàng** - trên đó ghi rõ ai gửi tiền (address của sender), mã số giao dịch( digest) , và thời gian gửi( timestamp). Các thông tin này giúp hệ thống theo dõi và xử lý giao dịch một cách chính xác và an toàn. + +TxContext là một phần quan trọng trong Sui - Trong module của tx_context sẽ có `TxContext` nắm giữ các thông tin quan trong khi run transaction. Khi so sánh với các blockchain khác, TxContext của Sui có nhiều tính năng hữu ích hơn. Ngoài việc lưu thông tin cơ bản của giao dịch, nó còn có thể làm những việc đặc biệt như tạo mã ID cho mỗi object. Cấu trúc của TxContext: + +```rust +/// sui-framework/sources/tx_context.move +public struct TxContext has drop { + sender: address, // The address of the current transaction sender + tx_hash: vector, // The hash of the current transaction + epoch: u64, // The current epoch number + epoch_timestamp_ms: u64, // The timestamp when the epoch started (in milliseconds) + ids_created: u64 // The number of new IDs created in the current transaction +} +``` + +Lưu ý⚠ TxContext là một phần đặc biệt mà bạn không thể tự tạo ra. Nó được hệ thống Sui (MoveVM) tự động tạo và gửi vào transaction dưới dạng &mut TxContext. Khi một TxContext được tạo ra, các thông tin bên trong nó như: + +- Địa chỉ người gửi +- Mã giao dịch +- Và các thông tin khácsẽ không thể thay đổi trong suốt quá trình thực hiện giao dịch. Điều này giúp đảm bảo giao dịch của bạn luôn an toàn và đáng tin cậy.. + + +### Các core function trong transaction context + + +```rust +// Get the sender's address +public fun sender(self: &TxContext): address { + self.sender +} + +// Return the current transaction hash (i.e., transaction digest) +public fun digest(self: &TxContext): &vector { + &self.tx_hash +} + +// Return the current epoch number +public fun epoch(self: &TxContext): u64 { + self.epoch +} + +public fun epoch_timestamp_ms(self: &TxContext): u64 { + self.epoch_timestamp_ms +} + +``` + +Nếu bạn thắc mắc đoạn code về generate Unique address ở Object thì đó là `fresh_object_address` trong tx_context module: + +```rust +public fun fresh_object_address(ctx: &mut TxContext): address { + let ids_created = ctx.ids_created; + let id = derive_id(*&ctx.tx_hash, ids_created); + ctx.ids_created = ids_created + 1; + id +} +``` + +Nếu bạn muốn dùng các field tương tự như `ids_created` trong đoạn code của bạn thì ở các section sau mình sẽ viết về `bcs`((Binary Canonical Serialization)) module. Ví dụ: + +```rust +let ctx_bytes = bcs::to_bytes(ctx); +let bcs_obj = &mut bcs::new(ctx_bytes); + +let signer_obj : address = bcs::peel_address(bcs_obj); +let tx_hash : vector = bcs::peel_vec_u8(bcs_obj); +let epoch : u64 = bcs::peel_u64(bcs_obj); +let ids_created : u64 = bcs::peel_u64(bcs_obj); + +``` + + +> Đây là challenge nhỏ dành cho bạn. Hãy viết một package `animal`, có object `AnimeObject` với các thuộc tính `name`, `no_of_legs`, và `favorite_food`. Tạo một hàm init và sau đó chuyển quyền sở hữu(ownership sẽ được nói ở bài học tiếp theo) của đối tượng `AnimeObject` cho địa chỉ là `sender`. + +hint: +```rust +sui move new animal + +--- +public struct AnimeObject { + //define ở đây nhé +} + +``` + +Trong Sui move, bạn chỉ có thể gọi đến object mà bạn sở hữu. Để sử dụng các objects, có hai cách khác nhau để truyền objects dưới dạng tham số: bằng tham chiếu và bằng giá trị: +1. `&T`: Chỉ đọc được reference +2. `&mut T`: Mutable reference + + +Đối với read-only reference, Tham chiếu chỉ đọc chỉ cho phép bạn đọc dữ liệu của object mà thôi. Nó không cho phép bạn thay đổi hay cập nhật dữ liệu của object đó. + +```rust +module sui_bootcamp::sum { + use sui::object; + use sui::tx_context::TxContext; + + + struct SumObject has key { + id: UID, + number_1: u8, + number_2: u8, + } + + // Constructor function used to initialize the SumObject + fun new(num_1: u8, num_2: u8, ctx: &mut TxContext): SumObject { + SumObject { + id: object::new(ctx), + number_1: num_1, + number_2: num_2, + } + } + + // uses the values data of obj to create a new object + public entry fun make_copy(obj: &SumObject, ctx: &mut TxContext) { + let sum_obj = new(obj.num_1, obj.num_2, ctx); + transfer::transfer(sum_obj, tx_context::sender(ctx)) + } +} +``` + + +Vậy, tham chiếu có thể thay đổi (mutable reference) là ngược lại với tham chiếu chỉ đọc. Mutable reference cho phép bạn chỉnh sửa dữ liệu trong object và thay đổi giá trị của các trường trong object đó. + +```rust +// copy_into function uses the properties data of obj_1 (non-mutable) +public entry fun copy_into(obj_1: &SumObject, obj_2: &mut SumObject, ctx: &mut TxContext) { + obj_2.num_1 = obj_1.num_1; + obj_2.num_2 = obj_1.num_2; + transfer::transfer(obj_2, tx_context::sender(ctx)) +} +``` + +Trong ví dụ này, chúng ta có hai đối tượng: + +- `obj_1` chỉ có thể đọc (không thể thay đổi) +- `obj_2` có thể thay đổi được +1. Lấy giá trị từ `obj_1` và gán cho `obj_2` +2. Chuyển quyền sở hữu của `obj_2` cho người gửi giao dịch bằng module `transfer` + +Lưu ý: Để thực hiện được giao dịch này, người gửi phải sở hữu cả hai đối tượng `obj_1` và `obj_2`. Hàm này được đánh dấu là "entry" để có thể gọi trực tiếp trong giao dịch. + + +Cách khác là truyền trực tiếp giá trị của object vào hàm entry. Khi làm như vậy, object sẽ không nằm trong global storage của Sui: +``` +public entry fun update_num_1(num_1: u8, object: SumObject): SumObject { + let obj = object; + obj.number_1 = num_1; + obj + } +``` + + +Trong đoạn code này, chúng ta truyền `object` bằng giá trị trực tiếp. Quá trình này gồm 3 bước: + +1. Tạo một object mới tên `obj` +2. Cập nhật giá trị `number_1` của object đó +3. Trả về object đã được cập nhật + +Tuy nhiên, cách này có một vấn đề: Khi truyền object bằng giá trị, hệ thống sẽ tạo một bản sao mới của object trong bộ nhớ. Bản sao này sẽ tồn tại cho đến khi chúng ta tự xóa nó đi. Mà bạn đã học ở bài học về abilities thì UID strct không thẻ có `drop` ability được. Vây có thể làm gì nếu muốn giải phóng bộ nhớ? Để xử lý các objects được truyền bằng giá trị, chúng ta có hai cách: +* Delete the object +* Transfer the object + +### Đối với delete object + +Để xóa một object, chúng ta không thể xóa nó trực tiếp mà phải tách rời (phân rã) nó thành các phần nhỏ hơn. Quá trình này gọi là "unpacking". Cụ thể, bạn cần: + +1. Tách các thành phần của object ra +2. Lưu chúng vào các biến riêng biệt +3. Sau đó gán giá trị rỗng cho các biến này + +Ví dụ : + +```rust +// unpack object +let SumObject { id, number_1: _, number_2: _ } = object; + + +--- + +// Defining the SumObject +struct SumObject has key { + id: UID, + number_1: u8, + number_2: u8, +} + +// delete object và dùng object::delete để bỏ id đó đi +public entry fun delete(object: SumObject) { + let ColorObject { id, red: _, green: _, blue: _ } = object; +object::delete(id); +} + +``` + +Để xóa một object, chúng ta thực hiện hai bước chính: + +1. Đầu tiên, chúng ta tách các giá trị `number_1` và `number_2` ra khỏi object bằng ký hiệu `_`. Ký hiệu này cho phép bỏ qua các giá trị này. +2. Sau đó, vì không thể xóa trực tiếp trường `id`, chúng ta dùng hàm `object::delete` để xóa `UID` và giải phóng bộ nhớ. + + +Lưu ý📔: Chúng ta không xóa các objects được truyền bằng tham chiếu (reference) - chỉ xóa những objects được truyền bằng giá trị (value). Lý do là: + +1. Objects được truyền bằng tham chiếu được lưu trong bộ nhớ toàn cục (global storage). Nếu xóa chúng, chúng ta sẽ mất vĩnh viễn dữ liệu thực tế, điều này không phải là điều chúng ta muốn. +2. Objects được truyền bằng giá trị thì khác - chúng chỉ là bản copy của object gốc. Khi đã sử dụng xong các bản sao này, việc dọn dẹp chúng là cần thiết để giải phóng không gian bộ nhớ. + + +### **Transfer the object** + +Một cách khác để xử lý object là chuyển quyền sở hữu của nó cho một chủ sở hữu khác. Để làm điều này, chúng ta cần định nghĩa hàm `transfer`. + +```rust +public entry fun transfer(object: SumObject, recipient: address) { + transfer::transfer(object, recipient) +} + +``` +