关于交易转发、交易池接纳和挖矿交易选择的系列周刊的已出版部分的副本 —— 这个系列解释了为父么 Bitcoin Core 设置了比共识规则更严格的交易池规则,以及钱包可以如何更高效地使用这些规则。

  1. 为什么节点需要一个交易池?
  2. 激励兼容
  3. 竞价区块空间
  4. 费率估算
  5. 用于保护节点资源的规则
  6. 规则一致性
  7. 网络资源
  8. 交易池规则是个接口
  9. 规则提案
  10. 参与其中

为什么节点需要一个交易池?

最早出版于Newsletter #251

比特币网络上的许多节点将未确认的交易存储在一个内存池或称之为 交易池(mempool)。该缓存是每个节点的重要资源,使得点对点的交易中继网络成为可能。

参与交易中继的节点稳步而非陡然地下载和验证区块。每隔约 10 分钟发现一个区块时,没有交易池的节点就会出现带宽峰值,随之而来的是验证每笔交易的计算密集期;另一方面,具有交易池的节点通常已经看到了区块的所有交易并将它们存储在它们的内存池中。使用“致密区块中继,这些节点只需下载一个区块头和 shortid,就可以使用其交易池中的交易来重建区块。与区块的大小相比,用于中继致密区块的数据量很小。验证交易也快得多:节点已经验证(并缓存)了签名和脚本,计算了时间锁要求,并已经出于必要、从磁盘加载了相关的 UTXO。该节点还可以迅速将区块转发给其他节点,从而显着提高网络范围内的区块传播速度、降低出现陈旧区块的风险。

交易池也可用于构建独立的费用估算器。区块空间市场是收费拍卖,保留交易池可以让用户更好地了解其他人在竞标什么以及过去哪些竞标成功了。

然而,没有“唯一交易池”这样的东西——每个节点可能会收到不同的交易。向一个节点提交交易并不一定意味着它已经到达矿工手中。一些用户发现这种不确定性令人沮丧,并想知道,“我们为什么不直接向矿工提交交易呢?”

设想一种比特币网络,其中所有交易都直接从用户发送到矿工。人们可以通过要求少数实体记录与每笔交易对应的 IP 地址来审查和监视金融活动,并拒绝接受任何符合特定模式的交易。这种类型的比特币有时可能更方便,但会缺少一些比特币最有价值的特性。

比特币的抗审查性和隐私性来自于它的点对点网络。为了中继交易,每个节点都可以连接到一些匿名的对手节点集,每个对手节点都可以是矿工或与矿工有联系的人。此方法有助于混淆交易源自哪个节点,以及哪个节点可能负责确认它。希望审查特定实体的人可能会针对矿工、热门交易所或其他中心化提交服务,但很难完全阻止任何事情。

未确认交易的普遍可用性也有助于最大限度地降低成为区块生产者的进入成本——对被选择(或被排除)的交易不满意的人可能会立即开始挖矿。将每个节点视为交易广播的平等候选者,可避免给予任何矿工获取交易及其费用的特权。

总之,交易池是一种非常有用的缓存,它允许节点随时间分配区块下载和验证的成本,并让用户获得更好的费用估算。在网络层面,交易池支持交易分发和区块中继网络。当每个人都在矿工将它们包含在区块中之前看到所有交易时,所有这些好处最为明显——就像任何缓存一样,交易池在“火热”时最有用,并且必须限制其大小以适应内存。

下周本节将探讨使用激励相容性作为判断哪些交易将保留在交易池中的最有用的指标。

激励兼容

最早出版于Newsletter #252

本栏目在上周提到,交易池(mempool)是未确认交易的缓存空间,它为用户提供了一种去中心化的、向矿工发送交易数据的方法。但是,矿工没有义务确认这些交易;只包含了一笔 coinbase 交易的区块也是共识上有效的区块。用户可以通过提高输入的价值而不改变输出的总价值 —— 矿工能够获取两端的差额作为交易 手续费 —— 来吸引矿工打包自己的交易。

虽然交易手续费在传统的金融系统中很常见,但刚接触比特币的用户可能经常觉得惊讶,这些手续费不是按支付额的比例收取的,而是根据交易的重量(weight)收取的。也就是说,区块空间才是限制因素,流动性并不是。手续费率 通常以 聪/vB(虚拟字节)来衡量。

共识规则限制了每个区块可用于打包交易的空间。这个限制使得区块广播到整个网络的时间低于出现区块的间隔,从而降低了出现 “过时区块(stale blocks)” 的风险。它也帮助限制了区块链和 UTXO 集的体积增长,这两者都直接构成了启动和维护一个全节点的成本。

因此,作为这个未确认交易的缓存的角色的一部分,交易池也协助了无弹性的区块空间的公开拍卖:在正常运行的时候,拍卖会遵循自由市场的原理,即,完全基于手续费,而非跟矿工的个人关系,来决定交易打包的优先级。

为一个区块(有自身的总重量限制和签名操作数量限制)选择交易、同时最大化手续费,是一个 “NP 困难问题”。这个问题会因为交易之间的关联而变得更加复杂:打包一笔高费率的交易,可能需要同时打包一笔低费率的父交易。反过来说,打包一笔低费率的交易,可能会开启打包高费率子交易的机会。

Bitcoin Core 客户端的交易池会为每一笔交易及其祖先交易计算手续费率(称为 “祖先手续费率”),缓存这个结果,然后使用一种 “贪婪区块模板建构算法”。它会按 “祖先分数”(在祖先手续费率和单体交易手续费率两者间取小值)为交易池排序,然后按顺序选出祖先交易包、更新剩余交易的祖先手续费,并对信息加权。这套算法在性能和获利能力之间取得了一个平衡,但并不一定能产生最优的结果。它的效力可以通过限制单体交易和祖先交易包的体积来提高 —— Bitcoin Core 将它们分别限制在 40 0000 重量单位和 40 4000 重量单位。

类似地,可以计算出一个 后代分数 并用来选择要逐出交易池的交易包,因为逐出自身低手续费率但具有高手续费率后代的交易可能会错失好处。

交易池验证在处理花费相同输入的交易(即,重复花费或者说冲突交易)时也会用到手续费和手续费率。节点不会按先到先得的规则保留先收到的那一笔交易,而是会根据一组规则来确定哪一笔交易更加激励兼容,然后保留下来。这个行为叫做 “手续费替换(Replace by Fee)”。

矿工会最大化手续费,这符合直觉,但为什么一个不挖矿的节点也要实现这些规则呢?就像上周本栏目所说的,不挖矿节点的交易池的效用,是由它跟矿工的交易池的相似性决定的。因此,即使一个节点从不尝试使用其交易池中的内容产生区块,他们也愿意保存最为激励兼容的交易。

虽然没有共识规则要求交易支付手续费,但手续费和手续费率在为比特币网络中扮演着重要角色,它是一种 “公平的” 解决区块空间竞争的办法。矿工使用手续费率来评估可取程度、处理驱逐和冲突,而不挖矿的节点也参照这种行为,以尽可能提高自己的交易池的效用。

区块空间的稀缺性,产生了降低交易体积的压力,并鼓励开发者构造更有效率的交易。下周的专栏中,我们会探索链上交易节约手续费的实用策略和技术。

竞价区块空间

最早出版于Newsletter #253

上周我们提到交易为所用的区块空间支付费用,而不是按照所转移的金额支付费用,并确定矿工将优化他们的交易选择以最大化收取费用。因此,当找到一个块时,只有那些位于交易池头部的交易才会得到确认。在这篇文章中,我们将讨论让手续费花得最值的实用策略。让我们假设我们有一个不错的费率估算来源——我们将在下周的文章中更多地讨论费率估算。

在构建交易时,交易的某些部分比其他部分更灵活。每笔交易都需要头部字段,收款人输出由正在进行的付款决定,并且大多数交易都需要找零输出。发送方和接收方都应该更喜欢区块空间高效的输出类型,以减少未来花费交易输出的成本,但在输入/钱币选择期间,更改交易的最终组成和重量的空间最大。由于交易按费率[费率/重量]竞争,较轻的交易只需更低的费用就能达到相同的费率。

一些钱包,例如 Bitcoin Core 钱包,尝试组合输入以避免设置找零输出。避免找零可以节省现在输出的重量,还可以节省以后花费找零输出的未来成本。不幸的是,除非钱包拥有大量不同金额的大型 UTXO 池,否则这种输入组合几乎不存在。

较新的输出类型比旧输出类型更节省区块空间。例如,花费 P2TR 输入产生的重量不到 P2PKH 输入的 2/5。(使用我们的交易规模计算器试试吧!)对于多重签名钱包,最近定稿的 MuSig2 方案和 FROST 协议通过允许多重签名功能以看起来像单签名输入的方式编码,节省了许多费用。特别是在区块空间需求飙升的时代,使用较新的输出类型的钱包本身就可以节省大量费用。

Overview of input and output weights

聪明的钱包根据费率调整其选择策略:在高费率下,它们使用很少的输入和较新的输入类型来让输入集的重量尽可能低。始终选择最轻的输入集将局部地最小化当前交易的成本,但也会将钱包的 UTXO 池磨成小碎片。这可能会让用户在日后的高手续费率环境下也不得不选择较重的输入集。因此,对钱包来说,具有先见之明的做法是,如果预期日后会出现区块空间的需求高峰,就趁手续费率的低谷选择更多和更重的输入、将资金整合进数量更少的新型输出。

大容量钱包通常会将多个付款批处理到单个交易中,以减少每一笔支付的交易重量。批处理避免了头字节的开销和每次付款的找零输出,所有支付共同分摊同一份固定开销。即使只是批量处理几笔付款,也可以快速降低每次付款的成本。

Savings from payment batching with
P2WPKH

但是,即便许多钱包会错误估计手续费(因此超额支付(overpayment)),在出块缓慢或交易提交量激增的时候,有时交易也会迟迟得不到确认。在这些情况下,发送方或接收方可能希望再次提高交易的确认优先级。

用户通常有两种工具可以提高交易的优先级,即“子为父偿(CPFP)”和“手续费替换(RBF)”。在 CPFP 中,用户花费其交易输出来创建高费率的子交易。正如上周的帖子所描述的那样,矿工被激励将父交易选入区块,以便包括手续费高的子交易。一笔交易的任何收款者均可利用 CPFP,因此接收方和发送方(如果他们创建了找零输出)都可以利用它。

在 RBF 中,发送者制作更高手续费的交易以替换原版交易。替换交易必须重用原版交易中的至少一个输入,以确保与原版交易冲突,并且区块链中只能包含两个交易中的一个。通常,这样的替换交易会保留原版交易的付款,但发送者也可以将替换交易中的资金重新定向,或者在替换时将多个交易的付款合并为一个。正如上周的帖子所述,节点驱逐原版交易,以支持更具激励相容的替换交易。

虽然区块空间的需求和生产都不在我们的控制范围内,但钱包可以使用许多技术来有效地竞标区块空间。钱包可以通过消除找零输出、花费原生的隔离见证输出以及在低费率环境中对其 UTXO 池进行碎片整理,来创建更轻的交易,以节省费用。支持 CPFP 和 RBF 的钱包也可以从保守的费率开始,然后在需要时使用 CPFP 或 RBF 更新交易的优先级。

费率估算

最早出版于Newsletter #254

上周,我们探讨了在给定费率的情况下,最小化交易手续费的技巧。但是,费率应该是多少呢?理想情况下,它应该尽可能低(为了省钱),同时又高到足以保证交易在适合用户时间偏好的区块中获得一个位置。

费(率)估算 的目标是将确认的目标时间转化为交易应支付的最低费率。

费率估算的一个复杂之处在于区块空间生产的不规律。假设一个用户需要在一小时内支付给商家,以收到商品。用户可能期望每 10 分钟挖出一个区块,因此目标是在接下来的 6 个区块中找到一个位置。然而,完全有可能一个区块需要 45 分钟才能被挖出。费率估算器必须在用户期望的紧急程度或者时间窗口(类似于“我希望在工作日结束之前确认这笔交易”)和区块空间供应(一定数量的区块)之间进行转换。许多费用估算器通过将确认目标以区块数量和时间的形式表示来解决这个挑战。

如果没有正在等待确认的交易的信息,人们可以依据历史数据(已经入块的交易的费率)构建一个简单的费用估算器。由于这样的估算器没有考虑交易池中待确认的交易,在区块空间需求出现意外波动和偶尔的长区块间隔时,它会变得非常不准确。它的另一个弱点是它完全依赖矿工控制的信息,矿工可以通过在他们的区块中包含虚假的高费率交易来推高(估算)费率。

幸运的是,区块空间的市场并不是暗标拍卖。我们在第一篇文章中提到,保留交易池并参与点对点交易中继网络允许节点查看用户的出价。Bitcoin Core 费用估算器还使用历史数据来计算交易在 n 个区块内以费率 f 确认的可能性,但具体跟踪节点首次看到交易的高度以及交易确认的时间。这种方法通过忽略公开费用市场之外发生的活动来避免被它们影响。如果矿工在自己的区块中人为地包含高费率交易,则该费用估算器不会出现偏差,因为它仅使用在确认之前被公开转发的交易的数据。

我们还深入了解了为区块选择交易的方式。在上一篇文章中,我们提到节点模拟矿工策略,以便在其交易池中保留激励兼容的交易。扩展这个想法,我们可以构建一个费用估算器来模拟矿工会做什么,而不只是查看过去的数据。为了找出交易在接下来的 n 个区块中为确认所需要的费率,费用估算器可以使用区块组装算法从其交易池中预测接下来的 n 个区块模板,并计算出击败费率最低一笔交易、从而可以进入到区块 n 中的费率。

显然,该费用估算器方法的有效性取决于其交易池内容与矿工内容之间的相似性,而这一点永远无法得到保证。它还忽视了矿工由于外部动机而可能包含的交易,例如,矿工自己的交易、在系统外给矿工支付费用的交易。预测还必须考虑从现在到预测区块被挖出之间新出现的交易。可以通过减少预计区块的大小,来容纳其它交易所带来的影响——但减少多少呢?

这个问题再次凸显了历史数据的效用。智能模型可能能够整合活动模式并考虑影响费率的外部事件,例如典型的营业时间、公司定期的 UTXO 合并以及针对比特币交易价格变化的活动。预测区块空间需求的问题仍然有待探索,并且可能永远有创新的空间。

费用估计是一个多方面且困难的问题。糟糕的费用估计可能会超付费用(也即浪费资金)、增加比特币在支付方面的摩擦、导致 L2 用户因错过一个时间锁定的 UTXO 的备用花费路径而损失资金。良好的费用估计可以让用户清楚而准确地向矿工传达交易的紧急程度,而 CPFPRBF 允许用户在初始估计不足时更新出价。激励兼容的交易池策略,与良好设计的费用估计工具和钱包相结合,使用户能够参与高效的公共拍卖以获取区块空间。

费用估算器通常不会返回低于 1sat/vB 的任何值,无论时间范围有多长,待确认的交易有多少。许多人认为 1sat/vB 是事实上的最低费率。这是因为在比特币网络中,网络上的大多数节点(包括矿工)从不接受低于该费率的任何交易,无论他们的交易池有多空。下周的文章将探讨这种节点策略以及利用费率在交易中继中的另一个动机:防止资源耗尽。

用于保护节点资源的规则

最早出版于Newsletter #255

在本系列文章的开篇,我们提到,比特币的隐私和抗审查特性,都来自于网络的去中心化。用户运行自己的节点的习惯,减少了单点故障、监视和审查。这又来自于比特币节点软件的首要设计目标:运行节点是非常轻松的。如果每个比特币用户都需要购买昂贵的硬件、使用特定的操作系统、每个月支出数百美元的运营成本,那网络中的节点数量可能会大大减少。

此外,比特币网络中的节点就是一台计算机,它使用互联网跟陌生人的节点相互连接;这些陌生人可能会对这个节点发送 “拒绝服务式(DoS)” 攻击:发送会导致这个节点耗尽内存然后宕机的消息、使用无意义的数据耗费这个节点的运算资源和贷款从而使之不能接收新区块。因为这些陌生人都是匿名的(系统本身就是这样设计的),节点无法在连接之前预先断定哪个对等节点是诚实的、恶意的;而且在观察到攻击之后也无法有效地绝交。所以,实现保护节点免受 DoS 攻击的交易池规则,不仅是一种理想,更是一种现实需要。

节点实现中内置了通用的 DoS 保护措施,以防止资源耗尽。举例来说,如果一个 Bitcoin Core 节点从单个对等节点处收到许多消息,那么它会仅处理第一条收到的消息、将其余的消息放到一个待处理队列中,等其他对等节点的消息到达之后再处理。类似地,节点一般会先下载一个区块头,待验证完这个区块头的 “工作量证明(PoW)” 之后,才下载和验证完整的区块。因此,任何希望通过区块转发来耗尽这个节点的资源的攻击者,都必须先花费不成比例的大量资源计算出一个有效的 PoW ,然后才能施行攻击。PoW 的高昂计算成本和微不足道的验证成本,提供了一种应对区块转发 DoS 的天然方法。但这种特性无法延伸到 未确认的 交易的转发中。

通用的 DoS 保护措施并不能提供足够多的抗性,让一个节点的共识引擎可以放心地暴露在点对点网络中接收输入。攻击者可以尝试制作一个计算任务极为繁重、但在共识上有效的交易,就像区块 #364292 处出现的这笔 1MB 的 “巨型交易” 一样,因为签名验证中的哈希运算量呈平方级膨胀的问题,它需要反常的长时间来验证。攻击者也可以制作一个只有最后一个签名无效的交易,让节点在这笔交易的验证上花费大量的时间,直到最后才发现它是个垃圾。在这样浪费时间的时候,节点会推迟处理新的区块。你可以想象,某个矿工可以针对自己的对手发起这样的攻击,从而在下一个区块的挖掘中获得 “起跑优势”。

为避免处理计算量非常繁重的交易,Bitcoin Core 节点为每一笔交易施加了一个体积限制和签名操作(“sigop”)数量限制,这个限制比共识规则在区块层面实施的限制更为严格。Bitcoin Core 节点也对祖先交易包和后代交易包的体积施加限制、让区块模板的生产和驱逐算法更加高效,同时还会约束交易池插入和删除操作的计算复杂度(更新一笔交易的祖先和后代集合就涉及这样的操作)。虽然这意味着一些合法的交易可能不会被接受和转发,但预计这样的交易是罕见的。

这些规则都是 “交易转发规则” 的案例 —— 节点在共识规则要求之上,对未确认的交易施加的额外验证规则。

默认情况下,Bitcoin Core 节点不会接受手续费率低于 1 聪/vb 的交易(“minrelaytxfee”),也不会在检查完这个要求之前验证任何签名,也不会在交易池接受一笔交易之前转发这笔交易。从某种意义上说,这个手续费率的规则,是在为网络验证和转发的工作设置一个 “价格” 的下限。不挖矿的节点不能收到手续费 —— 交易只会给确认它的矿工支付手续费。但是,手续费代表了攻击者的成本。如果有人要通过发送大量的交易来 “浪费” 网络的资源,那么 TA 最终将因为手续费而耗尽资金。

Bitcoin Core 所实现的手续费替换(Replace by Fee)” 规则要求替换交易支付比跟它直接冲突的任一笔交易更高的手续费率,同时还要求它所支付的手续费总额也要比任一笔竞争交易更高。而且,额外支付的手续费除以替代交易的虚拟体积,必须至少是 1 聪/vb 。换句话说,无论原版交易和替代交易的手续费率的绝对水平如何,新交易都必须为自身所耗费的网络带宽支付至少 1 聪/vb 的 “新” 手续费。这个手续费规则的首要顾虑不是激励兼容性。相反,它是为重复的交易替换施加一个成本下限,以阻止浪费带宽的攻击,比如,每笔替换交易只多付 1 聪手续费的攻击。

完全验证区块和交易的节点,需要包括内存、运算力、网络带宽在内的资源。我们必须保证资源要求处于较低水平,从而让节点容易运行,并保护节点免受轰炸。通用的 DoS 保护措施是不够的,所以节点需要在验证未确认交易时,在共识规则之上应用交易转发规则。但是,因为这样的规则不是共识的一部分,两个节点可能会使用完全不同的规则,但依然能对链的最新状态达成共识。下周,我们会讨论作为个人选择的交易池规则。

规则一致性

最早出版于Newsletter #256

上周的文章介绍了 “规则(policy)”,这是一组在共识规则之外应用的交易验证规则。这些规则不适用于已入块的交易,因此即使节点的规则与其对等节点不同,它仍然可以保持一致性。就像节点操作员可以决定不参与交易中继一样,他们也可以自由选择任何规则,甚至不选择任何规则(将其节点暴露于 DoS 风险之下)。这意味着我们不能假设整个网络的交易池规则完全相同。然而,为了让用户的交易被矿工接收,愿意接纳这笔交易到自己的交易池的节点必须形成一条通向矿工的路径——节点之间的规则差异直接影响交易中继功能。

作为节点规则差异的极端例子,想象一种情况,每个节点操作员选择一个随机的nVersion,并仅接受具有该nVersion的交易。由于大多数点对点关系具有不兼容的规则,交易将无法传播到矿工。

另一方面,网络中相同的规则有助于聚合交易池的内容。具有一致交易池的网络可以最顺畅地中继交易,并且也非常适合费用估算致密区块中继,正如之前的帖子中所提到的。

考虑到交易池验证的复杂性和规则不一致带来的困难,Bitcoin Core 在规则可配置性方面一直保守。虽然用户可以轻松地调整 sigops 计数的方式(bytespersigop)以及嵌入在OP_RETURN输出中的数据量限制(datacarriersizedatacarrier),但他们不能选择违背 400,000 个重量单位的最大标准重量,也不能应用别的一套与手续费相关的 RBF 规则,除非改变源代码。

Bitcoin Core 的一些规则配置选项存在是为了适应节点操作环境和运行节点的目的的差异。例如,矿工的硬件资源和保持交易池的目的与日常用户在笔记本电脑或树莓派上运行轻量级节点的目的不同。矿工可以选择增加他们的交易池容量(maxmempool)或过期时间线(mempoolexpiry)以在高峰期存储低费率交易,然后在流量减少时进行挖掘。提供可视化、存档和网络统计的网站可能运行多个节点,以收集尽可能多的数据,并显示默认的交易池行为。

在单个节点上,交易池容量的选择会影响费用提升工具的可用性。当交易池最低费率因交易提交超过默认交易池大小而上升时,从交易池的“底部”清除的交易和低于此费率的新交易不能再使用 CPFP进行 费用提升。

另一方面,由于被清除的交易所用的输入不再为交易池中的任何交易所用,此前无法进行的 RBF 手续费追加也许又变成可能了。新交易实际上并没有替换这个节点的交易池中的任何内容,因此不需要考虑通常的 RBF 规则。但是,(因为具有更大的交易池容量而)没有逐出原版交易的节点将新交易视为拟议的替换,并要求其遵守 RBF 规则。如果被清除的交易没有发出 BIP125 可替换信号,或者新交易的费用即使费率很高但不符合 RBF 要求,矿工可能收不到他们的新交易。钱包必须小心处理被清除的交易:交易的输出不能被视为可以花费,但输入同样不能被重复使用。

乍一看,具有更大的交易池容量的节点似乎使 CPFP 更有用、使 RBF 更无用。然而,交易中继受紧急的网络行为的影响,可能不存在接受用户 CPFP 并将其转发到矿工的节点路径。节点通常只在接受交易并将其放入交易池后转发一次,并忽略已存在于其交易池中的交易的通知——存储更多交易的节点在这些交易被重新广播到它们时充当黑洞。除非整个网络增加其交易池容量(这将是更改默认值的迹象),否则用户不应该指望从增加自己的交易池容量中获得太多好处。交易池默认设置的最低费率限制了在高流量时使用 CPFP 的效用。成功地将 CPFP 交易提交到自己增大了的交易池的用户可能无法注意到该交易未传播给其他人。

交易中继网络由动态加入和离开网络的个体节点组成,每个节点必须保护自己不被爆破。因此,交易中继只能尽力而为,我们不能保证每个节点都了解每个未确认的交易。同时,如果节点收敛在一组使得交易池尽可能同质化的中继规则上,那么比特币网络的表现就会最佳。下一篇文章将探讨采取了哪些规则来符合整个网络的利益。

网络资源

最早出版于Newsletter #257

前一篇文章讨论了保护节点资源的问题。由于各个节点的资源不同,因此有些规则是可配置的。我们还提出了为什么最好统一规则的理由,但是哪些内容应该包含在这个规则里呢?本文将讨论网络范围的资源概念,这对于可扩展性、可升级性、启动和维护全节点的可访问性等方面至关重要。

正如在之前的文章中讨论的那样,比特币网络的许多意识形态目标体现在其分布式结构中。比特币的点对点性质允许网络规则从各个节点运营者所选择的粗略共识中产生,同时抑制在网络中获取不当影响力的企图。然后这些规则由每个节点通过对每个交易进行独立验证来强制执行。一个多样化和健康的节点群体需要保持节点运营成本低廉。不论什么项目,扩展到全球规模都很困难;如果还不想牺牲去中心化,就如同反绑一只手跟人打架。比特币项目通过严格保护其共享的网络资源(UTXO 集、区块链的数据足迹、处理数据所需的计算工作量,以及演化比特币协议的升级钩子)来尝试实现这种平衡。

我们无需重述整个区块体积战争来认识到限制区块链增长是必要的、我们以此来保证个人运行得起自己的节点。但是,区块链的增长在交易池规则层面上也会得到抑制:minRelayTxFee 的值为 1 sat/vbyte,表示了“对超多副本的永久存储的无限需求”的最低成本。

最初,网络状态是通过保留所有仍有未花费输出的交易来跟踪的。随着 UTXO 集作为跟踪资金的手段引入,区块链的这一部分大大减少了。自那时以来,UTXO 集一直是一个核心数据结构。普遍情况下,UTXO 查找占据了节点所有内存访问的主要部分(在初始化区块下载(IBD)期间尤其如此)。Bitcoin Core 已经使用了一个手动优化的 UTXO 缓存的数据结构,但 UTXO 集的大小也决定了集合中有多少交易无法进入节点的缓存。较大的 UTXO 集意味着更多的缓存未命中,这会降低区块验证、IBD 和交易验证的速度。粉尘限制是一种限制 UTXO 创建的策略,特别是限制那些可能永远不会被花费的 UTXO,因为它们的金额不足以支付它们的成本。即便如此,规模达数千笔交易的“粉尘风暴”近在 2020 年仍发生过

当使用裸多签输出将数据发布到区块链上变得流行起来时,标准交易的定义被修改,允许使用单个 OP_RETURN 输出作为替代方案。人们意识到,无法阻止用户在区块链上发布数据,但至少这些数据不需要永远存在于 UTXO 集中。Bitcoin Core 0.13.0 引入了一个启动选项 -permitbaremultisig,用户可以切换以拒绝带有裸多签输出的未确认交易。

尽管共识规则允许自由格式的输出脚本,但 Bitcoin Core 节点只会中继少数一些被较好理解了的模式。这样更容易推理网络中的许多问题,包括验证成本和协议升级机制等。例如,输入脚本中包含了操作码、P2SH输入中的签名超过 15 个、P2WSH 输入的见证堆栈超过 100 个项,任何一个都将使该交易成为非标准交易(请查看此交易池规则概述以获取更多规则示例及其动机)。

最后,比特币协议是一个不断发展的软件项目,需要不断演进以应对未来的挑战和用户需求。为此,有一些升级钩子被故意保留为共识有效但未使用,例如附录、taproot 叶子版本、见证版本、OP_SUCCESS 以及一些 no-op 操作码。然而,就像因为没有单点故障而阻碍了攻击一样,网络范围下的软件升级要涉及到协调数以万计的独立节点运营者。在其含义被明确定义前,节点不会转发使用了保留的升级钩子的交易。这种阻碍旨在防止应用程序各自独立地创建相互冲突的标准。这种冲突使得共识无法在采用一个应用程序的标准的同时避免另一个标准无效。 此外,当共识真的发生变更时,没有立即升级的节点(因此不了解新的共识规则)无法“被骗”去接受一个现在无效的交易进入他们的交易池中。这种主动阻碍方式可以帮助节点具备向前兼容性,并使网络能够安全升级共识规则而不需要完全同步地进行软件升级。

我们可以看到,使用交易池规则来保护共享网络资源有助于保护网络的特性,并使未来协议的开发路径保持开放。与此同时,我们正在看到,如何在严格限制区块重量的情况下来扩展网络的矛盾正在推动着最佳实践、良好的技术设计和创新的采用:下周的文章将探讨交易池规则作为二层协议和智能合约系统的接口。

交易池规则是个接口

最早出版于Newsletter #258

到目前为止,我们已经探讨了关于去中心交易转发的目的和挑战,这些因素使得节点本地整个网络都要使用比共识规则更严格的交易验证规则。因为 Bitcoin Core 软件的交易转发规则变更可能影响一个应用的交易是否能被转发,所以在提出之前,需要整个比特币社区的社会合作。类似地,使用了交易转发的应用和二层协议也必须跟交易池规则一起设计,以避免创建会被拒绝的交易。

合约式协议甚至更密切地依赖于跟打包优先级相关的交易池规则,因为其强制执行能力依赖于能够让交易快速得到确认。在对抗环境中,通过推迟交易的确认欺骗对手可能会有利可图,所以我们必须思考交易转发规则(作为一种接口)的 “怪癖” 如何可以用来攻击用户。

闪电网络的交易遵循前面的文章提到的标准化规则。举例来说,这种点对点协议在其 open_chennel 消息中指定了一个 dust_limit_satoshis 参数,用来明确粉尘输出的门槛。因为一笔包含了价值低于粉尘门槛的输出的交易不会被转发(因为节点的粉尘输出限制),这些支付会被认为是 “不可在链上强制执行的”,然后从承诺交易中剔除。

合约式协议经常使用带有时间锁的花费路径,让每一个参与者都有机会竞争将状态发布到链上。如果受影响的用户没有办法在这个时间窗口内让自己的交易得到确认,他们就有可能损失资金。这让手续费变得极为重要,因为它是提高确认优先级的首要机制,但也产生了更多难点。交易需要在未来的某个时候广播,或者受影响的用户只拥有轻节点,或者一些追加手续费的方法不可用,都导致费率估计很难。比如说,如果闪电通道的一个参与者离线了,另一方可能会单方面广播一笔预签名的承诺交易,来结算他们在链上共享的资金。没有任何一方可以独自花费他们共享的 UTXO,所以当其中一方离线的时候,就无法签名一笔替换交易来为承诺交易追加手续费。反过来,闪电通道的承诺交易可能会为通道参与者包含 “锚点输出”,让他们可以在广播交易的时候附上用于追加手续费的子交易

但是,这些手续费追加方法都有局限性。如之前的文章文章所述,如果交易池的最低手续费率已经比承诺交易的手续费率要高,那么添加一个子交易是不会奏效的,所以闪电通道的用户依然必须使用稍微高估的费率来签名交易,以应对未来交易池的最低费率上涨的情形。此外,锚点输出的开发综合了一系列的考量,因为某一方可能从推迟交易确认中获利。举个例子,一方(Alice)可能会在离线之前广播自己的承诺交易。如果这笔承诺交易的费率太低、无法立即得到确认,而且 Alice 的对手(Bob)没有看到这笔交易,那么,他可能会很困惑 —— 当他想把自己的承诺交易广播出去的时候,会发现自己这笔交易无法转发。每一笔承诺交易都有两个锚点输出,所以任何一方都可以加速任意版本的承诺交易的确认,例如,Bob 可以盲目地尝试广播一笔基于 Alice 版本的承诺交易的 CPFP 子交易,即使他不确定 Alice 之前有没有广播过这个版本。每一个锚点输出都带有高于粉尘门槛的价值,而且在一段时间后就可被任何人领走,从而避免让 UTXO 集膨胀。

但是,保证每一方的 CPFP 能力,光凭给每一方一个锚点输出可不够。如之前的文章所述,Bitcoin Core 会限制可以附加到一笔未确认交易上的后代交易的数量和总体积,这是一种 DoS 保护措施。因为每一方都可以为共享的一笔交易附加后代,那么,其中一方就可以阻止别人的 CPFP 交易得到转发 —— TA 可以用自己的 CPFP 交易用尽这个可附加的容量。结果是,这些后代交易会让承诺交易以低优先级的状态 “钉死” 在交易池中。

为了缓解这种可能的攻击,闪电网络的锚点输出提议使用一个相对时间锁锁定了所有的非锚点输出,从而阻止它们在承诺交易未得确认的时候就被花费,而且 Bitcoin Core 的后代限制规则也修改了,允许附加额外的一个子交易,条件是这笔交易的体积较小而且没有其它祖先交易。这些变更的组合保证了一笔共享交易的两个参与者都可以在交易广播的时候调整交易费率,同时不会显著增加交易转发的 DoS 攻击界面。

通过耗尽后代交易的容量来阻止 CPFP,是 “钉死攻击” 的一个例子。钉死攻击利用交易池规则的限制来阻止激励兼容的交易进入交易池以及得到确认。在这个案例中,交易池的规则在 DoS 抗性激励兼容性之间做了取舍。你必须取舍 —— 节点需要考虑追加手续费的机制,但无法处理无限数量的交易。CPFP 的 carve out 为一个具体的应用场景细化了这种取舍。

除了耗尽后代交易的容量限制,还有别的钉死攻击可以同时阻止 RBF 的使用、或让 RBF 贵得离谱、或者利用 RBF 来推迟一笔 ANYONECANPAY 交易的确认。钉死攻击仅在多方合作创建一笔交易的时候,或者一个不受信任的参与者可以干预交易的时候是个问题。尽量不将交易暴露给不受信任的参与者,总的来说是一种避免钉死的好方法。

这些摩擦点不仅显示了交易池作为比特币生态系统中的应用和协议的接口的重要性,还指明了需要提升的地方。下周,我们会讨论交易池规则的变更提议以及悬而未决的问题。

规则提案

最早出版于Newsletter #259

上周的文章介绍了锚点输出CPFP 分拆,以确保通道双方任意一方都可以在不需要协作的情况下为他们共同的承诺交易追加手续费。这种方法仍然有一些不足之处:通道资金被绑定以创建锚点输出;承诺交易费率通常高于交易池最低费率以确保其能够被尽快打包。而且,CPFP 分拆只允许一个额外的后代。锚点输出也不能为三方或更多方共享的交易如 coinjoins 或多方合作协议提供相同的手续费提升能力。本篇文章探讨了目前为解决这些和其他限制所做的努力。

包中继包括点对点协议和规则变更,以使得交易组的传输和验证得以实现。这将允许承诺交易即使未达到交易池的最低费率,也可通过子交易进行费用提升。此外,包 RBF 可让追加手续费的子交易替换掉与其父交易发生冲突的交易。包中继旨在消除基础协议层的一般限制。然而,由于它在共享交易费用提高方面的实用性,它也催生了一些旨在消除特定情况下交易钉死攻击的尝试和努力。例如,包 RBF 允许承诺交易在广播其各自的费用提升子交易时互相替换,从而消除了每个承诺交易上需要多个锚点输出的需要。

需要注意的是,现有的 RBF 规则要求替换交易支付的绝对费用高于所有待替换交易支付的累计费用。此规则有助于防止通过重复替换来发起的 DoS,但允许恶意用户通过附加高费用但低费率的子交易来增加替换其交易的成本。这种通过阻止善意用户发起高手续费率的替代交易包、从而阻碍交易被挖出的不公平情形,通常被称为,“针对规则 3 的交易钉死”。

开发人员还提出了完全不同的给预签名交易增加费用的方式。例如,使用 SIGHASH_ANYONECANPAY | SIGHASH_ALL 签署交易输入,可以允许交易广播者通过在交易中附加额外的输入(而不改变输出)来提供费用。然而,由于 RBF 没有任何规则要求替代交易具有更高的“挖矿分数”(即会更快地入选一个区块),攻击者可以通过创建来自低手续费率祖先交易的替换交易,来钉死这些类型的交易。难以准确评估交易和交易包“挖矿分数”的原因在于,现有的祖先和后代限制不能限定该计算的计算复杂性。任何关联的交易都会影响交易被挑选到区块中的顺序。一个完全连接的组合(称为_集群_)可以是给定的当前祖先和后代限制的任何大小。

解决一些交易池不足和 RBF 钉死攻击的长期解决方案是重构交易池数据结构,以跟踪集群而不仅仅是祖先和子孙集合。这些集群的大小将受到限制。限制集群的大小会限制用户使用未确认的UTXO的方式,但可以使用基于祖先分数的挖矿算法快速线性化整个交易池,极快地构建区块模板,并添加条件:要求替换交易需要具有比待替换交易更高的挖矿分数。

即便如此,可能没有一套规则能够满足交易中继的广泛需求和期望。例如,尽管批量付款交易的收款方受益于能够花费未确认的输出,但相对宽松的后代限制会给共享交易的绝对费用留下包 RBF 钉死攻击的空间。为此,针对v3 交易中继规则的一个提议被制定出来,以允许合约协议选择更严格的一套包限制要求。V3交易仅允许大小为二的包(父级与子级),并限制子交易的重量。这些限制将减轻通过绝对费用钉死 RBF 的攻击,并为集群交易池提供一些好处,而无需重构交易池。

临时锚点建立在v3交易和数据包中继属性之上,以进一步改进锚点输出。它使得零费用v3交易所属的锚点输出免于粉尘限制,但前提是该锚点输出被费用提升的子级花费。由于零费用交易必须由一个子交易进行费用提升(否则矿工不会被激励将其包含在区块中),因此此锚点输出是“临时的”,不会成为 UTXO 集的一部分。临时锚点提案隐含地阻止了在未确认时花费非锚点输出,而不需要设立 1 OP_CSV 时间锁,因为唯一允许的子级必须花费锚点输出。这也使得使用 CPFP 作为通道关闭交易的费用提供机制的 LN symmetry 协议成为可能。它还使得这种机制可用于多于两个参与者共享的交易。开发者一直在 signet 上使用 bitcoin-inquisition 来部署临时锚点以及各种软分叉提议,以构建和测试这些多层次的变化。

在本文中提到的钉死问题,以及其他问题,在去年引起了许多讨论和关于改进 RBF 规则的建议,这些讨论和建议的平台包括邮件列表、PR、社交媒体和面对面会议。开发人员提出并实施了各种解决方案,从小的修改到完全改版的方案都有。-mempoolfullrbf 选项旨在解决钉死问题和 BIP125 实现中的差异,突显了交易中继规则中合作的重要性和困难。虽然已经做出了真正的努力并使用了常规的方式让社区参与进来,包括提前一年开始 bitcoin-dev mailing 对话,但很明显,现有的沟通和决策方法并没有产生预期的结果,需要改进。

去中心化的决策过程具有挑战性,但是它对于支持使用比特币交易中继网络的协议和应用程序的多样化生态系统来说是必要的。下周将是我们系列文章的最后一篇,我们希望鼓励我们的读者参与并改进这个过程。

参与其中

最早出版于Newsletter #260

我们希望这个系列可以让读者更好地了解在等待确认时发生了什么。我们从讨论比特币的一些意识形态价值开始,将其转化为比特币的结构和设计目标。对等网络的分布式结构提供了比典型的集中式模型更高的抗审查性和隐私保护。一个开放的交易中继网络有助于每个人知晓即将进入区块的交易。这提高了区块中继的效率,使得作为一个新矿工加入比特币网络更可行,同时也创造了一个对区块空间的公开拍卖。作为一个由许多独立的、匿名的实体运行节点组成的理想网络,节点软件必须被设计成可防 DoS 攻击并尽量减少运营成本。

手续费在比特币网络中扮演着重要的角色,作为解决区块空间竞争的“公平”方式。在交易池中,允许交易替换、可以感知交易包的选择和驱逐算法,使用激励兼容性来衡量存储一个交易的效用,并为用户启用 RBFCPFP 作为追加手续费的机制。这些交易池策略的组合、能经济地构造交易的钱包和良好的费率估计,可以为区块空间创造一个高效的市场,从而使每个人受益。

个别节点还会执行 交易中继策略,以保护自己避免资源耗尽表达个人偏好。在网络范围内,标准规则和其他策略保护着可扩展性、节点运行的可访问性以及更新共识规则的能力等至关重要的资源。由于网络中的绝大多数都遵守这些策略,它们是比特币应用程序和 L2 协议所依赖的接口的重要组成部分。然而,它们并不完美。我们描述了几个与交易池策略相关的提案,这些提案致力于解决广泛的局限性以及特定用例,比如对 L2 结算交易的钉死攻击

我们还强调,网络策略的持续演进需要协议、应用和钱包开发者之间的合作。随着比特币生态系统在软件、使用案例和用户方面的增长,去中心化的决策过程变得更加必要,但也更具挑战性。即使比特币的采用率增长,系统也是由利益相关者的关注和努力而形成的——没有一家公司负责收集客户反馈并雇佣工程师来构建新的协议功能或删除未使用的功能。对希望成为网络的粗略共识的一部分的利益相关者而言,有多种参与途径:自主了解情况、提出疑问和问题、参与网络设计,甚至贡献改进的实现。下次当你的交易确认时间过长时,就知道该怎么做了!