V3交易是一种新的交易池策略,结合了交易包转发、一次性锚点和新的交易池接纳规则,旨在优化锚点通道和锚点输出。它们使用CPFP、锚点输出和交易包转发作为支付手续费的主要方法,但可能导致挖矿中心化。建议将交易包转发添加到Bitcoin Core中,避免使用协议外的手续费支付。闪电网络已经推出了锚点通道,应立即受益于CPFP。V3交易目前没有令人信服的应用场景,不应被推出。
“V3 交易” 是一组提议中的交易池策略(mempool policies)集,旨在允许合约式协议(例如闪电通道)中的交易使用 “子为父偿(CPFP)”、锚点输出和交易包转发作为支付手续费的首要方法。在本文中,我们会了解对 V3 交易以及锚点输出的期待是什么样的,以及它们在闪电通道这样的协议中的作用。最终我们会看到,它们对 CPFP 的依赖,使得它们在区块空间(以及手续费)上昂贵得多,相比于 “手续费替换(RBF)” 技术,在绝大多数情况下都将强制关闭通道的成本提高了大约 2 倍。我们也会解释何以 V3 交易形式会成为对挖矿中心化的一个潜在威胁,因为协议外(out-of-band)的手续费支付手段可能会比锚点交易便宜很多。
感谢 Fulgur Ventures 资助这项研究。他们对本文的内容无任何编辑权限,也未在出版之前审核。
闪电通道以及类似的协议依赖于交换预先签名的交易来工作,除非出现了意外,这些交易本无意于被挖出。意外,就是指参与者之间不能达成一致意见的时候。在这些意外情形中 —— 比如,通道的某一方下线了 —— 资金会通过签名并广播必要的交易来复原。举个例子,在典型的、没有待处理的 HTLC 的情况下,一条通道的两方都拥有一笔对应着这个通道最新状态的承诺交易,它花费持有通道资金的 2-of-2 多签名输出,将资金发回给各方控制的公钥。
问题在于,为得到区块确认而需支付的手续费率是经常变化的,而且会大幅变化。其次,Bitcoin Core 当前要求交易的手续费率必须在某个门槛之上,才能被本地节点的交易池接纳。这个手续费率门槛也会随着网络的确认需求而变化,因为节点的交易池的容量上限是固定的。
虽然闪电协议有一种让参与者能供协商预签名交易的手续费率的机制,但这种机制也无法预测未来。因此,经常出现这样的情况:预签名交易的手续费要么太低,因此无法被及时确认;要么太高,因此浪费了一些资金。
在特定情况下,网络确认需求的意外增加甚至会让通道状态的解决变得不可能,因为进入交易池的手续费门槛已经高于预签名交易的手续费率。这在还有 HTLC 待处理的时候是尤其有害的,因为 HTLC 可能具备严格的时间窗口,如果不能在窗口期结束之前处理,应该得到资金的人就可能遭受损失。
闪电通道已经实现了一部分的解决方案,就是 “锚点通道”。锚点通道使用了两项关键的技术:
在锚点通道中,承诺交易加入了两个面额为粉尘门槛的锚点输入,目的是允许 本地 以及/或者 远端 的参与者使用 CPFP 来提高承诺交易的实质手续费,在双方所选的手续费太低、无法在合理时间内被挖出时,能够提高交易的确认优先级。
两个锚点输出的脚本都是这样的形式:
你可能会好奇,为什么这样本质上没有价值的输出,要使用 OP_CHECKSIG(检查签名) 操作码。为什么不使用一种裸露的、最小化的 OP_TRUE 输出? 不管怎么说,如果别人花费这个输出,不也意味着是在支付手续费、加速我们的承诺交易被挖出吗?
因为,不幸的是,我们必须处理 “交易钉死攻击”:它会让 RBF 手续费追加法变得极为昂贵,甚至完全不可行。基本上,如果这个输出只是一个 OP_TRUE,那么一个攻击者可以广播一笔交易、花费这个 OP_TRUE 锚点输出,使得我们使用 RBF 来追加手续费变得昂贵,甚至完全不可行,因此这笔承诺交易也难以在合理时间内得到确认。
因此, OP_CHECK 保证了只有实际参与这条通道的各方才能花费锚点输出,从而阻止任何钉死攻击。这同样是设置两个锚点输出的原因:我们不希望一方能对另一方发动钉死攻击。
实际上,两个锚点输出是冗余的: to_remote 输出就可以作为 to_remote_anchor 输出,这是我在撰写本文时发现的。只需一个锚点输出就够了。
当前,Bitcoin Core 会孤立地判定是否要将一笔交易纳入本地交易池 —— 不考虑该交易的任何子交易。因此,即使有了锚点通道,承诺交易依然有可能因为网络手续费率上涨得太多而无法进入任何一个交易池(因为交易池的容量都是有限制的)。这是用,锚点输出就无法使用 CPFP 机制了,因为父交易根本就无法进入交易池,因此无从开始。
“交易包转发” 机制旨在通过评估交易 包(将相互关联的多笔交易作为一个整体)来解决这个问题。有了交易包转发,即使零费率的父交易也可以进入交易池,只要这个交易包包含了(通过 CPFP)为父交易支付手续费的子交易。
如果交易包转发能够实现,锚点通道就能在所有环境下使用了。相比于 RBF,它们依然不够高效 —— 我们下文会讨论到 —— 但至少是能够工作、不必顾虑交易池的条件的。
“V3 交易” 提议结合了交易包转发、一次性锚点以及新的交易池接纳规则,以尝试优化锚点通道和锚点输出。值得注意的是,“V3 交易” 中的 “V3” 指的是一种新的、非共识层面的 nVersion 数值 3, 矿工和节点被期望会 利他主义 地区别对待它,从而防止 V3 交易的输出被某一些方式花费掉。
因此,V3 交易提议有三个部分:
我使用 “非共识限制” 的意思是,实际上的区块有效性规则并没有被改变。相反,仅仅是 Bitcoin Core 将拒绝尝试花费 V3 交易输出的交易 —— 即使它们是有效的,并且对矿工来说有利可图 —— 只要这些交易没有满足特定的要求,其中主要的一条是:花费未确认的 V3 输出的交易的重量必须小于 1000vB,否则就会被拒绝。这种限制阻止了重大的交易钉死攻击,反过来使得锚点输出可以是简单的、任何人都可以花费的 OP_TRUE。因为花费这个输出的交易无法被钉死,如果第三方尝试以低费率交易花费这个输出,任何人都可以直接用更高费率的交易替换掉第三方的交易。
至少,想法上是这样的。不幸的是,因为 1000vB 的限制依然显著大于标准的承诺交易以及一次性锚点的花费交易,攻击者依然可以对第三方进行便宜而有效的钉死攻击。具体有多便宜、有多高效,取决于交易池内的环境。但一个攻击攻击者只需花费少许资金(甚至不需要花费资金)就可以让受害者为一次强制关闭通道的操作支付大约 1.5 倍的手续费,最高甚至可达约 3.7 倍。
对相同问题的一个显然的解决方案是,直接预签名不同费率的承诺交易。虽然乍看起来这是低效的,但计算机很快,带宽也便宜:secp256k1 曲线上的一次(MuSig2)签名操作的计算时间仅在 100us
(100 微秒)级别(一个公钥)2 3,然后生成一个 64 字节的签名。因为交易的变体可以确定性地生成,因此只需要传递用于确定性生成的参数,以及签名本身。并不需要传输完整的交易。而且闪电网络已经在使用这种技术了:交易的确切形式是由闪电网络规范确定的。
那么需要多少个挡位的手续费呢?根据 mempool.space 的数据,在过去的六年中,进入下一个区块所需的手续费率从 1sat/vB
到 500sat/vB 不等。
如果我们的手续费范围是从 a 到 b,而递进的比例是 r,我们很容易算出需要几次递进:
举个例子,如果你希望覆盖 10sat/vB 到 1000sat/vB 的费率,递进的比例是 10 %,那么只需要 50 个挡位,(需要传输的的)总体积是 3200 字节,只需要 5ms(5 毫秒)来签名(单核计算机)。给定闪电通道的非常好的可扩展性,这个开销是合理的。
更新:事实证明,AICNQ 的 Phoenix 钱包最近已经为通道实现了部分的 RBF,在底层的 lightning-kmq 库中。
现有的闪电通道实际上需要 两笔 承诺交易,remote(“对方”)承诺交易和 local(“己方”)承诺交易,因为双方手上的承诺交易有些许区别;上述手续费挡位的计算指的是每一方需要准备的数量,不是总数量。每一笔承诺交易都要由对方签名,这就引入了为不同参与者分配手续费的能力。在绝大部分情况下,让广播承诺交易的一方支付手续费是合理的;因此,每一方都签名交易、给予对方用 自己 的钱来充当手续费的能力,在他们愿意的时候,就可以补上自己的签名 并广播交易。
只要手续费是由选择广播承诺交易的一方来支付的,最高手续费率就可以是该方在通道中的全部余额;这样一方也将不能通过广播高手续费的承诺交易来骚扰另一方,因为他们只能广播用 自己 的钱来支付手续费的承诺交易。这种机制有个好处:不会陷入某一方没有足够的手续费的情形中。如果让一笔承诺交易被挖出需要支付己方在该通道中的全部余额,那么己方尝试让这笔交易挖出是没有意义的。可以等待手续费率下降,或者直接放弃通道中的资金。
闪电承诺交易的 HTLC 输出只能被预签名的 HTLC-超时 或者 HTLC-成功 交易花费。之所以需要这些专门的交易,是因为一方可能广播已经撤销的承诺交易然后创建出 HTLC 输出,而我们需要让另一方有机会使用撤销公钥。在锚点通道中,这些 HTLC 是使用 SIGHASH_SINGLE|SIGHASH_ANYONECANPAY 签名的,所以任何人都能够通过添加额外的输入和输出来为这些交易追加手续费。
因为可以加入额外的输入和输出, 所以转发费率门槛 不是 一个问题:我们总是可以添加足够大的 输入/输出 来够上这个门槛。因此使用 RBF 承诺交易的一种办法是直接为每一种手续费挡位预签名(一笔) HTLC 超时/成功 交易,然后继续使用这种 “添加一个输出” 的机制。这会让我们需要为每一个 HTLC 做的工作乘以 N,但这里也一样,因为这些交易是确定性地制作出来的,所以很便宜,也很容易验证。
为同一个 HTLC 超时/成功 操作签名多个手续费挡位的交易也是可以做到的。虽然在最糟糕的情况下,总工作量会变成 N的2次方 级别。但只要我们意识到,通常来说,HTLC 交易通常需要接近于对应那笔承诺交易的手续费,就可以节省下来。注意,这也说明了为什么对于 Phoenix 这样的终端用户钱包来说,手续费挡位是更好的选项 —— 终端用户钱包希望每个用户只有一个 UTXO,所以不会有额外的 UTXO 能够用来为 HTLC 输出追加手续费。
最后,SIGHASH_ANYPREVOUT 可以解决这个 N的2次方 复杂度问题,因为它可以让任意的 HTLC 交易变体都能花费任何承诺交易的变体。
混合两者的方法也是可行的。让多笔变体交易只负责一部分的手续费范围,然后让一笔携带了锚点输出的变体负责最高的手续费。
RBF 要比锚点输出高效得多,因为它只需要一笔交易。一笔标准的、使用 V3 形式的闪电通道承诺交易是 163vB,然后需要一笔体积为 152vB 的一次性输出交易来支付手续费,总计 315vB。
因为使用 RBF 的承诺交易不需要锚点输出,所以体积只有 154vB,而且不需要第二笔交易。V3 交易在体积上 至少 是两倍,因此手续费也将会是两倍。
但 V3 其实比这还要差:V3 交易需要保留额外的、纯粹只是为追加手续费而需保留的输出。管理这些额外的输出对许多闪电节点来说都是困难而且昂贵的,尤其是更小的 节点/钱包。很难确定要为这些输出分配多大比例的资金,而且,显然,需要消耗区块空间来创建它们。
绝大多数对比特币的究极扩展容量的分析都忽略了这一点:使用锚点输出,每一个闪电网络的用户都至少需要创建 两个 UTXO,而不是一个输出,从而将闪电网络可能容纳的全球用户总量砍半。
这个问题的一个特别糟糕的例子可以在面向用户的钱包(比如 Phoenix 7)上看到:Phoenix 希望让一个用户的所有资金都放在一条闪电通道中,而使用通道拼接技术来加入和取出链上资金。
像 RGB 闪电通道和 LND 的 Taproot Assets 这样的协议旨在让非比特币的协议也能利用闪电通道形式的通道,但可能被迫绑定更多的 BTC 以使用 RBF 技术,因为双方尝试交易的资产并不能直接用来支付手续费。对于大体量的通道来说,这可能不是一个问题,因为手续费的 BTC 价值相对于通道的价值来说是小的。但更小的通道可能需要使用其它技术。
举个例子,SIGHASH_ANYPREVOUT 让承诺交易可以用 SIGHASH_ANYONECANPAY 来签名,从而可以在有需要的时候通过添加额外的输入来使用 RBF 手续费追加。当然,这可能会引入一些问题,比如说交易钉死攻击。
感谢 Brandon Black 指出这个问题。
因为锚点输出比 RBF 要低效得多 —— 代价大约是 2 倍 —— 它带来了显著的挖矿中心化威胁,因为用户可能尝试使用协议外(out-of-band)的手续费支付手段。问题在于,如果你拥有使用锚点输出的交易,你需要确认它,使用这个机制(锚点输出)来挖出交易,比起让矿工挖出目标交易而不花费锚点输出,要消耗大概是两倍的区块空间。
一些大矿工已经接受了协议外的支付手段,允许你通过直接支付给他们来让你的交易被挖出;仅有 大体量的矿工可以合理地提供这项服务,因为只有大矿工才能足够频繁地找出区块,来让这种协议外的手续费物有所值。去中心化的矿池协议比如 P2Pool 和 Braidpool 完全没有任何希望能够提供这样的服务。
因为使用锚点输出的标准闪电通道需要花费 2 倍的区块空间,一个大矿工可以容易地以一定的折扣(比如 25%)提供协议外的手续费支付,这也实质上给了他们 25% 的溢价(相比于他们的更小的竞争对手)。给定矿池的手续费是高度竞争的,量级在 1% 到 2%,如果能够赚取 25% 的溢价,那会是一种巨大的竞争优势。有了闪电网络,可以自动化、便利地实现这样的服务。
我们不能开发让去中心化挖矿反而处于不利地位的协议。单凭这一点,就是 V3 交易和临时锚点输出不应被实现的好理由。
作为一个社区,我们应该追问,这样一个低效的提议,伴随去挖矿去中心化的巨大潜在伤害,为何走了如此之远。V3 交易的 PR 已经以各种形式存在了超过一年的时间,尚未有一份 BIP 或者任何真正的设计文档。尤其是,作者最近承认 8 他们对标准的闪电承诺交易的体积的认识是显著错误的,由此产生了前面提到的 V3 交易钉死问题。
在考虑这样复杂的协议决策时,我们不应该急着实现代码。我们应该定位真实的应用场景并解决这些场景的效率和隐藏后果。到目前为之,通过 PR 而公开的关于 V3 交易的文档没有提供这一类的分析;就我所知,我是第一个合理地比较了它于其它解决方案的人。