帖子
分享您的知识。

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 { 地址:地址 } 包含泛型类型字段的类型最多可以解析到第一个泛型类型字段. 因此,如果它是自定义类型,则最好将泛型类型字段放在最后一个或多个字段.
像无符号整数这样的原始类型以 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,整数);
//使用 bcs.de () 反序列化数据
const de_integer = bcs.de (BCS.U16, ser_Integer.toBytes ());
const de_array = bcs.de(
让我们仔细看看序列化和反序列化的字段:
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 合约中的对象.
//初始化 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
什么是小端和大端字节序?
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

- ... SUIBigSneh+1396
- ... SUISuiLover+1333
- ... SUI0xduckmove+1207
- ... SUIThorfin+1202
- ... SUIOwen+970
- ... SUIharry phan+847
- ... SUItheking+742