比特币开发系列 - 2 序列化
当无法预测二进制字符串的长度时,情况会变得有点棘手,但解决方案非常简单:字符串前缀带有关于其长度的有用信息。可变长度序列化的核心是 varint 伪类型。
到目前为止,我们已经遇到了4种整数类型:int8、int16、int32和int64。但如果我们想要在平均情况下节省内存呢?对于数百万笔交易,区块链很可能会注意到整数序列化的保守努力,因此有了varint 类型。
varint可以是上述任何长度,只要指定了这样的长度 - 除了int8之外 - 还需要额外的1字节前缀:
typedef enum {
BBP_VARINT16 = 0xfd,
BBP_VARINT32 = 0xfe,
BBP_VARINT64 = 0xff
} bbp_varint_t;
8位varint没有这样的前缀,因为它们本身就是一个值。下表将希望能够阐明一些问题:
大小 | 值 | 编码 |
---|---|---|
8位 | 8c |
8c |
16位 | 12 a4 |
fd 12 a4 |
32位 | 12 a4 5b 78 |
fe 12 a4 5b 78 |
64位 | 12 a4 5b 78 12 c4 56 d8 |
ff 12 a4 5b 78 12 c4 56 d8 |
请注意,varint 前缀引入了之后要到来的数字的大小。varint8 的唯一限制是它无法表示fd
-ff
值,因为它们具有特殊含义,因此需要 varint16。
查看 varint.h 以获取 varint 解析实现。
考虑字节字符串:
13 9c fd 7d 80 44 6b a2 20 cc
如在 ex-varints.c 中所示:
uint8_t bytes[] = {
0x13, 0x9c, 0xfd, 0x7d,
0x80, 0x44, 0x6b, 0xa2,
0x20, 0xcc
};
以及相应的高级结构:
typedef struct {
uint16_t fixed1;
uint64_t var2;
uint32_t fixed3;
uint8_t fixed4;
} foo_t;
该结构有 3 个固定长度整数和 1 个可变长度整数(按约定)。由于 varints 可以容纳高达 64 位的值,我们需要分配最大的大小。以下是我们如何将二进制字符串解码为结构体:
foo_t decoded;
size_t varlen;
decoded.fixed1 = bbp_eint16(BBP_LITTLE, *(uint16_t *)bytes);
decoded.var2 = bbp_varint_get(bytes + 2, &varlen);
decoded.fixed3 = bbp_eint32(BBP_LITTLE, *(uint32_t *)(bytes + 2 + varlen));
decoded.fixed4 = *(bytes + 2 + varlen + 4);
换句话说:
9c13
。bytes + 2
(int16 占用 2 个字节)。bytes + 2
保存fd
并宣布一个 varint16。807d
。bytes + 5
(varint16 占用varlen = 3
个字节)。20a26b44
。cc
。现在你已经能够读取 varint,反序列化可变数据就易如反掌了。从技术上讲,可变数据只是一些带有其长度的 varint 前缀的二进制数据。考虑 13 字节的字符串:
fd 0a 00 e3 03 41 8b a6
20 e1 b7 83 60
如在 ex-vardata.c 中所示:
uint8_t bytes[] = {
0xfd, 0x0a, 0x00, 0xe3,
0x03, 0x41, 0x8b, 0xa6,
0x20, 0xe1, 0xb7, 0x83,
0x60
};
以下是解码过程:
size_t len;
size_t varlen;
uint8_t data[100] = { 0 };
len = bbp_varint_get(bytes, &varlen);
memcpy(data, bytes + varlen, len);
与前一个示例类似,我们在数组开头找到一个 varint16,其中包含值0a
,这在十进制中是 10。10 是接下来数据的长度,因此我们从byte + 3
开始读取 10 个字节,因为 varint16 占用varlen = 3
个字节。就是这样!
对于可变字符串也是一样,只需在序列化之前对其进行 UTF-8 编码。
在 GitHub 上查看完整源代码。
你已经学会了如何为区块链序列化可变长度数据。你已经完全准备好利用更大的实体了!
在下一篇文章中,我将教你一些关于密钥和区块链属性的概念。如果你喜欢这篇文章,请分享。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!