协议演进 / BIP/比特币改进提案 / BIP-155
BIP-155
新增 addrv2 消息,用网络 ID 加变长地址在 P2P 网络中 gossip 节点地址,使 Tor v3、I2P 等长地址也能被传播。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-155 |
|---|---|
| 标题 | addrv2 message |
| 作者 | Wladimir J. van der Laan <[email protected]> |
| 指定日期 | 2019-02-27 |
| 层级 | Peer Services(对等服务) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/155 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki |
二、放在哪一族
节点地址发现与 gossip(地址传播)一族。它接续的是既有的 addr 消息:节点靠互相转告“我知道这些节点在这些网络端点上”,新节点才能逐步找到可连接的对等节点,无需永远依赖少数种子。
BIP-155 不是推翻 addr,而是给它配一个 v2 继任者。旧 addr 把一切端点塞进固定的 16 字节地址字段(洋葱地址靠 OnionCat 方式嵌进 IPv6 形式),装不下新一代网络的长地址;addrv2 用“网络 ID + 变长地址”的结构把这个上限打开,同时保留与旧对等节点的兼容路径。
原文文件头没有 Requires、Replaces 等关系字段——它与旧 addr 的关系是并行兼容、按对端能力选用,而不是在文件头层面声明取代。
三、它要解决什么
原文 Motivation 聚焦一个具体的装不下问题:
Tor v3 隐藏服务自 Tor 0.3.2.9 起进入稳定版,相比旧版隐藏服务有更好的加密与隐私特性,但它的地址是 256 位的,塞不进现有 addr 消息——旧消息把洋葱地址封装在 OnionCat IPv6 地址里,地址字段只有 128 位。
不止 Tor:I2P 等其他传输层协议历来就使用更长的地址。地址 gossip 不过去,意味着这些网络上的节点无法经 P2P 网络被其他对等节点发现和连接,哪怕节点软件本身支持走这些网络出站。
因此需要一条新消息:能装下更长的端点地址、能区分地址属于哪个网络、还能继续与只懂旧 addr 的节点共存。
四、规则本身
4.1 消息格式:把定长字段换成网络 ID 加变长地址
addrv2 消息(pchCommand == "addrv2")沿用 P2P 消息的标准序列化,整体结构与 addr 相近,差别有两处:固定的 16 字节 IP 地址被换成一个网络 ID 加一段变长地址;服务位(services)字段改用 CompactSize 编码(通常更省字节,这是原文致谢中点明的改动来源之一)。
每条地址记录包含:
time(uint32):该节点最近一次被见到连在网络上的时间,UNIX 纪元时间;services(CompactSize):服务位位字段;networkID(uint8):网络标识,说明下面的地址属于哪个网络;addr(变长字节串):网络地址,具体解释取决于 networkID;port(uint16):网络端口,与该网络无关时必须为 0。
上限纪律:一条消息最多装 1,000 个地址,客户端应拒绝超出的消息;单个 addr 字段最长 512 字节(4096 位),更长的应拒绝,不论网络 ID 为何。收到与表中规定长度不符的地址,客户端应拒绝该消息中的相应地址,因为它们没有意义。
4.2 网络 ID 登记表
原文保留的网络 ID 如下(新的网络 ID 必须另以一份 BIP 文档登记,不得私自占用):
0x01IPV4:IPv4 地址,4 字节0x02IPV6:IPv6 地址,16 字节0x03TORV2:Tor v2 隐藏服务地址,10 字节(原文现行版注明 Tor v2 已不再运行:客户端不得 gossip 或中继 Tor v2 地址,收到时必须忽略)0x04TORV3:Tor v3 隐藏服务地址,32 字节——附录 B 规定只发其 32 字节公钥部分,版本号恒为 0x03,足以重建完整的 .onion 地址0x05I2P:I2P 覆盖网络地址,32 字节——附录 C 规定发解码后的 SHA-256 哈希0x06CJDNS:Cjdns 覆盖网络地址,16 字节(即 fc00::/8 范围内的 IPv6 形式地址)0x07YGGDRASIL:Yggdrasil 覆盖网络地址,16 字节(即 0200::/7 范围内的 IPv6 形式地址)
两条防混淆规则:其一,某些 IPv6 地址段本身是用来嵌入其他网络的(例如 IPv4-in-IPv6 的 ::ffff:0:0/96),这类地址已有其所属网络 ID 下的规范编码,不得再以 IPV6 的名义发送,收到时应忽略,以免同一端点被当作两个不同的对等节点。其二,客户端不应 gossip 自己不认识的网络的地址——无法验证真伪,就可能被 trick 去传播无效地址;反之,建议客户端 gossip 所有已知网络的地址,哪怕自己当前并未连在其中某些网络上,这对多宿主(multi-homed)节点有帮助,也让观察者更难判断一个节点到底连了哪些网络。
各网络的具体编码细节放在原文附录 A 至 E 中,包括 Tor v2 的旧编码(已停用)、Tor v3、I2P、Cjdns 与 Yggdrasil 的编码方式。
4.3 如何宣告支持:sendaddrv2
新增一条 sendaddrv2 消息表示“我能懂 addrv2,请优先发 addrv2 给我”——它只表达对接收 addrv2(而非 addr)的偏好,不涉及是否愿意接收未经请求的地址消息。
时序是硬性的:sendaddrv2 只能在收到对方 version 消息之后、自己发出 verack 之前发送。对没有发过 sendaddrv2 的旧对等节点,继续发旧的 addr 消息,并忽略其中新引入的地址类型,保证新旧节点混在同一网络里都能工作。
原文 Reference implementation 一节列出了 Bitcoin Core 中的原始参考实现条目链接。
五、谁必须动
普通持币人:无直接动作。这里的“地址”是节点在各网络上的端点,不是收款地址;钱包里的地址格式完全不受影响。
全节点:本 BIP 的实现主体:按对端是否发过 sendaddrv2 决定发 addrv2 还是旧 addr,遵守条数、长度与网络 ID 的校验纪律,并按规定 gossip 已知网络的地址。
钱包开发者:一般不必实现;只有自带 P2P 地址发现逻辑的实现才需要处理 addrv2 与 sendaddrv2。
共识层:完全不动。节点地址如何传播,不影响区块与交易的有效性。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。按 BIP 体系的用法,这表示规范已进入实际运行的部署:支持它的节点之间用 addrv2 交换包括 Tor v3、I2P 在内的各类端点地址,不支持的旧节点继续走旧 addr 路径,两者并存。它解决的是一类很实际的连通性问题:没有可 gossip 的长地址格式,运行在新一代洋葱服务或 I2P 上的节点就很难被网络发现。
常见误读:
“BIP-155 改了比特币的地址格式,以后收款地址要变长了。”
不对。这里的 address 从头到尾指的都是 P2P 网络中节点的网络端点(IP、.onion、.i2p 等),是“节点在哪里能被连上”的问题;用户之间付款用的比特币地址(其格式由地址与脚本类 BIP 定义)与本 BIP 毫无关系。把两者混为一谈,就会误以为每次 P2P 消息升级都要换钱包地址。
七、延伸
- 阅读版:https://bips.dev/155
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0155.mediawiki
- 相关:原文未在文件头列依赖或前后任 BIP;新网络 ID 的登记须另行提出 BIP,编码细节见官方原文附录 A–E
- 仓库总目录:https://github.com/bitcoin/bips
