Sui.

Допис

Діліться своїми знаннями.

article banner.
0xduckmove.
May 30, 2025
Стаття

Кодування BCS в Sui Що це таке і чому це важливо

Якщо ви будуєте на Sui або возите з Move, ви, напевно, чули термін BCS, що плаває навколо. Це скорочення від машини форматування Binary Canonical Serialization, спочатку створеної для блокчейну Diem, а тепер є наріжним каменем екосистем на основі MOVE, таких як Sui, Aptos, Starcoin та 0L.

Тож так, вам краще затишно з ним, якщо ви серйозно ставитеся до будівництва в цьому просторі.

Що таке BCS?

Бінарна канонічна серіалізація (BCS) - це формат, який використовується для серіалізації (кодування) та десеріалізації (декодування) структурованих даних у байти.

Ви побачите, що він використовується, коли:

  • Кодування транзакцій перед підписанням.
  • Випромінювання або аналіз подій з блокчейну.
  • Взаємодія з Move смарт-контрактами поза ланцюжком за допомогою JavaScript.

Але BCS не включає інформацію про тип у байтах. Це означає, що ви повинні знати структуру заздалегідь під час декодування на відміну від форматів, таких як JSON або буфери протоколів, які більше самоописуються.

Ключові особливості BCS

Немає метаданих типу

Серіалізований вихід не містить підказок щодо типів полів. Ви повинні знати, з чим маєте справу, коли декодуєте.

Серіалізація, що залежить від замовлення

Структури кодуються в точному порядку їх полів. Змініть порядок, і ваша десеріалізація переривається. Ось чому функції peel_* у Move повинні відповідати макету структури 1:1.

Загальний тип

У структурі типу:

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

Ви можете надійно десеріалізувати лише до мета-поля. Загальні типи псуються з обробкою BCS, тому завжди ставте їх останніми, якщо ви хочете, щоб ваші дані були безпечно розшифровані.

Використання BCS в JavaScript

Завдяки бібліотеці @mysten /bcs ви можете працювати з BCS в JS як професіонал.

npm i @mysten/bcs

і основний приклад:

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

Ви також можете серіалізувати вектори та рядки:

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

Реєстрація користувальницьких типів

Припустимо, у вас є такі структури переміщення:

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

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


Ви можете зареєструвати їх так в JS:

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

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

Приклад серіалізації та десеріалізації

Серіалізація JavaScript:

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

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

Вихід може бути:

0x0000000000000000000000000000000000000005000000000000000000000000000000000000000a03616161

Тепер це можна передати в контракт Move або навіть перевірити вручну в Sui CLI.

BCS може виглядати низькорівневим і важким на байт, але як тільки ви зрозумієте, як він кодує дані, ви відкриєте глибше розуміння того, як насправді діють смарт-контракти Move — і як безпечно з'єднати позаланцюгові системи on-chain ↔.

І якщо ви налагоджуєте байти BCS на Sui Explorer (як наведений нижче):

Кодування BCS Бінарна канонічна серіалізація, або BCS, - це формат серіалізації, розроблений в контексті блокчейну Diem, і зараз широко використовується в більшості блокчейнів на основі Move (Sui, Starcoin, Aptos, 0L). BCS використовується не тільки в Move VM, але також використовується для кодування транзакцій та подій, наприклад, серіалізація транзакцій перед підписанням або аналіз даних подій.

Знання того, як працює BCS, має вирішальне значення, якщо ви хочете зрозуміти, як Move працює на більш глибокому рівні, і стати експертом Move. Давайте зануримося.

Специфікація та властивості BCS Є деякі властивості кодування BCS високого рівня, про які слід пам'ятати, коли ми проходимо решту уроку:

BCS - це формат серіалізації даних, де отримані вихідні байти не містять жодної інформації про тип; через це сторона, яка отримує закодовані байти, повинна знати, як десеріалізувати дані

У BCS немає структур (оскільки немає типів); структура просто визначає порядок, в якому поля серіалізуються

Типи обгортки ігноруються, тому outerType і UnnestedType матимуть однакове представлення BCS:

структура OuterType { власник: InnerType } структура innerType { адреса: адреса } структура UnstedType { адреса: адреса } Типи, що містять поля загального типу, можна обробляти до першого поля загального типу. Тож корисною практикою є розміщення поля загального типу останніми, якщо це спеціальний тип, який буде сер/де'd.

структура BCSobject має drop, copy { ідентифікатор: Ідентифікатор, власник: адреса, мета: Метадані, загальний: T } У цьому прикладі ми можемо десеріалізувати все аж до мета-поля.

Примітивні типи, такі як непідписані int, кодуються у форматі Little Endian

Вектор серіалізується як довжина ULEB128 (з максимальною довжиною до u32), за якою слідує вміст вектора.

Повну специфікацію BCS можна знайти в сховищі BCS.

Використання бібліотеки JavaScript @mysten /bcs Установка Бібліотека, яку вам потрібно буде встановити для цієї частини, є бібліотека @mysten /bcs. Встановити його можна, ввівши в кореневому каталозі проекту вузла:

npm і @mysten /bcs Основний приклад Давайте спочатку скористаємося бібліотекою JavaScript для серіалізації та десеріалізації деяких простих типів даних:

імпорт {БКС, GETSUIMoveConfig} з "@mysten /bcs «;

//ініціалізуйте серіалізатор за допомогою конфігурацій Sui Move за замовчуванням const bcs = новий БКС (getSUIMoveConfig ());

//Визначте деякі типи тестових даних const ціле число = 10; масив const = [1, 2, 3, 4]; const string = «тестовий рядок»

//використовувати bcs.ser () для серіалізації даних const ser_integer = bcs.ser (BCS.U16, ціле число); const ser_array = bcs.ser («вектор», масив); const ser_string = bcs.ser (BCS.STRING, рядок);

//використовуйте bcs.de () для десеріалізації даних const de_integer = bcs.de (BCS.U16, сер_цілі.тобайт ()); const de_array = bcs.de («вектор», сер_масив.тобайтів ()); const de_string = bcs.de (BCS.STRING, SER_STRING.тобайт ()); Ми можемо ініціалізувати екземпляр серіалізатора за допомогою вбудованого налаштування за замовчуванням для Sui Move, використовуючи наведений вище синтаксис, new BCS (getSUIMoveConfig ()).

Є вбудовані ENUM, які можна використовувати для типів Sui Move, таких як BCS.U16, BCS.STRING тощо. Для загальних типів його можна визначити за допомогою того самого синтаксису, що і в Sui Move, як вектор у наведеному вище прикладі.

Давайте уважно розглянемо серіалізовані та десеріалізовані поля:

int — це маленькі ендіанські шістнадцятимельні числа

0а00 10

перший елемент вектора вказує на загальну довжину,

тоді це просто будь-які елементи у векторі

401020304 1,2,3,4

рядки - це просто вектори u8, при цьому перший елемент дорівнює довжині рядка

0б7465737420737472696е67 тестовий рядок Тип реєстрації Ми можемо зареєструвати власні типи, з якими ми будемо працювати, використовуючи наступний синтаксис:

імпорт {БКС, GETSUIMoveConfig} з "@mysten /bcs «; const bcs = новий БКС (getSUIMoveConfig ());

//Зареєструвати тип метаданих bcs.registerStructType («Метадані», { ім'я: БЦ.СТРИНГ, });

//Те саме для основного об'єкта, який ми маємо намір прочитати BCS.RegisterStructType («BCSobject», { //BCS.ADDRESS використовується для типів ідентифікаторів, а також типів адрес ідентифікатор: BCS.АДРЕСА, власник: БЦ.АДРЕСА, meta: «Метадані», }); Використання bcs у смарт-контрактах Sui Продовжимо наш приклад зверху зі структурами.

Визначення структури Почнемо з відповідних визначень структури в контракті Sui Move.

{ //.. Struct Метадані мають drop, copy { ім'я: std: :ascii: :Рядок }

структура BCSobject має drop, copy { ідентифікатор: Ідентифікатор, власник: адреса, meta: Метадані } //.. } Десеріалізація Тепер давайте напишемо функцію для десеріалізації об'єкта в контракті Sui.

загальнодоступний цікавий об'єкт_з_байтів (bcs_байтів: вектор): BCSObject {

//Ініціалізує екземпляр байтів bcs нехай bcs = bcs: :новий (bcs_байт);

//Використовуйте peel_*функції для видалення значень із серіалізованих байтів. //Порядок повинен бути таким же, як ми використовували в серіалізації! let (ідентифікатор, власник, мета) = ( bcs:: адреса_вилучення (& мут bcs), bcs:: адреса_відклеювання (& мут bcs), bcs:: peel_vec_u8 (& мут bcs) ); //Упакуйте структуру BCSObject з результатами серіалізації BCSObject {id: об'єкт: :id_з_адреси (id), власник, мета: Метадані {ім'я: std: :ascii: :рядок (мета)}}} Методи peel_*, що варіюються в модулі Sui Frame bcs, використовуються для «очищення» кожного окремого поля з серіалізованих байтів BCS. Зверніть увагу, що порядок, яким ми очищаємо поля, повинен бути точно таким же, як порядок полів у визначенні struct.

Тест: Чому результати не однакові з перших двох викликів peel_address на одному об'єкті bcs?

Також зверніть увагу на те, як ми перетворюємо типи з адреси в id, а з вектора в <8>std: :ascii: :string за допомогою допоміжних функцій.

Тест: Що станеться, якби BSCobject мав тип UID замість типу ідентифікатора?

Повний приклад Ser/De Знайдіть повні зразки кодів JavaScript та Sui Move у папці example_projects.

Спочатку серіалізуємо тестовий об'єкт за допомогою програми JavaScript:

//Будуємо тестовий об'єкт для серіалізації, зауважте, що ми можемо вказати формат виводу на hex нехай _байтів = bcs .ser («BCSObject», { ідентифікатор: «0x00000000000000000000000000000000000000000005», власник: «0x0000000000000000000000000000000000000000000а», мета: {ім'я: «ааа"} }) .toString («шестигранник»); Ми хочемо, щоб вихід запису BCS цього разу був у шістнадцятковому форматі, який можна вказати, як вище.

Прикріпіть шестирядку результату серіалізації префіксом 0x та експортуйте до змінної середовища:

експортувати об'єкт_HexString = 0x000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000А03616161 Тепер ми можемо або запустити пов'язані тести Move unit, щоб перевірити правильність:

тест на самостійний рух Ви повинні побачити це в консолі:

БУДІВНИЦТВО bcs_move Запуск тестів Move unit [ПРОПУСК] 0x0: :bcs_object: :тест_десеріалізація Результат тесту: ОК. Всього тестів: 1; пройдено: 1; не вдалося: 0 Або ми можемо опублікувати модуль (і експортувати PACKAGE_ID) і викликати метод emit_object за допомогою наведеного вище BCS серіалізованого шестирядка:

власний виклик клієнта --функція emit_object --модуль bcs_object --package $PACKAGE_ID --аргс $OBJECT_HEXSTRING Потім ми можемо перевірити вкладку Події транзакції на Sui Explorer, щоб побачити, що ми випустили правильно десеріалізований BCSObject:

  • Sui
  • SDKs and Developer Tools
1
Поділитися
Коментарі
.
harry phan.
May 30 2025, 17:12

Що таке лтл-ендіан і біг-ендіан?

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

306Пости450Відповіді
Sui.X.Peera.

Зароби свою частку з 1000 Sui

Заробляй бали репутації та отримуй винагороди за допомогу в розвитку спільноти Sui.

Кампанія винагородЧервень
Ми використовуємо файли cookie, щоб гарантувати вам найкращий досвід на нашому сайті.
Детальніше