5个版本

0.0.1-sol52020年4月30日
0.0.1-sol42019年10月25日
0.0.0 2019年8月6日
0.0.0-sol9 2019年7月26日
0.0.0-sol152019年7月27日

#1752 in 数据结构

Download history 43/week @ 2024-03-11 63/week @ 2024-03-18 69/week @ 2024-03-25 99/week @ 2024-04-01 53/week @ 2024-04-08 46/week @ 2024-04-15 59/week @ 2024-04-22 44/week @ 2024-04-29 42/week @ 2024-05-06 64/week @ 2024-05-13 38/week @ 2024-05-20 52/week @ 2024-05-27 40/week @ 2024-06-03 39/week @ 2024-06-10 40/week @ 2024-06-17 59/week @ 2024-06-24

每月下载量 178
21crate中使用 (7 个直接使用)

Apache-2.0

51KB
827

Libra规范序列化 (LCS)

概述

本文档定义了Libra规范序列化 (LCS)。LCS定义了一种确定性的方法,将消息或数据结构转换为字节序列,不受平台、架构或编程语言的影响。

背景

在Libra中,参与者传递消息或数据结构,这些消息或数据结构通常需要由证明者签名并由一个或多个验证者验证。在此上下文中,序列化指的是将消息转换为字节数组的过程。许多序列化方法支持宽松的标准,使得两个实现可以生成两个不同的字节流,代表相同的、相同的消息。虽然对于许多应用程序来说,非确定性序列化不会引起问题,但它会对使用序列化进行加密目的的应用程序造成问题。例如,给定一个签名和一条消息,验证者可能无法产生与证明者在签名消息时构建的相同的序列化字节数组,导致不可验证的消息。换句话说,为了在使用非确定性序列化时确保消息的可验证性,参与者必须保留原始序列化字节的副本,或者冒着失去验证消息的能力的风险。这给参与者带来了负担,需要他们维护序列化字节和反序列化消息的副本,往往导致对安全性和正确性的困惑。虽然存在一些现有的确定性序列化格式,但没有明显的选择。为了解决这个问题,我们提出了Libra规范序列化,它定义了将消息转换为字节的一种确定性方法。

规范

LCS支持以下原始类型

  • 布尔值
  • 有符号8位、16位、32位和64位整数
  • 无符号8位、16位、32位和64位整数
  • 长度前缀的字节数组
  • UTF-8编码的字符串
  • 结构体

通用结构

消息的序列化格式不自行指定其编码,换句话说,LCS采用流式编码,允许存储任意长度的消息。LCS定义了整数、布尔值和字节数组等原语的结构。它使用这些原语的组合来支持枚举、映射和对象等高级数据结构。由于这种无类型但表达性强的特性,每个消息都需要一个序列化器和相应的反序列化器。

除非指定,所有数字都以小端、二进制补码格式存储。

布尔值和整数

类型 原始数据 十六进制表示 序列化格式
布尔值 真 / 假 0x01 / 0x00 [01] / [00]
8位有符号整数 -1 0xFF [FF]
8位无符号整数 1 0x01 [01]
16位有符号整数 -4660 0xEDCC [CCED]
16位无符号整数 4660 0x1234 [3412]
32位有符号整数 -305419896 0xEDCBA988 [88A9CBED]
32位无符号整数 305419896 0x12345678 [78563412]
64位有符号整数 -1311768467750121216 0xEDCBA98754321100 [0011325487A9CBED]
64位无符号整数 1311768467750121216 0x12345678ABCDEF00 [00EFCDAB78563412]

字节数组

根据本文件原语部分定义,字节数组以32位无符号整数作为长度前缀。字节数组必须小于或等于2^31字节。

示例

给定一个长度为231800522的字节数组:[0x00 0x01 ... 0xFE 0xFF]

LCS表示:[CAFE D00D 00 01 ... FE FF]

其中231800522序列化为[CAFE D00D]

字符串

默认情况下,字符串以UTF-8格式存储,UTF-8字符串的字节数组的表示前有一个32位无符号整数。

给定长度为:ሰማይ አይታረስ ንጉሥ አይከሰስ።的字符串。

长度前缀格式:[36000000E188B0E1889BE18BAD20E18AA0E18BADE189B3E188A8E188B520E18A95E18C89E188A520E18AA0E18BADE18AA8E188B0E188B5E18DA2]

注意:字符串由20个字符组成,但由54个UTF-8编码的字节组成

结构体

结构体是由可能不同类型的字段组成的固定大小的类型

struct MyStruct {
  boolean: bool,
  bytes: Vec<u8>,
  label: String,
}

结构体中的每个字段按规范结构定义的顺序进行序列化。

LCS会将MyStruct的实例序列化为:[布尔值 字节 标签]

此外,结构体可以存在于其他结构体中。LCS递归到每个结构体,并按顺序进行序列化。考虑

struct Wrapper {
  inner: MyStruct,
  name: String,
}

LCS会将Wrapper的实例序列化为:[内部名称] 去除一层抽象:[布尔值 字节 标签 名称]

没有标签,结构体顺序定义了序列化流中的组织。

高级数据类型

利用原语规范,更高级的类型可以通过LCS进行序列化。

高级类型包括

  • 元组
  • 可变长度数组
  • 映射(键/值存储)
  • 枚举
  • 可选数据

元组

元组是对象的类型化组合:(Type0, Type1)

元组可以被视为无名称的结构体,并利用LCS中匿名结构体相同的组织。像结构体一样,每个对象应使用其定义良好的、一致的序列化方法进行序列化,然后按元组内定义的顺序顺序放置到位流中。

字节表示:[tuple.0, tuple.1]

注意:元组不需要长度,因为它们与结构体一样固定在长度。

可变长度数组

可变长度数组由一个公共对象组成。在LCS中,它们首先以数组中元素数量的长度前缀表示,然后是按数组中存储的顺序对每个对象进行序列化。

假设一个对象数组,[obj0, obj1, obj2, ...]

LCS会将此元组的实例序列化为:[数组长度 | obj0 obj1 obj2 ...]

映射(键/值存储)

映射可以视为长度为两个元组的可变长度数组,其中键指向值表示为(键,值)。因此,它们应该首先按字典顺序序列化,顺序由LCS序列化的键的字节表示定义,然后是每个条目。

考虑以下映射

{
  "A" => "B",
  "C" => "D",
  "E" => "F"
}

LCS会将其序列化为:[3 A B C D E F]

(注意,上面已经按字典顺序排列)

枚举

枚举通常表示为

enum Option {
  option0(u32),
  option1(u64)
}

其中枚举对象只能表示这些选项之一。

在LCS中,每个选项都映射到一个特定的32位无符号整数,后面可以跟有类型关联的值时可选序列化的数据。

option0将被编码为0

而option1将被编码为1

示例

  • option0(5) -> [0000 0000 0500 0000]
  • option1(6) -> [0100 0000 0600 0000 0000 0000]

可选数据

可选或可空数据要么以完整表示存在,要么不存在。例如,

optional_data: Option(uint8); // Rust
uint8 *optional_data; // C

LCS表示为:如果数据,例如optional_data等于8,存在:[True data] -> [01 08] 如果数据不存在:[False] -> [00]

向后兼容性

高级对象定义得不是很严格,但更多地依赖于它们所使用的规范。LCS不提供直接的版本控制或前后兼容性规定。对象结构的更改可能会阻止历史客户端理解新客户端,反之亦然。

原始交易序列化

注意:请参阅types/src/unit_tests/canonical_serializer_examples.rs以验证这些类型在LCS的Rust实现中的类型。

原始交易

struct RawTransaction {
    sender: AccountAddress,
    sequence_number: u64,
    payload: TransactionPayload,
    max_gas_amount: u64,
    gas_unit_price: u64,
    expiration_time: Duration,
}
  • AccountAddress表示为可变长度字节区域,其中字节区域是地址本身
  • u64是一个64位无符号整数
  • TransactionPayload是一个枚举,表示Program或WriteSet
  • Duration是以秒为单位的64位无符号整数

Program

struct Program {
  code: Vec<u8>, // Variable length byte array
  args: Vec<TransactionArgument>, // Variable length array of TransactionArguments
  modules: Vec<Vec<u8>>, // Variable length array of variable length byte arrays
}

TransactionArgument

enum TransactionArgument {
    U64(u64), // unsigned 64-bit integer
    Address(AccountAddress), // Address represented as a variable length byte array
    ByteArray(ByteArray), // Variable length byte array
    String(String), // Variable length byte array of a string in UTF8 format
}

WriteSet


struct WriteSet {
   // Variable length array of the tuple containing AccessPath and WriteOp
  write_set: Vec<(AccessPath, WriteOp)>,
}

AccessPath

struct AccessPath {
  address: AccountAddress, // Address represented as a variable length byte array
  path: Vec<u8>, // Variable length byte array
}

WriteOp

struct WriteOp {
  is_value: bool,
  value: Vec<u8>, // This is optional and not written if is_value is false
}

示例

AccountAddress

字符串表示

ca820bf9305eb97d0d784f71b3955457fbf6911f5300ceaa5d7e8621529eae19

LCS表示:[20000000CA820BF9305EB97D0D784F71B3955457FBF6911F5300CEAA5D7E8621529EAE19]

其中20000000是地址大小:32,表示为小端32位无符号整数

TransactionArgument u64

字符串表示

{U64: 9213671392124193148}

LCS表示:[000000007CC9BDA45089DD7F]

TransactionArgument AccountAddress

字符串表示

{ADDRESS: 2c25991785343b23ae073a50e5fd809a2cd867526b3c1db2b0bf5d1924c693ed}

LCS表示:[01000000200000002C25991785343B23AE073A50E5FD809A2CD867526B3C1DB2B0BF5D1924C693ED]

TransactionArgument String

字符串表示

{STRING: Hello, World!}

LCS表示:[020000000D00000048656C6C6F2C20576F726C6421]

TransactionArgument ByteAddress

字符串表示

{ByteArray: 0xb"cafed00d"}

LCS表示:[0300000004000000CAFED00D]

Program

字符串表示

{
  code: "move",
  args: [{STRING: CAFE D00D}, {STRING: cafe d00d}],
  modules: [[CA][FED0][0D]],
}

LCS表示:[040000006D6F766502000000020000000900000043414645204430304402000000090000006361666520643030640300000001000000CA02000000FED0010000000D]

AccessPath

字符串表示

{
  address: 9a1ad09742d1ffc62e659e9a7797808b206f956f131d07509449c01ad8220ad4,
  path: 01217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97
}

LCS表示:[200000009A1AD09742D1FFC62E659E9A7797808B206F956F131D07509449C01AD8220AD42100000001217DA6C6B3E19F1825CFB2676DAECCE3BF3DE03CF26647C78DF00B371B25CC97]

WriteOp 删除

LCS表示:[00000000]

WriteOp 值

字符串表示:cafed00d [0100000004000000CAFED00D]

WriteSet

字符串表示

[
  (
    AccessPath {
      address: a71d76faa2d2d5c3224ec3d41deb293973564a791e55c6782ba76c2bf0495f9a,
      path: 01217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97
    },
    Deletion
  ),
  (
    AccessPath {
      address: c4c63f80c74b11263e421ebf8486a4e398d0dbc09fa7d4f62ccdb309f3aea81f,
      path: 01217da6c6b3e19f18
    },
    cafed00d
  )
]

LCS表示:[0200000020000000A71D76FAA2D2D5C3224EC3D41DEB293973564A791E55C6782BA76C2BF0495F9A2100000001217DA6C6B3E19F1825CFB2676DAECCE3BF3DE03CF26647C78DF00B371B25CC970000000020000000C4C63F80C74B11263E421EBF8486A4E398D0DBC09FA7D4F62CCDB309F3AEA81F0900000001217DA6C6B3E19F180100000004000000CAFED00D]

带有Program的交易负载

字符串表示

{
  code: "move",
  args: [{STRING: CAFE D00D}, {STRING: cafe d00d}],
  modules: [[CA][FED0][0D]],
}

LCS表示:[00000000040000006D6F766502000000020000000900000043414645204430304402000000090000006361666520643030640300000001000000CA02000000FED0010000000D]

带有WriteSet的交易负载

字符串表示

[
  (
    AccessPath {
      address: a71d76faa2d2d5c3224ec3d41deb293973564a791e55c6782ba76c2bf0495f9a,
      path: 01217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97
    },
    Deletion
  ),
  (
    AccessPath {
      address: c4c63f80c74b11263e421ebf8486a4e398d0dbc09fa7d4f62ccdb309f3aea81f,
      path: 01217da6c6b3e19f18
    },
    cafed00d
  )
]

LCS表示:[010000000200000020000000A71D76FAA2D2D5C3224EC3D41DEB293973564A791E55C6782BA76C2BF0495F9A2100000001217DA6C6B3E19F1825CFB2676DAECCE3BF3DE03CF26647C78DF00B371B25CC970000000020000000C4C63F80C74B11263E421EBF8486A4E398D0DBC09FA7D4F62CCDB309F3AEA81F0900000001217DA6C6B3E19F180100000004000000CAFED00D]

带有Program的原始交易

字符串表示

{
  sender: 3a24a61e05d129cace9e0efc8bc9e33831fec9a9be66f50fd352a2638a49b9ee,
  sequence_number: 32,
  payload: Program {
    code: "move",
    args: [{STRING: CAFE D00D}, {STRING: cafe d00d}],
    modules: [[CA][FED0][0D]],
  } ,
  max_gas_amount: 10000,
  gas_unit_price: 20000,
  expiration_time: 86400 seconds
}

LCS表示:[200000003A24A61E05D129CACE9E0EFC8BC9E33831FEC9A9BE66F50FD352A2638A49B9EE200000000000000000000000040000006D6F766502000000020000000900000043414645204430304402000000090000006361666520643030640300000001000000CA02000000FED0010000000D1027000000000000204E0000000000008051010000000000]

原始交易

字符串表示

{
  sender: c3398a599a6f3b9f30b635af29f2ba046d3a752c26e9d0647b9647d1f4c04ad4,
  sequence_number: 32,
  payload: WriteSet {
    write_set: [
      (
        AccessPath {
          address: a71d76faa2d2d5c3224ec3d41deb293973564a791e55c6782ba76c2bf0495f9a,
          path: 01217da6c6b3e19f1825cfb2676daecce3bf3de03cf26647c78df00b371b25cc97
        },
        Deletion
      ),
      (
        AccessPath {
          address: c4c63f80c74b11263e421ebf8486a4e398d0dbc09fa7d4f62ccdb309f3aea81f,
          path: 01217da6c6b3e19f18
        },
        cafed00d
      )
    ]
  },
  max_gas_amount: 0,
  gas_unit_price: 0,
  expiration_time: 18446744073709551615 seconds
}

LCS表示:[20000000C3398A599A6F3B9F30B635AF29F2BA046D3A752C26E9D0647B9647D1F4C04AD42000000000000000010000000200000020000000A71D76FAA2D2D5C3224EC3D41DEB293973564A791E55C6782BA76C2BF0495F9A2100000001217DA6C6B3E19F1825CFB2676DAECCE3BF3DE03CF26647C78DF00B371B25CC970000000020000000C4C63F80C74B11263E421EBF8486A4E398D0DBC09FA7D4F62CCDB309F3AEA81F0900000001217DA6C6B3E19F180100000004000000CAFED00D00000000000000000000000000000000FFFFFFFFFFFFFFFF]

依赖项

~185KB