先递清单,再点菜
比特币网络广播一笔新交易的方式,并不是每个节点把整笔交易立刻抄送所有邻居。真实流程分两步:节点先把交易装进一条 inv 消息,里面只有一个一个条目,每个条目由类型码加三十二字节哈希构成,意思是我这里有这么个东西;收到清单的节点如果发现自己没有这份数据,就回一条 getdata,把同样的类型码和哈希原样点名回去,索取方这才把完整的 tx 或 block 消息发过来。参考手册列出的类型族包括普通交易、带见证数据的交易、区块、默克尔区块和压缩区块等,一条清单装不下时,软件会连续发多条把它摊完。区块传播同理:新块先以 inv 报哈希,带宽敏感的邻居可能选择先拉二十到两千个区块头,再决定要不要要整块。

为什么要拆成两步
问询式结构给了接收方三样东西。第一是去重:邻居二十个都在喊同一个哈希,我只需要向其中一个要一次,剩下的重复清单直接忽略,全网流量因此不会被同一个区块放大二十倍。第二是带宽主权:带宽受限的节点可以对低价值条目干脆不点单,比如内存池同步时先看看清单再决定要不要花钱拉某些交易。第三是失败恢复:没收到货可以再向别的对端点名,请求权始终在收方手里。代价是多一次往返,所以延迟敏感的场景另有优化——压缩区块让节点在对方点单之前就把块的大部分内容猜出来,把两步压回接近一步。
mempool 消息:开局把库存清单摊开
节点刚连上网络时,可以向对端发一条 mempool 消息,对方的回应不是一条包含全部交易的巨型消息,而是一串 inv 消息,把内存池里未确认交易的哈希按清单格式全部报一遍。这对矿工组块和区块浏览器索引特别有用:先拿全清单,再对缺的交易逐条 getdata。手册同时提醒,这类清单和布隆过滤的某些更新模式并不完全兼容,轻量客户端要换用过滤器路线。
getdata 要不到的东西
getdata 不是万能下载器。它能要的是对方当前愿意且能够提供的内容:内存池或中继集合里还留着的交易、完整保留历史时的区块。要是对方节点做了存储裁剪,老区块的文件早被删了,它顶多回一条 notfound,格式和 inv 一样、只是态度从有变成没有。同理,你也没法用 getdata 去要任意历史交易——数据不在对方手里,协议再正确也变不出来。这正是全节点和裁剪节点在服务能力上的真实差别之一。
一条直觉算术
假设某时刻全网约有五千个可达节点,一笔交易若走纯推送模式,向平均十个邻居各推一次完整数据,全网原始流量至少是交易大小的五千倍量级;换成清单模式,每个节点先收到的只是每条三十六字节的哈希条目,真正点单拉取只在少数链路上发生,重复清单还能就地丢弃。区块传播对带宽更敏感,所以后来才有压缩区块这类把清单和点单合并的一步式方案——协议演化史很大程度上就是清单加往返次数的优化史。
快速问答
问:一个恶意节点给我发一堆假的 inv 清单会怎样? 答:清单本身没有真伪承诺,你按哈希点单后要重算工作量证明或验签名才能确认内容,控制类消息几乎都不做任何身份认证,防线在验证环节而不在清单环节。
问:我为什么在自己节点日志里看到大量 inv 却几乎没带宽暴涨? 答:正常的清单交换流量很小,只有你真正 getdata 点单的内容才占带宽。
常见误区
一是以为区块像广播喇叭一样全网同时推送,忽略了先清单后点单的去重设计。二是以为任何一个节点都能供出任何历史区块,存储裁剪之后老数据物理上就不在了。三是把 notfound 当成网络故障,它只是对方库存里没有这份数据的中性答复。
风险提示:本文为网络机制科普,不构成任何投资建议;节点暴露与带宽配置请参照 Bitcoin Core 当期官方文档执行。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。