Sui.

Bài viết

Chia sẻ kiến thức của bạn.

article banner.
0xduckmove.
May 30, 2025
Bài Viết

Mã hóa BCS trong Sui Nó là gì và tại sao nó quan trọng

Nếu bạn đang xây dựng trên Sui hoặc mày mò với Move, có lẽ bạn đã nghe đến thuật ngữ BCS trôi nổi xung quanh. Đó là viết tắt của máy định dạng Binary Canonical Serialization ban đầu được tạo ra cho blockchain Diem và hiện là nền tảng của các hệ sinh thái dựa trên Move như Sui, Aptos, Starcoin và 0L.

Vì vậy, vâng, tốt hơn hết bạn nên ấm cúng với nó nếu bạn nghiêm túc với việc xây dựng trong không gian này.

BCS là gì?

Binary Canonical Serialization (BCS) là một định dạng được sử dụng để tuần tự hóa (mã hóa) và giải mã (giải mã) dữ liệu có cấu trúc thành byte.

Bạn sẽ thấy nó được sử dụng khi:

  • Mã hóa giao dịch trước khi ký.
  • Phát ra hoặc phân tích các sự kiện từ blockchain.
  • Tương tác với Move smart contract off-chain thông qua JavaScript.

Nhưng BCS không bao gồm thông tin kiểu trong byte. Điều này có nghĩa là bạn phải biết cấu trúc trước khi giải mã không giống như các định dạng như JSON hoặc Protocol Buffers, vốn tự mô tả nhiều hơn.

Các tính năng chính của BCS

Không có loại siêu dữ liệu

Đầu ra được nối tiếp không chứa gợi ý về loại trường. Bạn phải biết bạn đang đối mặt với những gì khi bạn giải mã.

Sê-ri hóa phụ thuộc vào đơn hàng

Các cấu trúc được mã hóa theo thứ tự chính xác của các trường của chúng. Thay đổi thứ tự và quá trình khử chuỗi của bạn bị ngắt. Đây là lý do tại sao các hàm peel_* trong Move phải khớp với bố cục của struct 1:1.

Loại chung

Trong một cấu trúc như:

struct BCSObject<T> has drop, copy {
    id: ID,
    owner: address,
    meta: Metadata,
    generic: T
}

Bạn chỉ có thể giải mã hóa một cách đáng tin cậy cho đến trường meta. Các loại chung gây rối với phân tích cú pháp BCS, vì vậy hãy luôn đặt chúng cuối cùng nếu bạn muốn dữ liệu của mình được giải mã một cách an toàn.

Sử dụng BCS trong JavaScript

Nhờ thư viện @mysten /bcs, bạn có thể làm việc với BCS trong JS như một chuyên gia.

npm i @mysten/bcs

và ví dụ cơ bản:

import { BCS, getSuiMoveConfig } from "@mysten/bcs";
const bcs = new BCS(getSuiMoveConfig());

const ser = bcs.ser(BCS.U16, 10);
console.log(ser.toBytes()); // [0x0a, 0x00]

const des = bcs.de(BCS.U16, ser.toBytes());
console.log(des); // 10

Bạn cũng có thể tuần tự hóa vectơ và chuỗi:

bcs.ser("vector<u8>", [1, 2, 3, 4]); // 04 01 02 03 04
bcs.ser(BCS.STRING, "test string"); // 0b7465737420737472696e67

Đăng ký các loại tùy chỉnh

Giả sử bạn có cấu trúc Move sau:

struct Metadata has drop, copy {
    name: std::ascii::String
}

struct BCSObject has drop, copy {
    id: ID,
    owner: address,
    meta: Metadata
}


Bạn có thể đăng ký chúng như thế này trong JS:

bcs.registerStructType("Metadata", {
  name: BCS.STRING,
});

bcs.registerStructType("BCSObject", {
  id: BCS.ADDRESS,
  owner: BCS.ADDRESS,
  meta: "Metadata",
});

Ví dụ về sê-ri hóa & giải mã

Trình tự hóa JavaScript:

const bytes = bcs
  .ser("BCSObject", {
    id: "0x0000000000000000000000000000000000000005",
    owner: "0x000000000000000000000000000000000000000a",
    meta: { name: "aaa" }
  })
  .toString("hex");

console.log("Hex:", bytes);

Đầu ra có thể:

0x0000000000000000000000000000000000000005000000000000000000000000000000000000000a03616161

Điều này bây giờ có thể được chuyển vào hợp đồng Move hoặc thậm chí kiểm tra thủ công trong Sui CLI.

BCS có thể trông cấp thấp và nặng byte, nhưng một khi bạn hiểu cách nó mã hóa dữ liệu, bạn sẽ hiểu sâu hơn về cách hợp đồng thông minh Move thực sự hoạt động như thế nào - và cách kết nối các hệ thống ngoài chuỗi trên chuỗi ↔ một cách an toàn.

Và nếu bạn đang gỡ lỗi byte BCS trên Sui Explorer (như bên dưới):

Mã hóa BCS Binary Canonical Serialization, hay BCS, là một định dạng chuỗi hóa được phát triển trong bối cảnh của chuỗi khối Diệm, và hiện được sử dụng rộng rãi trong hầu hết các blockchain dựa trên Move (Sui, Starcoin, Aptos, 0L). BCS không chỉ được sử dụng trong Move VM, mà còn được sử dụng trong mã hóa giao dịch và sự kiện, chẳng hạn như sắp xếp các giao dịch trước khi ký, hoặc phân tích dữ liệu sự kiện.

Biết cách thức hoạt động của BCS là rất quan trọng nếu bạn muốn hiểu cách Move hoạt động ở mức độ sâu hơn và trở thành chuyên gia Move. Hãy đi sâu vào.

Đặc điểm kỹ thuật và tính chất của BCS Có một số thuộc tính cấp cao của mã hóa BCS cần lưu ý khi chúng ta xem qua phần còn lại của bài học:

BCS là một định dạng chuỗi hóa dữ liệu trong đó các byte đầu ra kết quả không chứa bất kỳ thông tin kiểu nào; vì điều này, bên nhận các byte được mã hóa sẽ cần biết cách giải mã hóa dữ liệu

Không có cấu trúc trong BCS (vì không có kiểu); cấu trúc chỉ đơn giản xác định thứ tự mà các trường được nối tiếp

Các loại Wrapper bị bỏ qua, vì vậy OuterType và UnnestedType sẽ có cùng một biểu diễn BCS:

cấu trúc OuterType { chủ sở hữu: InnerType } cấu trúc innerType { địa chỉ: địa chỉ } cấu trúc unnestedType { địa chỉ: địa chỉ } Các loại chứa các trường kiểu chung có thể được phân tích cú pháp cho đến trường kiểu chung đầu tiên. Vì vậy, bạn nên đặt (các) trường kiểu chung cuối cùng nếu đó là kiểu tùy chỉnh sẽ được ser/de'd.

struct BCSObject có drop, copy { ID: ID, chủ sở hữu: địa chỉ, meta: Siêu dữ liệu, chung chung: T } Trong ví dụ này, chúng ta có thể giải mã mọi thứ cho đến trường meta.

Các kiểu nguyên thủy như int không dấu được mã hóa ở định dạng Little Endian

Vector được nối tiếp thành độ dài ULEB128 (với chiều dài tối đa lên đến u32) theo sau là nội dung của vectơ.

Thông số kỹ thuật đầy đủ của BCS có thể được tìm thấy trong kho lưu trữ BCS.

Sử dụng Thư viện JavaScript @mysten /bcs Lắp đặt Thư viện bạn sẽ cần cài đặt cho phần này là thư viện @mysten /bcs. Bạn có thể cài đặt nó bằng cách nhập vào thư mục gốc của dự án nút:

npm ở @mysten /bcs Ví dụ cơ bản Trước tiên, chúng ta hãy sử dụng thư viện JavaScript để tuần tự hóa và khử sê-ri một số kiểu dữ liệu đơn giản:

nhập {BCS, getsuimoveConfig} từ "@mysten /bcs “;

//khởi tạo trình tuần tự với cấu hình Sui Move mặc định const bcs = BCS mới (getSUIMoveConfig ());

//Xác định một số kiểu dữ liệu thử nghiệm const integer = 10; mảng const = [1, 2, 3, 4]; const string = “chuỗi thử nghiệm”

//sử dụng bcs.ser () để nối tiếp dữ liệu const ser_integer = bcs.ser (BCS.U16, số nguyên); const ser_array = bcs.ser (“vector “, mảng); const ser_string = bcs.ser (BCS.STRING, chuỗi);

//sử dụng bcs.de () để giải mã dữ liệu const de_integer = bcs.de (BCS.U16, SER_integer.tobytes ()); const de_array = bcs.de (“vector “, ser_array.tobytes ()); const de_string = bcs.de (BCS.STRING, ser_string.tobytes ()); Chúng ta có thể khởi tạo phiên bản serializer với cài đặt mặc định tích hợp cho Sui Move bằng cách sử dụng cú pháp trên, new BCS (getSUIMoveConfig ()).

Có các ENUM tích hợp sẵn có thể được sử dụng cho các kiểu Sui Move như BCS.U16, BCS.STRING, v.v. Đối với các kiểu chung, nó có thể được định nghĩa bằng cách sử dụng cú pháp tương tự như trong Sui Move, giống như vector trong ví dụ trên.

Chúng ta hãy xem xét kỹ các trường được nối tiếp và giải mã hóa:

int là số thập lục phân little-endian

0a00 10

phần tử đầu tiên của vectơ cho biết tổng chiều dài,

thì nó chỉ là bất kỳ phần tử nào trong vectơ

4001020304 1,2,3,4

string chỉ là vectơ của u8, với phần tử đầu tiên bằng chiều dài của chuỗi

0b7465737420737472696e67 chuỗi kiểm tra Loại đăng ký Chúng tôi có thể đăng ký các loại tùy chỉnh mà chúng tôi sẽ làm việc bằng cú pháp sau:

nhập {BCS, getsuimoveConfig} từ "@mysten /bcs “; const bcs = BCS mới (getSUIMoveConfig ());

//Đăng ký loại siêu dữ liệu bcs.registerStructType (“Siêu dữ liệu”, { Tên: BCS.STRING, });

//Tương tự đối với đối tượng chính mà chúng tôi dự định đọc bcs.registerStructType (“BCSObject”, { //BCS.ADDRESS được sử dụng cho các loại ID cũng như các loại địa chỉ ID: BCS.ADDRESS, chủ sở hữu: BCS.ADDRESS, meta: “Siêu dữ liệu”, }); Sử dụng bcs trong Hợp đồng thông minh Sui Hãy tiếp tục ví dụ của chúng tôi từ phía trên với các cấu trúc.

Định nghĩa cấu trúc Chúng ta bắt đầu với các định nghĩa cấu trúc tương ứng trong hợp đồng Sui Move.

{ //.. struct Siêu dữ liệu có drop, copy { Tên: std: :ascii: :String }

struct BCSObject có drop, copy { ID: ID, chủ sở hữu: địa chỉ, meta: Siêu dữ liệu } //.. } Không phân loại hóa Bây giờ, chúng ta hãy viết hàm để giải mã một đối tượng trong hợp đồng Sui.

công cộng vui nhộn object_from_bytes (bcs_bytes: vector): BCSObject {

//Khởi tạo phiên bản bcs bytes hãy để bcs = bcs: :mới (bcs_bytes);

//Sử dụng các peel_*hàm để bóc các giá trị từ các byte được nối tiếp. //Thứ tự phải giống như chúng tôi đã sử dụng trong quá trình nối tiếp! let (id, chủ sở hữu, meta) = ( bcs: :địa chỉ peel_( & mut bcs), bcs:: địa chỉ peel_( & mut bcs), bcs:: peel_vec_u8 (& mut bcs) ); //Đóng gói cấu trúc BCSObject với kết quả sắp xếp sê-ri BCSObject {id: object: :id_from_address (id), chủ sở hữu, meta: Siêu dữ liệu {tên: std: :ascii: :chuỗi (meta)}}} Các phương thức peel_* khác nhau trong mô-đun Sui Frame bcs được sử dụng để “bóc” từng trường riêng lẻ từ các byte nối tiếp BCS. Lưu ý rằng thứ tự chúng ta bóc các trường phải hoàn toàn giống với thứ tự của các trường trong định nghĩa cấu trúc.

Trắc nghiệm: Tại sao kết quả không giống nhau từ hai cuộc gọi peel_address đầu tiên trên cùng một đối tượng bcs?

Cũng lưu ý cách chúng ta chuyển đổi các kiểu từ địa chỉ sang id và từ vector <8>sang std: :ascii: :string với các hàm trợ giúp.

Trắc nghiệm: Điều gì sẽ xảy ra nếu BSCobject có kiểu UID thay vì loại ID?

Hoàn thành ví dụ Ser/De Tìm mã mẫu JavaScript và Sui Move đầy đủ trong thư mục example_projects.

Đầu tiên, chúng tôi tuần tự hóa một đối tượng thử nghiệm bằng chương trình JavaScript:

//Chúng tôi xây dựng một đối tượng thử nghiệm để nối tiếp, lưu ý rằng chúng tôi có thể chỉ định định dạng của đầu ra thành hex cho _byte = bcs .ser (“bcsObject”, { id: “0x0000000000000000000000000000000000000005", chủ sở hữu: “0x000000000000000000000000000000000000000a”, meta: {name: “aaa"} }) .toString (“hex”); Chúng tôi muốn đầu ra của trình ghi BCS lần này ở định dạng thập lục phân, có thể được chỉ định như ở trên.

Dán kết quả chuỗi hóa hexstring với tiền tố 0x và xuất sang biến môi trường:

xuất object_hexstring=0x00000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000a03616161 Bây giờ chúng ta có thể chạy các bài kiểm tra đơn vị Move liên quan để kiểm tra tính chính xác:

kiểm tra sui move Bạn sẽ thấy điều này trong bảng điều khiển:

XÂY DỰNG bcs_move Chạy thử nghiệm đơn vị Move [PASS] 0x0: :bcs_object: :test_deserialization Kết quả kiểm tra: OK. Tổng số bài kiểm tra: 1; vượt qua: 1; thất bại: 0 Hoặc chúng ta có thể xuất bản mô-đun (và xuất PACKAGE_ID) và gọi phương thức emit_object bằng cách sử dụng chuỗi lục giác nối tiếp BCS ở trên:

gọi máy khách riêng --function emit_object --module bcs_object --package $PACKAGE_ID --args $OBJECT_HEXSTRING Sau đó, chúng tôi có thể kiểm tra tab Sự kiện của giao dịch trên Sui Explorer để xem chúng tôi đã phát ra BCSobject được giải mã chính xác hay không:

  • Sui
  • SDKs and Developer Tools
1
Chia sẻ
Bình luận
.
harry phan.
May 30 2025, 17:12

Little-endian và big-endian là gì?

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

306Bài viết450Câu trả lời
Sui.X.Peera.

Kiếm phần của bạn từ 1000 Sui

Tích lũy điểm danh tiếng và nhận phần thưởng khi giúp cộng đồng Sui phát triển.

Chiến dịch phần thưởngTháng Sáu
Chúng tôi sử dụng cookie để đảm bảo bạn có trải nghiệm tốt nhất trên trang web của chúng tôi.
Thêm thông tin