Sui.

帖子

分享您的知识。

article banner.
0xduckmove.
May 30, 2025
文章

Sui 中的 BCS 编码它是什么以及它为何重要

如果你是在 Sui 的基础上进行构建或者修改 Move,你可能已经听说过 BCS 这个词流传开来. 这是最初为Diem区块链设计的二进制规范序列化格式化机器的缩写,现在是Sui、Aptos、Starcoin和0L等基于MOVE的生态系统的基石.

所以,是的,如果你真的想在这个空间里建房,你最好对它感到舒服.

什么是 BCS?

二进制规范序列化 (BCS) 是一种用于将结构化数据序列化(编码)和反序列化(解码)为字节的格式.

你会看到它在以下情况下使用:

-在签名之前对交易进行编码. -从区块链发出或解析事件. -通过 JavaScript 在链下与 Move 智能合约进行交互.

但是 BCS 不包括字节中的类型信息. 这意味着在解码时必须提前了解结构,这与 JSON 或协议缓冲区等格式不同,后者更具自我描述性.

BCS 的主要功能

没有类型元数据

序列化输出不包含有关字段类型的提示. 解码时你必须知道自己在处理什么.

依赖订单的序列化

结构按照其字段的确切顺序进行编码. 更改顺序,你的反序列化就会中断. 这就是为什么 Move 中的 peel_* 函数必须与结构的布局 1:1 匹配的原因.

泛型类型

在像这样的结构中:

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

你只能可靠地反序列化到元字段. 泛型类型会干扰 BCS 解析,因此,如果您想安全解码数据,请务必将它们放在最后.

在 JavaScript 中使用区块链

多亏了 @mysten /bcs 库,你可以像专业人士一样在 JS 中使用 BCS.

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

注册自定义类型

假设你有以下 Move 结构:

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智能合约的真正运作方式——以及如何安全地桥接链上的 ↔ 链下系统.

而且,如果你在 Sui Explorer 上调试 BCS 字节(如下所示):

BCS 编码 二进制权威序列化(BCS)是在Diem区块链的背景下开发的一种序列化格式,现在广泛用于大多数基于Move的区块链(Sui、Starcoin、Aptos、0L). BCS 不仅用于 Move VM,还用于交易和事件编码,例如在签名之前序列化交易或解析事件数据.

如果您想更深入地了解 Move 的工作原理并成为 Move 专家,了解 BCS 的工作原理至关重要. 让我们潜入吧.

BCS 规格和特性 在我们完成本课的其余部分时,最好记住BCS编码的一些高级属性:

BCS 是一种数据序列化格式,其中生成的输出字节不包含任何类型信息;因此,接收编码字节的一方需要知道如何反序列化数据

BCS 中没有结构(因为没有类型);该结构仅定义了字段序列化的顺序

包装器类型会被忽略,因此 outerType 和 unnestedType 将具有相同的 BCS 表示形式:

struct outerType { 所有者:innerType } struct innerType { 地址:地址 } struct unnestedType { 地址:地址 } 包含泛型类型字段的类型最多可以解析到第一个泛型类型字段. 因此,如果它是自定义类型,则最好将泛型类型字段放在最后一个或多个字段.

struct bcsObject 已删除,复制 { ID:身份证, 所有者:地址, 元数据:元数据, 通用:T } 在这个例子中,我们可以反序列化直到元字段的所有内容.

像无符号整数这样的原始类型以 Little Endian 格式编码

向量序列化为 ULEB128 长度(最大长度可达 u32),然后是向量的内容.

完整的 BCS 规范可以在 BCS 存储库中找到.

使用 @mysten /bcs JavaScript 库 安装 你需要为这部分安装的库是 @mysten /bcs 库. 你可以通过在节点项目的根目录中键入来安装它:

npm i @mysten /bcs 基本示例 让我们先使用 JavaScript 库来序列化和反序列化一些简单的数据类型:

从 “@mysten /bcs” 导入 {BCS,getsuiMoveConfig};

//使用默认 Sui Move 配置初始化序列化器 const bcs = 新 BCS (getsuiMoveConfig ());

//定义一些测试数据类型 常量整数 = 10; const 数组 = [1, 2, 3, 4]; const 字符串 = “测试字符串”

//使用 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, ser_Integer.toBytes ()); const de_array = bcs.de(“向量”,ser_Array.toBytes ()); const de_string = bcs.de (BCS.STRING, ser_string.toBytes ()); 我们可以使用上述语法,即新的 BCS(getsuiMoveConfig ()),使用 Sui Move 的内置默认设置初始化序列化器实例.

有内置枚举可用于 Sui Move 类型,例如 BCS.U16、BCS.STRING 等. 对于泛型类型,可以使用与 Sui Move 相同的语法来定义,例如上面示例中的矢量.

让我们仔细看看序列化和反序列化的字段:

int 是小端十六进制

0a00 10

向量的第一个元素表示总长度,

那么它就是向量中的任何元素

0401020304 1,2,3,4

字符串只是 u8 的向量,第一个元素等于字符串的长度

0b7465737420737472696e67 测试字符串 类型注册 我们可以使用以下语法注册我们将要使用的自定义类型:

从 “@mysten /bcs” 导入 {BCS,getsuiMoveConfig}; const bcs = 新 BCS (getsuiMoveConfig ());

//注册元数据类型 bcs.registerStructType (“元数据”,{ 名称:BCS.STRING, });

//我们打算读取的主对象也一样 bcs.registerStructType (“bcsObject”, { //BCS.ADDRESS 用于 ID 类型和地址类型 ID:BCS.地址, 所有者:BCS.ADDRESS, meta: “元数据”, }); 在 Sui 智能合约中使用 bcs 让我们继续使用上面的结构示例.

结构定义 我们从 Sui Move 合约中相应的结构定义开始.

{ //.. struct 元数据已删除,复制 { 名称:std:: ascii:: String }

struct bcsObject 已删除,复制 { ID:身份证, 所有者:地址, meta:元数据 } //.. } 反序列化 现在,让我们编写一个函数来反序列化 Sui 合约中的对象.

公共娱乐 object_from_bytes(bcs_bytes:矢量):bcsObject {

//初始化 bcs 字节实例 让 bcs = bcs:: new (bcs_bytes);

//使用peel_*函数从序列化字节中提取值.
//顺序必须与我们在序列化中使用的顺序相同! let (id、所有者、元数据) = ( bcs:: peel_address (&mut bcs)、bcs:: peel_address (&mut bcs)、bcs:: peel_vec_u8 (&mut bcs) ); //使用序列化结果打包 BcsObject 结构 bcsObject {id: object:: id_from_address (id),所有者,元数据:元数据 {名称:std:: ascii:: string (meta)}} Sui Frame bcs 模块中各种 peel_* 方法用于从 BCS 序列化字节中 “剥离” 每个单独的字段. 请注意,我们剥离字段的顺序必须与结构定义中字段的顺序完全相同.

测验:为什么对同一 bcs 对象进行前两次 peel_address 调用的结果不一样?

另请注意我们如何使用辅助函数将类型从地址转换为 id,以及如何将<8>向量转换为 std:: ascii:: string.

测验:如果 BSCObject 使用 UID 类型而不是 ID 类型会发生什么?

完整的 Ser/De 示例 在 example_projects 文件夹中查找完整的 JavaScript 和 Sui Move 示例代码.

首先,我们使用 JavaScript 程序序列化一个测试对象:

//我们构造一个用于序列化的测试对象,注意我们可以将输出格式指定为十六进制 让 _bytes = bcs .ser(“bcsObject”,{ id:“0x000000000000000000000000000000000000000005”, 所有者:“0x000000000000000000000000000000000000a”, 元数据:{名称:“aaa”} }) .toString(“十六进制”); 这次我们希望 BCS 写入器的输出采用十六进制格式,可以像上面一样指定.

使用 0x 前缀将序列化结果十六进制字符串粘贴并导出到环境变量中:

export object_hexstring=0x00000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000000000 现在我们可以运行关联的 Move 单元测试来检查正确性:

sui move 测试 你应该在控制台中看到这个:

正在构建 bcs_move 运行 Move 单元测试 [PASS] 0x0:: bcs_object:: test_deserialization 测试结果:OK. 测试总数:1;通过次数:1;失败:0 或者我们可以发��模块(并导出 PACKAGE_ID)并使用上面的 BCS 序列化十六进制字符串调用 emit_object 方法:

sui 客户端调用--function emit_object--module bcs_object--package_ID--args $OBJECT_HEXSTRING 然后,我们可以在 Sui Explorer 上查看交易的 “事件” 选项卡,看看我们发出了正确的反序列化的 BcsObject:

  • Sui
  • SDKs and Developer Tools
2
分享
评论
.
harry phan.
May 30 2025, 17:12

什么是小端和大端字节序?

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

610帖子1335答案
Sui.X.Peera.

赚取你的 1000 Sui 份额

获取声誉积分,并因帮助 Sui 社区成长而获得奖励。

奖励活动七月