一笔转账能在十分钟内被打包进块,靠的不只是手续费,也靠一条低调的传播协议:当矿工找到新区块时,网络并不是把兆级字节的完整区块原封不动转发给每个节点。BIP152 的压缩区块机制让大多数节点只收到一份”目录”,缺哪几笔再单独点名补。这个设计决定了一笔普通支付为什么很少因为”区块没传开”而晚确认,也决定了节点带宽花在刀刃上的方式。
先回到朴素方案的成本。新区块里绝大多数交易是十分钟前就在全网流通过的内存池交易:接收节点本地早有副本,重传一遍纯属浪费。一条链上数千个节点、每十分钟一次、每次数兆字节,光区块重传就构成可观的冗余流量。朴素方案的另一条路是”先收到交易集合的哈希清单,再请求缺失项”,清单本身又是一笔不小的哈希数组开销。BIP152 的压缩区块把两个缺点各砍一半:清单用短 ID,缺失项按索引点名。
短 ID 的构造值得展开,因为它决定了”防碰撞”这层安全边界。节点对区块里每笔非预填交易计算一个 6 字节(48 位)的短标识:源码 blockencodings.h 中 SHORTTXIDS_LENGTH 为 6,实现上把交易哈希作输入、以本块随机数与节点随机数拼成的盐跑 siphash,截取结果。48 位短码在海量交易空间里存在生日攻击的理论可能——攻击者若能为某笔交易制造大量哈希变体,也许能撞上与另一笔交易相同的短码,诱导你把 A 安到 B 的位置。协议为此设了两道闸:其一,哈希变体本身在协议层被削弱——交易 ID 与见证交易 ID(wtxid)的定义把这类可改写的字段排除在哈希之外,“同一笔钱、N 种哈希”的空间大幅缩小;其二,接收端校验:收到压缩区块后重建完整交易集合、重算默克尔根并与区块头承诺比对,任何短码歧义最终都逃不过默克尔根的裁决,最多造成一次可修复的重同步,伪造不了任何一笔支付。
消息的实际形状是三件事的拼合:区块头、一笔(或数笔)预填交易、其余交易的短 ID 数组。coinbase 交易永远预填——它的内容由区块本身推导,没有”网络里已见过”的指望;其余交易如果发送方估计接收方没见过(比如新建连接、或者缓存显示对方缺这笔),也可以直接预填整笔。接收节点拿着短 ID 逐一在本地的”我已见交易集合”里查表:命中的直接就位,未命中的记下来,发一条按区块内序号点名的缺失交易请求,对端用一条 blocktxn 消息把整批缺失交易补寄回来。一切顺利时,一个满块的传播体积从兆级压到几十千字节量级,带宽差两个数量级;运气差的节点(刚重启、内存池冷)多花一轮请求-补寄的往返。
版本演进里有一次容易被文档混淆的升级:短 ID 的计算对象。早期实现基于普通交易 ID(txid),协议版本升到 v2 后改以见证交易 ID(wtxid)为输入——v31.0 源码 blockencodings.cpp 里 GetShortID 的入参正是 GetWitnessHash()。动机与隔离见证时代适配:wtxid 把见证数据一并承诺,既延续了抗构造性碰撞的方向,也让带见证的交易在短 ID 空间里有唯一的身份。连接建立时双方通过版本消息协商使用哪个版本,新节点和旧节点混跑时自动退回朴素区块传输,行为兼容。
对节点运维,这套机制有一条可见的开关线:压缩区块在 Bitcoin Core 里默认启用,配置项 -blocksonly 或内存策略调整会让节点改变订阅行为,而”是否宣告自己支持压缩区块”由版本协商在连接期决定——这意味着你在日志里看到的新区块到达延迟,主要取决于你上游对端的内存池与你本地内存池的重叠度。节点重启后头几分钟,你对短 ID 的命中率明显偏低,缺块补寄的流量会短暂升高,随后回落到日常水平。这也是为什么家庭节点的日志里”missing transaction”集中出现在启动窗口,通常不是故障。
顺带澄清一个因果:压缩区块优化的是”已知交易的重复搬运”,不是”确认速度”本身。手续费仍然是你交易何时被打包的决定变量;压缩区块保证的是,矿工打包了也不会因为传播折损让网络后半段多等几十秒。它和孤块率的关系同样属于”间接贡献”:更快的传播缩短了两条分支同时存在的窗口,理论上降低链尖竞争,但日常网络里这个效应远小于出块间隔本身十分钟量级的裕度。把它理解成带宽与延迟的工程优化,比理解成共识改进更接近事实。
风险提示:本文描述网络协议机制,参数与实现以 BIP152 原文及对应版本源码为准;不构成任何投资建议。

发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。