Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit an issue.
构建Smart Contracts (Move)Binary Canonical Serialization (BCS) | 二进制规范序列化 (BCS)

二进制规范化序列化 (BCS)

二进制规范化序列化 (BCS) 是 Aptos 区块链上使用的序列化格式。它是一种二进制规范化的非自描述序列化格式,用于序列化数据结构。BCS 用于序列化链上所有数据,提供 REST API 的二进制响应,并对交易的输入参数进行编码。

概述

由于 BCS 不是自描述格式,读取者必须提前知道字节的格式。

基本类型

支持 8 位、16 位、32 位、64 位、128 位和 256 位无符号整数。它们以小端字节顺序序列化。

Bool (布尔值)

布尔值序列化为单个字节。true 序列化为 0x01false 序列化为 0x00。所有其他值均无效。

字节
true0x01
false0x00
bool.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_bool() {
    // Serialize
    let val: bool = true;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x01]);
 
    // Deserialize
    let val_des = from_bcs::to_bool(bytes);
    assert!(val_des == true);
  }
}

U8 (无符号 8 位整数)

无符号 8 位整数序列化为单个字节。

u8.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_u8() {
    // Serialize
    let val: u8 = 1;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x01]);
 
    // Deserialize
    let val_des = from_bcs::to_u8(bytes);
    assert!(val_des == 1);
  }
}

U16 (无符号 16 位整数)

无符号 16 位整数以小端字节顺序序列化为 2 个字节。

u16.move
#[test_only]
module 0x42::example {
 use std::bcs;
 use std::from_bcs;
 
 #[test]
 fun test_u16() {
   // Serialize
   let val: u16 = 1000;
   let bytes: vector<u8> = bcs::to_bytes(&val);
   assert!(bytes == vector[0xe8, 0x03]);
 
   // Deserialize
   let val_des = from_bcs::to_u16(bytes);
   assert!(val_des == 1000);
 }
}

U32 (无符号 32 位整数)

无符号 32 位整数以小端字节顺序序列化为 4 个字节。

u32.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_u32() {
    // Serialize
    let val: u32 = 1000000000;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x00, 0xca, 0x9a, 0x3b]);
 
    // Deserialize
    let val_des = from_bcs::to_u32(bytes);
    assert!(val_des == 1000000000);
  }
}

U64 (无符号 64 位整数)

无符号 64 位整数以小端字节顺序序列化为 8 个字节。

u64.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_u64() {
    // Serialize
    let val: u64 = 10000000000000000;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x00, 0x40, 0x9c, 0x4f, 0x2c, 0x68, 0x00, 0x00]);
 
    // Deserialize
    let val_des = from_bcs::to_u64(bytes);
    assert!(val_des == 10000000000000000);
  }
}

U128 (无符号 128 位整数)

无符号 128 位整数以小端字节顺序序列化为 16 个字节。

u128.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_u128() {
    // Serialize
    let val: u128 = 10000000000000000;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9c, 0x4f, 0x2c, 0x68, 0x00, 0x00]);
 
    // Deserialize
    let val_des = from_bcs::to_u128(bytes);
    assert!(val_des == 10000000000000000);
  }
}

U256 (无符号 256 位整数)

无符号 256 位整数以小端字节顺序序列化为 32 个字节。

u256.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_u256() {
    // Serialize
    let val: u256 = 10000000000000000;
    let bytes: vector<u8> = bcs::to_bytes(&val);
    assert!(bytes == vector[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x9c, 0x4f, 0x2c, 0x68, 0x00, 0x00]);
 
    // Deserialize
    let val_des = from_bcs::to_u256(bytes);
    assert!(val_des == 10000000000000000);
  }
}

Uleb128 (无符号 128 位变长整数)

无符号 128 位变长整数序列化为可变字节数。每个字节的最高有效位用于指示是否有更多字节需要读取。剩余的 7 位用于存储值。

这通常用于向量的可变长度或枚举。

uleb128.move
// Currently not supported by itself in Move

Sequence 和 FixedSequence

序列化为一个项目的可变长度向量。向量的长度序列化为 Uleb128,后跟重复的项目。FixedSequences 在没有前导大小字节的情况下序列化。读取者必须在反序列化之前知道字节数。

vector.move
#[test_only]
module 0x42::example {
  use std::bcs;
  use std::from_bcs;
 
  #[test]
  fun test_vector() {
    // Serialize
    let val = vector[1u8, 2u8, 3u8];
    let bytes = bcs::to_bytes(&val);
    assert!(bytes == vector[3, 1, 2, 3]);
 
    // Deserialize, only supports bytes for now
    let val_des = from_bcs::to_bytes(bytes);
    assert!(val_des == vector[1, 2, 3]);
  }
}

复杂类型

字符串

字符串序列化为字节向量,但字节编码为 UTF-8。

// Note that this string has 10 characters but has a byte length of 24
let utf8_str = "çå∞≠¢õß∂ƒ∫";
let expecting = vec![
    24, 0xc3, 0xa7, 0xc3, 0xa5, 0xe2, 0x88, 0x9e, 0xe2, 0x89, 0xa0, 0xc2,
    0xa2, 0xc3, 0xb5, 0xc3, 0x9f, 0xe2, 0x88, 0x82, 0xc6, 0x92, 0xe2, 0x88, 0xab,
];
assert_eq!(to_bytes(&utf8_str)?, expecting);

AccountAddress

AccountAddress 序列化为固定的 32 字节向量。

@0x1 => [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01]

结构体

结构体序列化为字段的有序集合。字段按结构体中定义的顺序序列化。

struct Color {
  r: u8 = 1,
  g: u8 = 2,
  b: u8 = 3,
} => [0x01, 0x02, 0x03]

Option

Options 序列化为单个字节以确定是否填充。如果选项为 None,字节为 0x00。如果选项为 Some,字节为 0x01,后跟序列化值。

let some_data: Option<u8> = Some(8);
assert_eq!(to_bytes(&some_data)?, vec![1, 8]);
 
let no_data: Option<u8> = None;
assert_eq!(to_bytes(&no_data)?, vec![0]);

枚举

枚举序列化为 uleb128 以确定使用哪个变体。大小后跟变体的序列化值。

#[derive(Serialize)]
enum E {
    Variant0(u16),
    Variant1(u8),
    Variant2(String),
}
 
let v0 = E::Variant0(8000);
let v1 = E::Variant1(255);
let v2 = E::Variant2("e".to_owned());
 
assert_eq!(to_bytes(&v0)?, vec![0, 0x40, 0x1F]);
assert_eq!(to_bytes(&v1)?, vec![1, 0xFF]);
assert_eq!(to_bytes(&v2)?, vec![2, 1, b'e']);

映射

映射存储为元组序列。映射的长度序列化为 Uleb128,后跟重复的键值对。

let mut map = HashMap::new();
map.insert(b'e', b'f');
map.insert(b'a', b'b');
map.insert(b'c', b'd');
 
let expecting = vec![(b'a', b'b'), (b'c', b'd'), (b'e', b'f')];
 
assert_eq!(to_bytes(&map)?, to_bytes(&expecting)?);

参考