高带宽席位只有三个:sendcmpct 的版本号与席位轮换怎么选出压缩区块对端 图 1
高带宽席位只有三个:sendcmpct 的版本号与席位轮换怎么选出压缩区块对端 · 图 1

压缩区块是比特币块间传播的加速器:新块不再整块转发,而是先发一份只有短 ID 的骨架,接收方用自己内存池里的交易把肉补上(短 ID 与集合差的账目见 区块不整块重传:短交易 ID 与压缩区块的传播账)。但加速器不是免费公交——高带宽模式意味着节点会在收到宣告之前就可能转发尚未验证的压缩块,谁享受这个待遇是有名额的。名额管理与版本协商都写在 sendcmpct 这条消息里。本文按 Bitcoin Core 31.0 源码讲清这套席位制度。

sendcmpct 的两个字段:带宽标志与版本号

sendcmpct 的载荷只有两个字段:一个布尔的高带宽标志,一个 64 位无符号的版本号。版本号的含义是「我愿意在这个版本语义下交换压缩区块」。BIP152 对版本有明确约束:只有带见证数据的 v2 语义被保留,而 Bitcoin Core 源码里 CMPCTBLOCKS_VERSION 常量当前取值正是 2。

处理入站 sendcmpct 的代码就两条路:版本号不等于自己的 CMPCTBLOCKS_VERSION,直接返回,当作对方从未发过(不记过、不断开,只是不启用压缩区块支持);版本号一致,才把对方的「支持压缩区块」标志置起,并记录它的高带宽意愿。这个沉默处理是典型的协议防御姿态:对不认识版本的对端不升级冲突,也不降级猜测。

高带宽席位只有三个:sendcmpct 的版本号与席位轮换怎么选出压缩区块对端 图 2
高带宽席位只有三个:sendcmpct 的版本号与席位轮换怎么选出压缩区块对端 · 图 2

席位簿:只留三个名字

节点维护一份名单:哪些对端被我选中做高带宽压缩区块宣告。名单容量为三——这不是 Bitcoin Core 的私有偏好,而是 BIP152 的硬性规定:每个节点最多选三个对端作为高带宽伙伴。

轮换逻辑藏着一处体贴。当名单已满、又要纳入新对端时,默认动作是把名单最前面的对端降级:向它发一条 sendcmpct(0),告知「从现在起按普通带宽给我宣告」。但代码先做一次检查:如果这次要纳入的是入站对端,而名单里恰好只剩一个出站的高带宽席位排在最前——不降级它,而是把它挪到第二位再执行降级。原因值得琢磨:出站连接是我主动建立的、高带宽请求是我主动讨来的,把主动上门的合作者一脚踢下席位,不如让后来者坐第二排。

双向的开关,各记各的账

每条连接上有两个独立的位:我方宣告给对方的高带宽状态,与对方指定我方享有的状态。收到 sendcmpct(1) 意味着对方选我做它的三个席位之一;收到 sendcmpct(0) 则是让位通知。两条腿各自轮换、互不混淆。

blocksonly 不参与

还有一个前置条件常被忽略:以 -blocksonly 运行的节点从不向对端申请高带宽。源码注释说得很直白——只收区块不收交易的节点,内存池里没有重建骨架所需的肉,压缩区块来了也白来,白白占一个席位。同样,握手阶段没有宣告压缩区块支持的对端也进不了候选池。

为什么只有三个

席位稀缺是这套设计的核心,而非疏漏。高带宽的收益是新块抢先零点几秒到手,成本是可能收到还没验证过的工作——一个恶意对端可以用压缩块做低成本的探测与资源骚扰。把每侧数量压到三,既足以让拓扑良好的节点获得多路径并行传播,也把未验证转发带来的敞口限制在个位数。你家节点与骨干节点的差异,往往不在带宽,而在它恰好被多少个对端选入三席——这取决于连接池构成、节点可信度,甚至重启后席位簿清零重来的时机(重启对网络记忆的影响可参考 peers.dat 与 banlist.dat:节点的网络记忆存在哪)。

可以带走的事实:sendcmpct 是带版本号的君子协定,版本对不上就当没发生;高带宽席位每侧三个,满了降级最老的,但会保住自己主动交下的那个出站席位;blocksonly 与未宣告支持的对端都不在候选之列。这套制度的全部目的,是让压缩区块这条快车道只向少数谈得拢的伙伴开放。