作者:SHINOBI

来源:https://bitcoinmagazine.com/technical/learning-from-the-lnd-bug-on-lightning

10 月 9 日,来自 Bitmatrix(一个建立在 Liquid Network 上的互换工具)团队的 Burak 在比特币主网络上创建并广播了一笔交易,花费了一个使用 Tapscript 构造了 998-of-999 门限签名要求的 UTXO。这笔交易的见证数据字段有 998 个单独的签名,而且体积上达到了大约 0.1 MB;而且,有点搞笑的是,参与多签名的 999 个参与者,每个人都使用了完全相同的公钥。这笔交易导致了使用 LND 客户端的大量闪电网络节点和使用 btcd 客户端的比特币节点崩溃。

制作这笔交易的全部用意,就是证明 Taproot 升级提升了多签名脚本(multisig)的可扩展性。即使不使用基于 Schnorr 签名的 MuSig 协议,Taproot 也可以支持比之前版本的比特币脚本大得多的多签名参与者集合。关于之前对多签名的大小限制,如果你研究了所有使用比特币脚本构造多签名的方式,你会发现其中细节非常多,所以,为了简化,我只准备简单讲讲之前应用在 Pay-to-script-hash(P2SH)和 Pay-to-witness-script-hash(P2WSH)的多签名构造上的限制。在 P2SH 多签名构造的标准形式中,参与者最多只能有 15 个;而在标准的 P2WSH 多签名构造中,最多能有 20 个。出现这些限制,是因为使用这些不同操作的脚本有体积上的限制,而且在单个脚本中可以执行的处理操作的数量也是有限制的。打破任何一种限制都会使交易变成无效的。

而在 Taproot 实现之后,这些脚本大小的限制就被完全移除了,也就是说,限制 Taproot 脚本大小的因素只剩下了区块体积限制本身。而这就是 LND 和 btcd 出问题的根源。btcd 所实现的共识规则正确地移除了对脚本体积的限制,但问题是,btcd 还在点对点通信的代码中实现了对脚本体积的检查,这本意是为节点实现双重防御。区块和交易会先经过一个 “预共识” 的验证,然后再进入由核心共识代码执行的公式验证,这种双重检查的逻辑也是为了添加对无效区块和交易的额外防御。这部分代码并没有恰当地升级到移除对脚本体积的限制,它们继续对 Taproot 交易实施应用在 SegWit 交易上的限制。所以,虽然实际上的共识代码可以恰当地验证上述这一笔非常大的 Taproot 交易,但保护这笔交易的区块将无法通过点对点通信中的验证、进入到实际的共识验证逻辑,因此,所有的 btcd 节点都会卡在这个包含了这笔超大交易的区块上。

但是,许多人都是运行 Bitcoin Core 作为自己的 LND 闪电节点的比特币后端的,为什么这些节点也会受到影响呢?因为 LND 使用了 btcd 接收和处理区块的代码。所以,即使你的 LND 节点是搭配 Bitcoin Core 运行的、Bitcoin Core 可以恰当地验证这个区块而不会被卡住,LND 也会拒绝接受这个区块然后卡住,哪怕你的主链节点会继续处理。

这个 bug 很快就被补上了,而且据我所知,没有被主动利用并造成任何损失,但是,它让闪电网络上的每一个 LND 节点都处在通道中的资金可能被盗的风险中,除非节点运营者使用了外部的瞭望塔服务。因为节点卡在了这个区块,它就无法接收区块链的实时状态,如果这时候你的通道对手提交了一个旧的通道状态到区块链上,你是完全一无所知、也无法发布惩罚交易来应对。这是一个非常严重的 bug,会让闪电网络中的大量比特币处在被盗的风险中,用户要么得自己打补丁或者升级节点,要么得自己监控区块链以便在对手使用过时状态关闭通道时手动响应。我认为,绝大部分不懂技术的节点运营者可能都做不到这些。

幸运的是,这个问题并没有被广泛利用;但是,如果这个漏洞在 Burak 的交易发布之前就被发现了,就有可能被不怀好意的人以非常高妙的方式主动利用。一个人或者一群人,可以很容易在闪电网络上开启大量的通道,然后通过潜水艇互换,将通道中的所有资金都在链上发回给自己(让所有余额都位于通道对手那边),然后在链上发起一笔像 Burak 这样的大体积 Taproot 交易,然后立即使用过时的通道状态来关闭通道(从而欺诈对手)。受害者可以根本无法察觉,或者即使有所察觉,也因为技术能力不足而无法及时手动发出惩罚交易、纠正问题。

这个 bug 点出了两个需要我们思考的问题。其一,多种比特币节点的独立实现可能是非常危险的。幸好几乎没有人在重要场景中以 btcd 为节点,所以这次事件对比特币网络造成的影响可以忽略不计,只有很少一部分个人的节点卡住了而已。要是矿工一直在运行 btcd,这种事件很容易就会导致比特币网络链分裂、让所有运行 btcd 的节点跑到少数者链上去,需要手动干预来纠正。其二,对建立在主链上的二层网络来说,共识检查的实现必须非常谨慎。这是一个吊诡的问题,因为虽然所有的闪电节点都运行在比特币全节点之上、理论上来说它们可以直接把验证工作全部外包给比特币节点,但并不是所有的闪电网络节点都使用自己信得过的全节点。这是很难改变的 —— 许多用户将很有可能继续这样运营节点,所以一定程度上来说,检查部分乃至全部比特币共识规则,是所有闪电节点实现都必须做的事。

展望未来,我希望这是一记棒喝,提醒我们,保证共识验证在整个领域的所有软件中完全同步,是极为重要的,因为如果没有这样全方位的同步特性,就不是一个融贯的比特币网络。每个人都应该感到庆幸,这次事件没有造成网络的大规模破坏,但人们应该意识到,如果剧情不是像今天发生的这样,可能会有多么可怕。

(完)