协议演进 / BIP/比特币改进提案 / BIP-331

BIP-331 祖先包中继

定义按包请求与中继交易的 P2P 消息,让节点能索取某笔交易的全部未确认祖先,并把多笔交易打包下载。本 BIP 目前处于草案状态。

一、档案卡

档案卡
编号BIP-331
标题Ancestor Package Relay
作者Gloria Zhao <[email protected]>
指定日期2022-08-08
讨论日期2022-05-17
层级Peer Services(对等服务)
类型Specification(规范类)
状态Draft(草案)
阅读版https://bips.dev/331
官方原文https://github.com/bitcoin/bips/blob/master/bip-0331.mediawiki

二、放在哪一族

P2P 交易中继与内存池策略族,核心概念是“包”(package):一组以花费关系相连的未确认交易。本篇只定义在网络上“怎么要、怎么给”一个包的消息层;包能否被内存池接受,还取决于另一套安全的包接受策略,原文将后者列为实现本协议的前提。

它的前提与邻居包括:

BIP-339:基于 WTXID 的交易中继,包中交易一律以 WTXID 引用,包中继要求双方都支持 wtxid 中继

BIP-133:feefilter 消息,手续费过滤会影响低费祖先能否被公告,本篇专门讨论了与它的配合

BIP-330:交易公告对账(Erlay),原文指出使用对账中继的客户端可以无冲突地叠加包中继:对账后发现某笔交易有未确认祖先,再用祖先包中继补齐

三、它要解决什么

3.1 高费率交易要能带着低费祖先一起传播

自 0.13 版起,Bitcoin Core 在内存池评估与选币打包时就以祖先包而非单笔交易为单位计算费率。但在传播与接受环节,若只逐笔考虑,一笔交易单独不达内存池最低费率时就会被拒绝或驱逐;用户想给它挂一笔高费子交易来“子付父费”(CPFP)也做不到——子交易会因为花费不存在的输入被拒;想用高费后代替换一笔冲突交易(RBF)同样受阻。

后果是用户加费的手段被削弱。更严重的是,依赖预签名、时效性交易的合约协议(如闪电网络的 HTLC-Timeout、Revault、DLC、Eltoo 等)有一条关键安全假设:各方能及时传播并确认交易。攻击者利用内存池策略限制阻止交易传播或上链的“钉住攻击”(pinning attacks),正是钻了逐笔接受的空子。若预报费率太低又无加费手段,对手方就可能窃取资金;一味高估手续费只能在流量低且可预测时凑效,还浪费用户的钱。

理论上,只要有安全且激励相容的包内存池接受策略就够了,但让节点靠自己试凑被拒交易的组合,既低效又可能打开新的拒绝服务攻击面。因此需要新的 P2P 消息,让节点之间高效、可靠地交换包验证所需的信息。

3.2 更好地处理孤儿交易

按 txid 中继有个毛病:交易的见证数据被篡改时 txid 不变,节点无法用 txid 对已下载或已验证的交易去重。两个都支持 BIP-339 的节点之间,理应不再需要 txid 中继;唯一残留场景是处理“孤儿”交易——花费了本节点尚不知道的未确认交易的输出。

孤儿交易很常见:新节点刚完成初始区块下载、内存池还没跟上,或者从多个对等节点并发下载时子交易先于父交易到达。旧处理办法是把孤儿存进缓存、按 txid(prevout 里写的只有 txid)逐代索取缺失的父交易,既要求节点为未验证数据分配内存,又迫使两个 wtxid 中继节点回退到 txid 中继。本篇让孤儿消解更高效,且不再需要 txid 中继。

3.3 基本术语

父/子:Tx1 花费 Tx0 的输出,则 Tx0 是父、Tx1 是子。祖先/后代:递归地包含父母的父母、子女的子女。包:一列可用有向无环图表示的未确认交易。祖先包:某笔未确认交易加上它的全部未确认祖先。拓扑排序:父交易在列表中排在子交易之前。

四、规则本身

4.1 两轮结构

祖先包中继分两轮:包信息轮,让接收方先知道一个包里有哪些交易、再决定要不要下载;交易数据轮,让节点用一条消息批量下载多笔交易,而不是逐条往返。原文讨论过两个替代方案并都否决了:没有信息轮会让诚实节点大量重复下载已有交易;只有信息轮则总是要存储未验证交易,因此批量下载应是默认路径,逐条下载只作兜底。

协议只由接收方发起,节点不主动向对等方公告包。理由是:主动公告很可能重复对方已知信息而浪费带宽,节省的延迟不如浪费的带宽重要;先上线接收方发起的版本、观察真实用量后,再基于数据设计发送方发起的版本。

协商在版本握手时用 sendpackages 消息完成,其 versions 字段按位域解释(可同时支持多个包版本,以备将来扩展其他包类型)。包中继要求双方都已发送 wtxidrelay,且都没有把 fRelay 设为 false。

4.2 两个能力位

sendpackages 必须在 verack 之前发送,之后收到可断开连接;未知位(包括 versions 为 0)应忽略。

4.3 组合哈希

一个包的“组合哈希”是把包内各交易的 WTXID 按字典序拼接后做 sha256,充当这个包的简短标识,主要用于给 getpkgtxns 一个有意义的 notfound 回应。

4.4 四种新消息与两个 inv 类型

4.5 两个典型流程

孤儿处理:节点收到孤儿交易后,用 getdata(MSG_ANCPKGINFO) 索取其祖先包信息,再按信息批量请求交易数据,整包一起验证——全程不使用 txid 中继,也不必像旧办法那样逐代往返。

CPFP 加费:低费父交易若低于对方的 BIP-133 手续费过滤线,发送方本不会公告它;高费子交易被发出后,接收方把它当孤儿处理,走祖先包流程把父交易一并取回并整包验证,低费祖先就此搭上高费后代的车。前提是节点不能对先前因费率过低被拒的交易一拒了之,而应在得知它是高费交易的祖先后重新索取、按包接受。

五、谁必须动

普通持币人:不直接操作。受益点在于加费手段更可靠:低费交易有机会借后代被整包接受,合约协议的时效性交易也更不容易被钉住。

钱包开发者:钱包本身不发这些 P2P 消息,但其构造的 CPFP、RBF 与合约交易能否顺利传播,取决于节点是否实现包中继与包接受策略。

全节点与矿工:实现者需要新增 sendpackages 协商、四种消息与两个 inv 类型,并守住“全有或全无”、未协商不得使用、未被索取不得发送等规则。更重要的是,原文把安全的包内存池接受策略列为实现安全包中继的前提:接受包不得显著扩大拒绝服务攻击面,也不得假设所有包都是 CPFP——包里也可能高费父带低费子,策略应只留下激励相容的子集。原文给出的示例实现指向 Bitcoin Core 的相关合并请求。

共识层:不涉及。旧客户端完全兼容、互通;实现方只与协商成功的对等节点之间用包中继。原文还提醒:支持包中继的节点不应把低于手续费过滤线的交易的后代公告给不支持包中继的节点,以免对方拒绝后白白浪费带宽。

六、现在算不算数,以及一个常见误读

状态为 Draft(草案)。这套 P2P 消息规范尚在草案阶段;它本身也不等于“包接受已经上线”——消息层与内存池的包接受策略是两件事,后者是前者安全落地的前提。原文没有声称全网节点已普遍采用,本页不臆测部署进度。

常见误读:

“BIP-331 让任何低费交易都能靠一笔高费子交易混进所有节点的内存池。”

不对。本篇定的是请求与中继包的消息协议,是否接受一个包由各节点自己的包接受策略决定,且策略被要求不得扩大拒绝服务面、应只保留激励相容的子集;某些交易即使随包到达,也完全可能因策略不合而被拒。它解决的是“信息怎么高效传到”,不是“到了就必须收”。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。