Varint紧凑整数:比特币为什么不用四个字节记人数 图 1
Varint紧凑整数:比特币为什么不用四个字节记人数 · 图 1

用比特币开发者工具解码一笔原始交易时,你会看到这样的行:输入数量 2、输出数量 1、脚本长度 25。这些”数量”几乎从不占满固定四个字节——协议用了一套变长记法,能让小数字只吃一个字节。它就是 Varint(VarInt,紧凑大小整数,源码里叫 CompactSize)。这是读懂比特币序列化格式的第一块砖:交易结构、区块结构、P2P 报文全都靠它数数,理解它之后,再看到任何原始字节流都不会迷路。

问题:大多数数字都很小

假设序列化时用固定的 32 位无符号整数记”这笔交易有几个输入”。比特币交易绝大多数输入输出在一位数到两位数之间,每处固定四字节意味着每笔交易白付三字节余量——乘上每天数十万笔、再乘上每笔要在全网传播与存储的份数,浪费非常可观。协议因此采用「按数字大小换档」的编码:数值本身先装进尽可能窄的容器,只在装不下时才换更宽的容器,并在前面立一块牌子说明用的是哪一档。

Varint紧凑整数:比特币为什么不用四个字节记人数 图 2
Varint紧凑整数:比特币为什么不用四个字节记人数 · 图 2

规则:一张四行的换挡表

规则简单到可以背下来。数值小于 253:单字节直接放值,无牌子。等于或大于 253、小于 65536:先写字节 253(0xFD),后跟两个小端字节。小于四十二亿余(2 的 32 次方):写 254(0xFE),跟四个字节。更大:写 255(0xFF),跟八个字节。小端序即低位在前——258 会写成 0xFD 02 01。253 这道换挡坎是历史选择:一个字节能表 0–255,协议把 253–255 征用成牌子,于是 252 成为「单字节容量」的上界。解码器的逻辑也对称:读一字节,小于 253 直接是数;否则按牌子再读后续。这套编码出现在交易的数量字段、脚本前缀、见证堆栈,也出现在区块的事务数量、几乎一切「先报数再报货」的场合。2017 年隔离见证给交易加了「标记+标志位」的新段落,数量字段仍全部沿用 Varint——旧砖在升级里继续服役。

为什么值得单独认识它

第一,它是读懂任何工具输出的钥匙:解码器显示「scriptPubKey 长度 0x19」,就是 25 字节的紧凑声明,对照锁定脚本模板即可秒判付款类型。第二,它解释手续费的最小单位构成——每多一个输入,不只是多一条记录,而是数量字段、序列号、脚本前缀一整套字节同时长大,费率估算的微观账本由这些字节累加而成。第三,它是协议兼容性的活标本:区块体积逼近历史争论上限时,社区算账的对象正是这类编码开销;后续所有瘦身提案(压缩脚本、聚合签名)省下的字节,最终都体现在 Varint 计数与货值之上。

一条字节账

拿最常见的单输入单输出转账做个口算:版本号固定四字节,输入计数一字节,outpoint 三十六字节(三十二字节的交易哈希加四字节序号),序列号四字节;输出计数一字节,金额八字节,脚本长度声明一字节加二十六字节的锁定脚本;见证标记与堆栈计数再摊薄几个字节。全部字节相加、按权重规则折算——数字算一遍你就会明白,为什么钱包「合并小额零钱」能省钱:多攒一个输入,付出的不只是那条记录本身,还有数量字段与整套结构的连锁增长。Varint 在这张账本里的角色,是那个永远只占一到三个字节、却决定后面一切偏移的报数员。

快速问答

问:编码能表示多大的数? 答:最大一档用八个字节,理论范围到 unsigned 64 位整数的上限;但协议在更高层对脚本长度、区块体积另有硬帽,超限直接拒收,解码器也会把异常大的数字视为攻击信号。

问:所有区块链都用 Varint 吗? 答:不是。以太坊用长度前缀方案(RLP),其他生态各有各的整数编码,风格差异会直接反映在节点互操作工具上。

问:自己写解码器要注意什么? 答:小端序与牌子值的排布最易写反;对照规范里的示例十六进制自测一遍再上线,历史上有真实事故源于端序笔误。

常见误区

一是把 Varint 理解成压缩算法——它不压缩信息,只是按需变长。二是看到 0xFD 就紧张,它可能只是「数量 258」的诚实声明。三是把数量字段当作可篡改的自由字段:数量写错,序列化错位,交易直接无效——它不是参数而是结构本身。

风险提示:涉及自行构造交易的场景存在资金丢失风险,请先在测试网验证;本文不构成投资建议。