向谁要交易:txrequest 的记账、延迟与反封锁三件套 图 1
向谁要交易:txrequest 的记账、延迟与反封锁三件套 · 图 1

你刚广播一笔交易,全网很多节点都听说了它,但你的节点迟迟集不齐正文:谁手里有?该找谁要?找他不给怎么办?比特币核心把这套问题交给一个专门的调度器——src/txrequest.cpp,本文按该文件的源码注释把它的手续拆开:每笔交易对每个对端维护一个”什么时候可以问、问了多久算超时”的账本,用延迟、优先对端和随机抽签三件套抵御封锁。

一、状态机:一笔交易在调度器里的五种身份。调度器为每个(交易哈希,对端)组合记一条记录,依次经历:刚收到 inv 宣告时在 CANDIDATE_DELAYED 里等 reqtime(可以开问的最早时刻);到点后转 CANDIDATE_READY;同一交易在所有到点候选里挑出的最优者标 CANDIDATE_BEST;发出 getdata 后进 REQUESTED 并记下 expiry(本次请求的到期时刻);拿到交易、收到 NOTFOUND 或到期未兑现,统一进 COMPLETED。要点在于 READY 和 BEST 没有到期时间——没被问到就一直排队,不会过期作废。

二、reqtime 管”先问谁”。调用方(net_processing)给每个对端的宣告标一个延迟:条件好的对端(延迟低)先问,条件差的排后面。注释里的理由写得很直白:给更可信的对端一个先回答的机会,再麻烦次优目标。这个延迟同时构成防封锁工具——同一条交易的多路宣告故意错峰提问,攻击者就无法靠”抢先说没有”来截断问题。

三、preferred 旗标管”谁的话更重”。调度器不自己判断对端好坏,由调用方给每个对端打一个 preferred 标记(语义由上层决定,v31 实现里对应我们主动发起且值得信任的连接)。规则:只要存在 preferred 候选,非 preferred 对端直接不参与本轮抽签;同组内再在候选里均匀随机挑一个。随机不是点缀——注释明说均匀分配让攻击者难以操纵”谁被派出去要交易”。

四、注释里的封锁算术。txrequest.h 直接给出两组结论:若所有 preferred 连接诚实且至少有一条,攻击者的封锁不会成功;若 preferred 连接里有 Ph 条诚实、共 P 条,攻击者平均只能把我们延迟约 P/(Ph+1) 个到期周期;若 preferred 全是攻击者、另有 NP 条非 preferred 且其中 NPh 条诚实(且攻击者能掐线重连),延迟均值约 P-1+NP/NPh。两组公式的用意是校准安全预算:延迟到期时间与对端多样性是仅有的两个可调杠杆——到期时间越长、可配对端越多,封锁代价越高。

五、和区块下载调度器的分界。区块有另一套独立的在途窗口与请求流水线(按高度、按并行度切分),txrequest 只管交易正文。两套并行不冲突的原因很实际:区块按序大量下载、适合流水线;交易按 ID 零散下载、适合按对端记账。排障时对应两个问题面:节点区块同步慢查前者;节点能收到 inv 宣告却始终拿不到交易正文查后者——后者卡住的典型形状是”该交易只在少数对端间流传”,而我们的 preferred 集合恰好不包含持有者,表现就是交易反复到期、换人重问。

六、边界。这套调度是下载侧策略,不改变中继协议本身:节点仍然靠 inv 宣告发现交易、靠 getdata 索取正文;调度器只决定向谁、何时、问几次。它也防不了”所有人都没有这笔交易”的情形——那属于广播没有送达,解法在广播侧(连接数、隐私网络、直接 sendrawtransaction),不在下载侧。

风险提示:本文内容为技术机制科普,不构成任何投资建议、收益承诺或买卖时机判断。涉及协议规则与软件行为的描述以对应软件版本(文中已标注)的官方源码与规范为准。涉及资金操作的(如通道强制关闭、修剪开关),请先在测试网或小额环境验证。

向谁要交易:txrequest 的记账、延迟与反封锁三件套 图 2
向谁要交易:txrequest 的记账、延迟与反封锁三件套 · 图 2