广播进了队列:privatebroadcast 与 getprivatebroadcastinfo 的读写两笔 图 1
广播进了队列:privatebroadcast 与 getprivatebroadcastinfo 的读写两笔 · 图 1

比特币核心 v31.0 给交易广播加了一条更讲究隐私的路:开 -privatebroadcast 之后,sendrawtransaction 提交的交易不再从本机所有对端同时喊出去,而是只通过 Tor 或 I2P 网络的专用短连接发走,本机内存池也要等交易从网络上”转一圈回来”才收录。同年新增的两条 RPC——getprivatebroadcastinfo 和 abortprivatebroadcast——就是给这条异步队列装的仪表盘和急刹车。这篇拆解队列的机制、两条 RPC 的读法,以及从”广播即成功”转向”广播排队中”带来的心智变化。

先说清默认行为的隐私问题。传统路径下,sendrawtransaction 把交易塞进本机内存池,然后无差别发给所有开了交易中继的连接。网络里节点收到一笔”从对端直接递过来”的交易,第一反应往往是记下游说者——谁先递给我,谁就最接近源头。如果你的节点只有少数几条普通连接,甚至单条直连,手工广播基本等于自报家门:发行说明原文提醒,用 sendrawtransaction 手动重发会因泄露交易来源而损害隐私,因为节点通常不会重转发已在本机内存池里的非钱包交易。

-privatebroadcast 改变两件事。按 v31.0 源码里 sendrawtransaction 的帮助文本:启用后,交易只经”专用的、短生命周期的”连接到 Tor 或 I2P 对端(或经 Tor 出去的 IPv4/IPv6 对端)发送;交易要等从网络回传才进入本机内存池。两条隐私收益对应两层攻击:源 IP 不再与交易同场出现;两笔无关联交易因为各用一条独立连接而不再可链接。代价是广播从同步变异步:RPC 返回交易哈希只说明它被接受进队列,不再意味着”已经发出去了”。

getprivatebroadcastinfo 是队列的只读视图。按 rpc/mempool.cpp 的结果声明,它返回 transactions 数组,每笔交易给出 txid、wtxid、完整十六进制,外加一个 peers 数组——记录这笔交易被发给哪些对端地址、何时被挑中发送(sent,Unix 秒)以及对端何时确认收到(received,可选)。这两个时间字段就是排障的关键:发出去很久没有任何对端回执,通常是 Tor 出口或对端可达性问题;反复重挑同一对端,说明可用中继太少。abortprivatebroadcast 则按你给的 id(同时匹配 txid 与 wtxid)把交易从队列里移除并返回被移除的交易;队列里找不到时它直接报 RPC 错误并提示你先查 getprivatebroadcastinfo。一个容易忽略的细节来自参数文档:同一个 txid 若对应队列里多条不同 wtxid 的交易,一次 abort 会把它们一起移除并全部列在返回里。

运维上有几条硬边界。第一,启用前提是网络可达:源码在广播入口检查 Tor 或 I2P 至少一个可达,否则 sendrawtransaction 直接报错停机,提示检查 Tor 守护进程、-torcontrol、-torpassword 或 -i2psam 配置——开着 -privatebroadcast 却忘了配代理,是这类节点最常见的故障形态。第二,私有广播只对 sendrawtransaction 生效:钱包正常发款走自己的广播路径,不受这个开关影响。第三,“从网络回传才入池”意味着你的节点在窗口期内看不到这笔交易:依赖本机 mempool 做对账的系统要意识到这个空窗,或改用 ZMQ/链上数据核对。第四,隐私收益建立在混淆集上:如果你的节点同时有二十条普通中继连接,广播回传路径仍然可能被旁观者做时间关联分析——发行说明承诺的是不泄露源 IP 与两笔交易不可链接这两点,不要加码理解。

还有一个容易忽略的对照面:-privatebroadcast 只改变 sendrawtransaction 这条路径,钱包发款走的仍是”入本机内存池再向各对端公告”的传统中继——源码里两条路径对应不同的广播方法枚举,井水不犯河水。这个开关真正补上的是”手动提交一笔外部构造交易”这个长期裸奔的场景:硬件钱包导出签名后人工代播、冷机签名后由热机代发,过去这些操作等于把源 IP 递给了所有对端。把它纳入配置,等于给这些高频运维动作统一上了一层最低的出处卫生。

版本边界:-privatebroadcast、getprivatebroadcastinfo、abortprivatebroadcast 三者都自 v31.0 起存在(对应 PR 29415 与 34329),v30 及更早版本没有这条队列;默认值为关闭(源码 net.h 中 DEFAULT_PRIVATE_BROADCAST 为 false),不开则行为与历史完全一致。

风险提示:更精细的广播控制改善的是隐私期望而非绝对匿名,请勿据此处理需要强匿名的场景;本文不构成投资建议。

广播进了队列:privatebroadcast 与 getprivatebroadcastinfo 的读写两笔 图 2
广播进了队列:privatebroadcast 与 getprivatebroadcastinfo 的读写两笔 · 图 2