本文档详细阐述了闪电网络中链上交易处理的建议,涵盖了通道结束的三种方式:互相同意关闭、单方面关闭以及撤销交易关闭,并详细说明了节点在链上遇到这些情况时应如何反应,包括如何处理承诺交易、HTLC输出以及撤销交易,以确保资金安全。
闪电网络允许两个参与方(一个本地节点和一个远程节点)通过给每个参与方一个交叉签名的承诺交易来进行链下交易,该交叉签名承诺交易描述了通道的当前状态(基本上是当前的余额)。这个承诺交易在每次进行新的支付时都会更新,并且可以随时花费。
一个通道可以通过三种方式结束:
因为闪电网络被设计为无需信任的,所以在以上三种情况下都没有资金损失的风险;前提是情况得到妥善处理。本文档的目标是准确地解释一个节点在链上遇到以上任何情况时应该如何反应。
任何未花费的输出都被认为是未解决的,并且可以按照本文档中的详细说明进行解决。通常,这是通过使用另一个解决交易来花费它来实现的。然而,有时简单地记录输出以供以后钱包花费就足够了,在这种情况下,包含该输出的交易被认为是其自身的解决交易。
已解决的输出一旦远程的解决交易包含在最长工作量区块链的至少 100 个区块中,就被认为是不可撤销地解决的。100 个区块远远大于已知的最长的比特币分叉,并且与矿工奖励确认所用的等待时间相同(参见参考实现)。
一个节点:
error
。一旦本地节点有一些资金处于风险之中,就需要监控区块链以确保远程节点不会单方面关闭。
无效的交易(例如,错误的签名)可以由任何人生成,(并且无论如何都会被区块链忽略),所以它们不应该触发任何操作。
本地和远程节点各自持有一个承诺交易。每个承诺交易最多有六种类型的输出:
为了激励本地和远程节点合作,一个 OP_CHECKSEQUENCEVERIFY
相对超时限制了本地节点的输出(在本地节点的承诺交易中)和远程节点的输出(在远程节点的承诺交易中)。因此,例如,如果本地节点发布了它的承诺交易,它将不得不等待才能领取自己的资金,而远程节点将立即获得自己的资金。因此,这两个承诺交易并不相同,但它们(通常)是对称的。
更多细节参见 BOLT #3:承诺交易。
尽管关闭通道可以通过几种方式完成,但最好选择最有效的方式。
各种错误情况涉及关闭通道。在 BOLT #1:error
消息 中指定了向对等节点发送错误消息的要求。
一个节点:
to_local
或 HTLC 输出:
to_local
或其他 HTLC 输出:
closing_signed
消息:to_local_anchor
输出,提供足够的费用作为激励,以将承诺交易包含在一个区块中。
当花费给第三方时,必须特别小心,因为这重新引入了通过向非锚点输出添加 CSV 延迟来解决的漏洞。由于 dust_limit_satoshis
应该可以防止创建不经济的输出(否则这些输出将永远保留在区块链上未花费),因此必须花费所有承诺交易输出。
在一个通道的早期阶段,通常一方在通道中只有很少或没有资金;在这种情况下,由于没有风险,节点不需要消耗资源来监控通道状态。
存在一种偏向,倾向于互相同意关闭而不是单方面关闭,因为前者的输出不受延迟的限制,并且可以直接由钱包花费。此外,互相同意关闭的费用往往不如承诺交易的费用那么夸张(或者在 option_anchors
的情况下,承诺交易可能需要一个子交易才能被挖掘)。因此,不使用来自 closing_signed
的签名的唯一原因将是,所提供的费用太小而无法处理。
关闭交易解决了资金交易输出。
在互相同意关闭的情况下,节点不需要做任何其他事情,因为它已经同意了该输出,该输出已发送到其指定的 scriptpubkey
(参见 BOLT #2:关闭启动:shutdown
)。
这是涉及单方面关闭的两种情况中的第一种。在这种情况下,节点发现其本地承诺交易,该交易解决了资金交易输出。
然而,一个节点在 OP_CHECKSEQUENCEVERIFY
延迟过去之前(如远程节点的 to_self_delay
字段所指定的那样),不能从其发起的单方面关闭的输出中领取资金。在相关的情况下,下面会提到这种情况。
一个节点:
to_local
输出花费到一个方便的地址。OP_CHECKSEQUENCEVERIFY
延迟过去(如远程节点的 to_self_delay
字段所指定的那样)才能花费该输出。
to_remote
输出。
to_remote
被承诺交易本身解决。花费 to_local
输出避免了记住与特定通道相关的、复杂的见证脚本,以供以后花费。
to_remote
输出完全是远程节点的事情,可以忽略。
每个 HTLC 输出只能由本地提供者花费,方法是在超时后使用 HTLC-timeout 交易,或者由远程接收者花费,如果它有付款预原像。
可能存在没有被任何输出表示的 HTLC:要么是因为它们被作为灰尘修剪了,要么是因为该交易只被部分提交了。
一旦最新区块的高度等于或大于 HTLC cltv_expiry
,则 HTLC 输出就已超时。
一个节点:
OP_CHECKSEQUENCEVERIFY
延迟过去(如远程节点的 open_channel
的 to_self_delay
字段所指定的那样)。付款预原像要么用于证明付款(当提供节点发起付款时),要么用于从另一个对等方赎回相应的传入 HTLC(当提供节点转发付款时)。一旦一个节点提取了付款,它就不再关心 HTLC 花费交易本身的命运了。
在两种解决方式都可能的情况下(例如,当一个节点在超时后收到付款成功时),任何一种解释都是可以接受的;接收者有责任在此之前花费它。
本地 HTLC-timeout 交易需要用于使 HTLC 超时(以防止远程节点履行它并领取资金),然后本地节点才能使用 update_fail_htlc
(大概以 permanent_channel_failure
为理由)来向后失败任何相应的传入 HTLC,如 BOLT #2 中详细说明的那样。如果传入 HTLC 也在链上,则节点必须简单地等待它超时:没有办法发出早期失败的信号。
如果一个 HTLC 太小而无法出现在任何承诺交易中,则可以安全地立即失败它。否则,如果一个 HTLC 不在本地承诺交易中,一个节点需要确保区块链重组或竞争不会切换到包含该 HTLC 的承诺交易,然后该节点才能使其失败(因此需要等待)。传入 HTLC 在其自身超时之前失败的要求仍然适用作为上限。
每个 HTLC 输出只能由接收者花费,使用 HTLC-success 交易,它只有在拥有付款预原像时才能填充。如果它没有预原像(并且没有发现它),则提供者有责任在超时后花费该 HTLC 输出。
对于提供的 HTLC,有几种可能的情况:
一个本地节点:
OP_CHECKSEQUENCEVERIFY
延迟过去(如远程节点的 open_channel
的 to_self_delay
字段所指定的那样),然后才能花费该 HTLC-success 交易输出。如果该输出被花费(如建议的那样),则该输出会被花费交易解决,否则它被 HTLC-success 交易本身解决。
如果它没有以其他方式解决,一旦 HTLC 输出已过期,它就被认为是不可撤销地解决的。
远程节点的承诺交易解决了资金交易输出。
在这种情况下,没有延迟限制节点行为,因此节点处理起来比它发现其本地承诺交易的情况更简单(参见 单方面关闭处理:本地承诺交易)。
一个本地节点:
to_remote
的行动,这只是一个支付给本地节点的 P2WPKH 输出。to_remote
被承诺交易本身解决。to_local
的行动,这是一个支付给远程节点的付款输出。to_local
被承诺交易本身解决。在通过 commitment_signed
收到签名之后和相应的 revoke_and_ack
之前,可能会有多个有效的未撤销承诺交易。因此,任何一个承诺都可以作为远程节点的承诺交易;因此,需要本地节点同时处理这两种情况。
在数据丢失的情况下,本地节点可能会达到一种状态,即它无法识别远程节点的所有承诺交易 HTLC 输出。它可以检测到数据丢失状态,因为它已经签署了该交易,并且承诺号大于预期。它可以推导出它自己的该交易的 remotepubkey
,以便挽救自己的资金。注意:在这种情况下,节点将无法挽救 HTLC。
每个 HTLC 输出只能由本地提供者在超时后花费,或者由远程接收者通过使用 HTLC-success 交易来花费,如果它有付款预原像。
可能存在没有被任何输出表示的 HTLC:要么是因为输出被剪裁为灰尘,要么是因为远程节点有两个具有不同 HTLC 的有效承诺交易。
一旦最新区块的深度等于或大于 HTLC cltv_expiry
,则 HTLC 输出就已超时。
一个本地节点:
如果承诺交易属于远程节点,那么它花费 HTLC 输出(使用付款预原像)的唯一方法是使用 HTLC-success 交易。
付款预原像要么用于证明付款(当提供节点是付款的发起者时),要么用于从另一个对等方赎回相应的传入 HTLC(当提供节点转发付款时)。在一个节点提取付款之后,它不再需要关心 HTLC 花费交易本身的命运。
在两种解决方式都可能的情况下(例如,当一个节点在超时后收到付款成功时),任何一种解释都是可以接受的:接收者有责任在此之前花费它。
一旦它超时,本地节点需要在向后失败任何相应的传入 HTLC(使用 update_fail_htlc
(大概以 permanent_channel_failure
为理由))之前花费 HTLC 输出(以防止远程节点使用 HTLC-success 交易),如 BOLT #2 中详细说明的那样。如果传入 HTLC 也在链上,则节点只需等待它超时,因为没有办法发出早期失败的信号。
如果一个 HTLC 太小而无法出现在任何承诺交易中,它可以安全地立即失败。否则,如果一个 HTLC 不在本地承诺交易中,一个节点需要确保区块链重组或竞争不会切换到包含它的承诺交易,然后该节点才能使其失败:因此需要等待。传入 HTLC 在其自身超时之前失败的要求仍然适用作为上限。
远程 HTLC 输出只能由本地节点花费,如果它有付款预原像。如果本地节点没有预原像(并且没有发现它),则远程节点有责任在超时后花费该 HTLC 输出。
实际上,对于提供的 HTLC,有几种可能的情况:
一个本地节点:
如果没有以其他方式解决,一旦 HTLC 输出已过期,它就被认为是不可撤销地解决的。
如果任何节点试图通过广播过时的承诺交易(除了最新的承诺交易之外的任何先前的承诺交易)来作弊,则通道中的另一个节点可以使用其撤销私钥来声明来自通道原始资金交易的所有资金。
一旦一个节点发现它拥有撤销私钥的承诺交易,资金交易输出就会被解决。
一个本地节点:
per_commitment_secret
的承诺交易。option_anchors
适用:
security_delay
区块之前没有确认:
解决所有输出的单个交易将低于标准大小限制,因为每方有 483 个 HTLC 的限制(参见 BOLT #2)。
注意:如果 option_anchors
适用,作弊节点可以借助 SIGHASH_SINGLE 的可延展性来钉死其 HTLC-timeout / HTLC-success 输出的花费。因此,对所有已撤销的输出使用单个惩罚交易是不安全的,因为它可能会被阻止传播足够长的时间,以至于本地节点的 to_local
输出的相对锁定时间到期,并且作弊方逃脱了对该输出的惩罚。尽管如果钉死交易确认,这种情况不会阻止对第二级已撤销输出的忠实惩罚*。
security_delay
是相对于已撤销输出的绝对到期时间的固定点,在该时间点,惩罚节点必须广播已撤销输出的单次花费交易,并积极地提高费用,直到确认。security_delay
的确切值留作节点策略的问题,尽管我们建议 18 个区块(类似于传入 HTLC 的截止时间)。
惩罚交易有三种不同的脚本,具有以下见证权重(权重计算的详细信息在 附录 A 中):
to_local_penalty_witness: 160 字节
offered_htlc_penalty_witness: 243 字节
accepted_htlc_penalty_witness: 249 字节
惩罚 txinput 本身占用 41 个字节,权重为 164 个字节,这导致每个输入的权重如下:
to_local_penalty_input_weight:324 字节
offered_htlc_penalty_input_weight:407 字节
accepted_htlc_penalty_input_weight:413 字节
惩罚交易的其余部分占用 4+1+1+8+1+34+4=53 字节的非见证数据:假设它有一个 pay-to-witness-script-hash (最大的标准输出脚本),此外还有一个 2 字节的见证头。
除了花费这些输出之外,惩罚交易还可以选择花费承诺交易的 to_remote
输出(例如,减少支付的总费用)。这样做需要包含 P2WPKH 见证和一个额外的 txinput,从而导致额外的 108 + 164 = 272 字节。
在最坏的情况下,该节点只持有传入的 HTLC,并且 HTLC-timeout 交易未发布,这迫使该节点从承诺交易中花费。
最大标准权重为 400000 字节,可以在单个交易中扫描的 HTLC 的最大数量如下:
max_num_htlcs = (400000 - 324 - 272 - (4 * 53) - 2) / 413 = 966
因此,可以在单个惩罚交易中解决 483 个双向 HTLC(包含 to_local
和 to_remote
输出)。注意:即使不扫描 to_remote
输出,产生的 max_num_htlcs
也是 967;这产生了相同的 483 个 HTLC 的单向限制。
如果 option_anchors
不适用于承诺交易,则 HTLC-timeout 和 HTLC-success 交易是完整的交易,具有(希望!)合理的费用,并且必须直接使用。
否则,必须在从对等方收到的 HTLC 签名上使用 SIGHASH_SINGLE|SIGHASH_ANYONECANPAY
,因为这允许将 HTLC 交易与其他交易组合在一起。本地签名必须使用 SIGHASH_ALL
,否则任何人都可以将额外的输入和输出附加到该交易。
如果 option_anchors
适用,则 HTLC-timeout 和 HTLC-success 交易使用具有相同值的输入和输出来签名。这意味着它们的费用为零,并且必须与其他输入组合以获得合理的费用。
一个为承诺交易广播 HTLC-success 或 HTLC-timeout 交易的节点:
option_anchors
适用:
一个节点:
to_local
惩罚交易见证的预期权重如 BOLT #3 中所述,此交易的见证是:
<sig> 1 { OP_IF <revocationpubkey> OP_ELSE to_self_delay OP_CSV OP_DROP <local_delayedpubkey> OP_ENDIF OP_CHECKSIG }
````to_local` penalty 交易见证的**预期权重**计算如下:
to_local_script: 83 字节
- OP_IF:1 字节
- OP_DATA:1 字节(revocationpubkey 长度)
- revocationpubkey:33 字节
- OP_ELSE:1 字节
- OP_DATA:1 字节(delay 长度)
- delay:8 字节
- OP_CHECKSEQUENCEVERIFY:1 字节
- OP_DROP:1 字节
- OP_DATA:1 字节(local_delayedpubkey 长度)
- local_delayedpubkey:33 字节
- OP_ENDIF:1 字节
- OP_CHECKSIG:1 字节
to_local_penalty_witness:160 字节
- number_of_witness_elements:1 字节
- revocation_sig_length:1 字节
- revocation_sig:73 字节
- one_length:1 字节
- witness_script_length:1 字节
- witness_script (to_local_script)
### `offered_htlc` Penalty 交易见证的预期权重
`offered_htlc` penalty 交易见证的**预期权重**计算如下(一些计算已经在 [BOLT #3](https://learnblockchain.cn/article/18233) 中完成):
offered_htlc_script: 133 字节
offered_htlc_penalty_witness: 243 字节
- number_of_witness_elements: 1 字节
- revocation_sig_length: 1 字节
- revocation_sig: 73 字节
- revocation_key_length: 1 字节
- revocation_key: 33 字节
- witness_script_length: 1 字节
- witness_script (offered_htlc_script)
### `accepted_htlc` Penalty 交易见证的预期权重
`accepted_htlc` penalty 交易见证的**预期权重**计算如下(一些计算已经在 [BOLT #3](https://learnblockchain.cn/article/18233) 中完成):
accepted_htlc_script: 139 字节
accepted_htlc_penalty_witness: 249 字节
- number_of_witness_elements: 1 字节
- revocation_sig_length: 1 字节
- revocation_sig: 73 字节
- revocationpubkey_length: 1 字节
- revocationpubkey: 33 字节
- witness_script_length: 1 字节
- witness_script (accepted_htlc_script)
## 作者
[待定:]

<br>
本作品采用 [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/) 许可。
>- 原文链接: [github.com/lightning/bol...](https://github.com/lightning/bolts/blob/fd83d7cee0369eb1d9068eb9864bff8b1f940938/05-onchain.md)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!