Lightning Network

Table of Contents

1. 闪电网络简介

比特币有一些不足:

  • 约每 10 分钟打包一个区块,这对于那些对时效要求高的应用来说是无法接受的;
  • 而且比特币不适合进行小额转账,这是因为手续费可能比转账金额还高。

闪电网络(Lightning Network)可以解决上面提到的问题。2015 年 2 月,Joseph Poon 和 Thadeus Dryja 首次对闪电网络进行了描述(闪电网络白皮书参见 The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments),该网络建立在其他人提出和阐述的支付通道概念的基础上。

2. 支付通道(Payment Channel)

支付通道是闪电网络的基础,让我们先了解它。

支付通道是一个虚拟的概念,实际上没有“通道”,底层数据传输机制也并不是通道,我们使用通道这个术语来表示链外双方之间的关系。

当两个参与方完成一个注资交易(Funding Transaction)或称锚点交易(Anchor Transaction)后,我们称通道已经打开。

随后双方交换已签名的交易,这被称为 承诺交易(Commitment Transactions)。 承诺交易会改变两个参与方的资金分配比例。这些交易是有效的交易,因为它们可以被任何一方提交进行结算,但是在通道关闭之前,每一方都会将其在链下保留。状态更新的创建速度可以与每一方创建、签名并将交易传输给另一方的速度一样快。实际上,这意味着每秒可以交换数千笔交易。

最后, 通道可以协商关闭,即向区块链提交最后的结算交易(Settlement Transaction), 或者由任何一方单方面提交最后一个承诺交易到链上。结算交易代表通道的最终状态,并在链上进行结算。

在通道的整个生命周期中,只有两个交易需要提交到链上:“注资交易”和“结算交易”。在这两个状态之间,双方可以交换任何数量的承诺交易,任何其他人永远不会看到,也不会提交到链上。

1 是 Bob 和 Alice 之间的支付通道,显示了注资交易(提交上链),承诺交易(不提交上链)和结算交易(提交上链)。

ln_payment_channel.png

Figure 1: Bob 和 Alice 之间的支付通道,显示了注资交易,承诺交易和结算交易

2.1. 简单支付通道示例

我们从一个非常简单的例子开始。这个例子是一个单向通道,意味着价值只向着一个方向流动。为了便于解释,我们先假设没有人要试图欺骗他人。一旦我们解释了基本的通道概念,我们将研究如何使双方都不能作弊。

对于这个例子,我们假设两个参与者:Emma 和 Fabian。Fabian 提供视频流服务,使用支付通道按秒计费。Fabian 每秒视频收费 0.01 毫比(millibits)(0.00001 BTC),相当于每小时视频收费 36 毫比(0.036 BTC)。Emma 从 Fabian 这里购买流媒体视频服务。图 2 显示 Emma 使用支付通道从 Fabian 购买视频流服务。

ln_payment_channel_example0.png

Figure 2: Emma 使用以秒计费的支付通道从 Fabian 购买视频流服务

在这个例子中,Fabian 和 Emma 使用专门的软件来处理支付通道和视频流。Emma 在浏览器中运行软件,Fabian 从服务器端运行软件。这个软件包括基本的比特币钱包功能,可以创建和签署比特币交易。“支付通道”的概念和术语对于用户都是完全不可见的。他们看到的是以秒为单位付费的视频。

为了设置支付通道,Emma 和 Fabian 建立了一个 2/2 的多重签名地址,双方各持一个密钥。从 Emma 的角度来看,她的浏览器中的软件提供了一个带有 P2SH 地址的二维码(以“3”开头),并要求她提交最多 1 小时视频的“押金”。Emma 向该地址支付资金。Emma 支付给该多重地址的交易,就是支付通道的注资交易或叫锚点交易。

就这个例子而言,我们假设 Emma 支付了 36 个毫比(0.036 BTC)到通道中。这将允许 Emma 消费长达 1 小时的流媒体视频。这笔注资交易设定了可以在这个通道上发送的最大数量(数据量),即设置了通道容量(Channel Capacity)。

注资交易从 Emma 的钱包中消耗一个或多个输入以汇集资金。它创建一个价值为 36 毫比的输出,支付给 Emma 和 Fabian 之间共同控制的 2/2 多重签名地址。它也可能有一个作为找零到 Emma 的钱包的额外输出。

一旦注资交易得到确认,Emma 可以开始观看视频。Emma 的软件创建并签署一笔承诺交易,改变通道余额,将 0.01 毫比归入 Fabian 的地址,并退回给 Emma 35.99 毫比。Emma 签署的交易消耗了由注资交易创造的 36 毫比输出,并创建了两个输出:一个用于找钱,另一个用于 Fabian 的付款。交易只是部分被签署了,它需要两个签名(2/2),但现在只有 Emma 的签名。当 Fabian 的服务器接收到此交易时,它会添加第二个签名(用于 2/2 输入),并将其与时长 1 秒的视频一起返回给 Emma。现在双方都有谁都可以兑换的完全签署的承诺交易,这个承诺交易代表着通道中的最新正确余额。双方都不会将此交易广播到网络中。

在下一轮,Emma 的软件创建并签署另一个承诺交易(2 号承诺交易),该交易从资金交易中消耗相同的 2/2 输出。2 号承诺交易分配 0.2 毫比的一个输出到 Fabian 的地址,还有一个输出为 35.98 毫比,作为找零返回给 Emma 的地址。这个新交易支付的是累积两秒的视频内容。Fabian 的软件签署并返回第二个承诺交易,再加上另一秒视频。

利用上述的方法,Emma 的软件继续向 Fabian 的服务器发送承诺交易,以换取流媒体视频。因为 Emma 观看了更多秒数的视频,通道中属于 Fabian 的钱逐渐累积变多。假设 Emma 观看 600 秒(10 分钟)的视频,创建和签署 600 笔承诺交易。最后的承诺交易(600 号承诺交易)将有两个输出,将通道的余额分成两半,分别为 6 毫比属于 Fabian 和 30 毫比属于 Emma。

最后,Emma 点击“停止”停止流媒体视频。Fabian 或 Emma 现在可以发送最终状态交易以进行结算。最后一笔交易即为结算交易,向 Fabian 支付所有 Emma 消费的视频,并退还给 Emma 注资交易中剩余的资金。

3 显示了 Emma 和 Fabian 之间的通道以及更新通道余额的承诺交易。

ln_payment_channel_example1.png

Figure 3: Emma 和 Fabian 之间的支付通道,承诺交易不断的更新通道余额

最后,只有两个交易记录在块上:建立通道的“注资交易”和在两个参与者之间正确分配最终余额的“结算交易”。

2.2. 无需信任的通道

上一节的例子存在两个问题:

  1. 一旦注资交易发生,Emma 需要 Fabian 的签名才能收回自己的资金。如果 Fabian 消失,Emma 的资金将被锁定在 2/2 多签地址中,造成损失。
  2. Emma 可以把早期的承诺交易提交到区块链来关闭通道。如果她可以发送 1 号承诺交易,只需支付 1 秒的视频,为什么还要支付 600 秒的视频?也就是说 Emma 可以通过广播对她比较有利的之前的承诺交易来欺骗。

这两个问题都可以用时间锁来解决,下面看看如何使用交易级时间锁(nLocktime)。

除非有退款保证,否则 Emma 不能冒风险支付到 2/2 多重签名地址。为了解决这个问题,Emma 同时建立了注资交易和退款交易。 她只是签名了注资交易,但暂时不发送给任何人。Emma 只将退款交易传送给 Fabian,并获得他的签名。

退款交易作为第一个承诺交易,其时间锁规定了通道生命的上限。 在这种情况下,Emma 可以将 nLocktime 设置为 30 天或将来的第 4320 个区块。所有后续承诺交易必须具有较短的时间锁,以便在退款交易之前能把它们兑换。

现在,Emma 已经有一个完全签署的退款交易,她可以自信地发送签署过的注资交易,因为她知道最终可以在时间到期后赎回退款交易,即使 Fabian 消失也不会有问题。

在通道生命中双方交换的每一个承诺交易都会被时间锁锁进未来的时间点。但是每个承诺交易的延迟时间会稍短一点,因此最近的承诺可以在先前的承诺失效之前兑现。由于 nLocktime,任何一方都只有其时间锁到期后才能成功传播任何承诺交易。如果一切顺利,他们将协商并通过结算交易正常关闭通道,这样就无需发送中间的承诺交易了。如果发生意外,则可以传播最近的承诺交易进行账户结算,并使以前的所有承诺交易都失效。

例如,如果 1 号承诺交易被时间锁锁定到未来的第 4320 个区块,则 2 号承诺交易被时间锁锁定到未来的 4319 个块。就是说在 1 号承诺交易变为有效之前还有 600 个区块时,600 号承诺交易就可以被花费了。

4 显示每个承诺交易设置“较短的时间锁”,允许在它在之前的承诺变为有效前被花费。

ln_payment_channel_example2.png

Figure 4: 关键点:1. 第一个承诺交易是退款交易;2. 每个承诺交易设置“较短的时间锁”,允许在它在之前的承诺变为有效前被花费

每个后续承诺交易必须具有较短的时间锁,以便可以在上一个承诺交易和退款交易之前进行广播。提前广播承诺的能力可以确保只有它最先能够花费资金输出,并阻止任何其他承诺交易通过花费输出实现兑换。

时间锁可以使先前的承诺无效,但其有两个明显的缺点:

  1. 在通道首次打开时建立最大时间锁,这限制了通道的使用寿命。更糟糕的是,允许通道长时间保留,和如果其中一位参与者提前关闭通道需要等待很长时间才能退款,它们迫使通道要在这二者之间实现一种平衡。
  2. 由于每个后续的承诺交易必须缩短时间锁,所以在双方之间可以交换的承诺交易数量有明确的限制。例如,一个 30 天的通道,设置了位于未来第 4320 个区块的时间锁,在必须被关闭前这段时间只能容纳 4320 个承诺交易。将时间锁承诺交易的间隔设置为 1 个区块存在风险。如果将承诺交易之间的时间锁设置为 1 个区块,开发者会给通道参与者带来了非常高的负担,参与者必须保持警惕,保持在线并监视,并随时准备传送正确的承诺交易。

后面将介绍其它可以使先前的承诺无效的方案。

2.3. 不对称可撤销承诺(Asymmetric Revocable Commitments)

上一节也提到时间锁的方案存在一些缺点,时间锁并不是使之前的承诺交易无效的唯一方法。这节我们将介绍如何使用“撤销密钥”来让先前的承诺无效。

为了解释撤销密钥,我们将在由 Hitesh 和 Irene 经营的两个交易所之间构建一个更加复杂的支付通道。 Hitesh 和 Irene 分别在印度和美国运营比特币交易所。 Hitesh 的印度交易所的客户经常向 Irene 的美国交易所的客户发送付款,反之亦然。目前,这些交易发生在比特币链上,但这需要支付交易费还要等待几个区块进行确认。在交易所之间设置支付通道将大大降低成本并加快交易流程。

Hitesh 和 Irene 通过合作建立注资交易来启动通道,每人向通道注资 5 个比特币。初始余额为 Hitesh 有 5 比特币且 Irene 有 5 比特币。注资交易将通道状态锁定在 2/2 多重签名中,就像在简单支付通道的例子中一样。

接着,Hitesh 和 Irene 创建了两个不对称的 asymmetric 承诺交易,而不是创建一个双方都签署的单一承诺交易。

Hitesh 有一个带有两个输出的承诺交易。第一个输出是立即支付欠 Irene 的 5 比特币。第二个输出是支付欠 Hitesh 自己的 5 比特币,但条件是 只有在 1000 个区块的时间锁之后。 交易输出如下所示:

# 下面 Tx 的 Input 是 2/2 多签,所以需要两人签名才能提交上链
# 这个 Tx 对 Irene 更有利,因为它马上会给 Irene 5 BTC
# Irene 已经签名,给 Hitesh 持有(这样 Hitesh 自己签名后可以提交上链)
# 但 Hitesh 并不会把签名给 Irene(所以Irene 没有办法提交上链)

Input: 2-of-2 funding output, signed by Irene

Output 0 <5 bitcoin>:
    <Irene's Public Key> CHECKSIG

Output 1:
    <1000 blocks>
    CHECKSEQUENCEVERIFY
    DROP
    <Hitesh's Public Key> CHECKSIG

Irene 也有带有两个输出的不同的承诺交易。第一个输出支付欠 Hitesh 的 5 比特币。 第二个输出支付给欠 Irene 自己的 5 比特币,但同样必须经过 1000 个区块的时间锁。 Irene 持有的承诺交易(由 Hitesh 签署)看起来像这样:

# 下面 Tx 的 Input 是 2/2 多签,所以需要两人签名才能提交上链
# 这个 Tx 对 Hitesh 更有利,因为它马上会给 Hitesh 5 BTC
# Hitesh 已经签名,给 Irene 持有(这样 Irene 自己签名后可以提交上链)
# 但 Irene 并不会把签名给 Hitesh(所以Hitesh 没有办法提交上链)

Input: 2-of-2 funding output, signed by Hitesh

Output 0<5 bitcoin>:
    <Hitesh's Public Key> CHECKSIG

Output 1:
    <1000 blocks>
    CHECKSEQUENCEVERIFY
    DROP
    <Irene's Public Key> CHECKSIG

这样一来,双方各有一笔承诺交易,可以花费 2/2 的资金输出。该承诺交易的输入是由对方署的。在任何时候,持有承诺交易的一方都可以签字(完成 2/2 签名)并进行广播。然而,如果他们广播承诺交易,承诺交易会立即支付对方,而他们自己的资金则必须等待时间锁到期。通过强制延迟兑换其中一方的输出,我们可以做到让各方在选择单方面广播承诺交易时处于轻微的不利地位。

5 显示两个不对称承诺交易,其中 承诺持有人的输出被延迟 。这样,承诺持有人就没有动力把承诺交易提交上链。

ln_payment_channel_example3.png

Figure 5: 两个不对称承诺交易,其中“承诺持有人的输出被延迟”

为了防止作弊者广播过期承诺,我们引入撤销密钥,它允许被欺诈的一方通过占有通道的所有余额来惩罚骗子。

撤销密钥由两个密语组成,每个密语由每个通道参与者独立生成。它类似于 2/2 的多重签名,使用椭圆曲线算法构造。 虽然双方都知道撤销公钥,但其实每一方只知道撤销密钥的一半。 在每一轮交易中,双方都将其撤销密语的一半透露给另一方,从而使另一方(现在双方都有)在广播此撤销的交易时,可以要求获得惩罚输出。每个承诺交易都有一个“延迟”的输出,该输出的兑换脚本允许一方在 1000 个区块后兑换它,或者另一方如果拥有撤销密钥(两个密语都知道)也可兑换它。

所以当 Hitesh 为 Irene 签署承诺交易时,他将在 1000 个区块之后把第二个输出定支付给自己,或者支付给撤销公钥(他只知道其中一半的密语)。Hitesh 构建了这个交易,他只会在准备改变通道状态,并希望撤销这一承诺交易时,才会把半个撤销密语透露给 Irene。

# Hitesh 持有的第 1 个承诺交易

# 这个 Tx 对 Irene 更有利,因为它马上会给 Irene 5 BTC
# Irene 已经签名,给 Hitesh 持有(Hitesh 自己签名后可以上链)
# 但 Hitesh 没有把签名给 Irene(所以 Irene 没有办法提交上链)
# 注:Tx 的 Input 是 2/2 多签,所以需要两人签名才能提交上链

Output 0 <5 bitcoin>:
    <Irene's Public Key> CHECKSIG

Output 1 <5 bitcoin>:
IF
    # Revocation penalty output
    <Revocation Public Key>
ELSE
    <1000 blocks>
    CHECKSEQUENCEVERIFY
    DROP
    <Hitesh's Public Key>
ENDIF
CHECKSIG

撤销密钥使用的关键是: Hitesh 必须先撤销之前他所持有的承诺交易后,Irene 才会对下一个 Hitesh 将持有的承诺交易进行签名;类似地,Irene 必须先撤销之前他所持有的承诺交易后,Hitesh 才会对下一个 Irene 将持有的承诺交易进行签名。

2.3.1. 实例讲解

假设 Irene 的一个客户希望向 Hitesh 的一个客户发送 2 比特币。要通过通道传输 2 比特币,他们将提交一个新的状态(状态号 2),通道的 10 个比特币被分割,7 个比特币属于 Hitesh 和 3 个比特币属于 Irene。

下面演示了 Hitesh/Irene 各自所持有承诺交易的情况:

 # Hitesh 持有的第 1 个承诺交易                                
                                                               
 # 这个 Tx 对 Irene 更有利,因为它马上会给 Irene 5 BTC         
 # Irene 已经签名,给 Hitesh 持有(Hitesh 自己签名后可以上链) 
 # 但 Hitesh 没有把签名给 Irene(所以 Irene 没有办法提交上链) 
 # 注:Tx 的 Input 是 2/2 多签,所以需要两人签名才能提交上链   
                                                               
 Output 0 [5 bitcoin]:                                         
     [Irene's Public Key] CHECKSIG                             
                                                               
 Output 1 [5 bitcoin]:                                         
 IF                                                            
     # Revocation penalty output                               
     [Revocation Public Key]                                   
 ELSE                                                          
     [1000 blocks]                                             
     CHECKSEQUENCEVERIFY                                       
     DROP                                                      
     [Hitesh's Public Key]                                     
 ENDIF                                                         
 CHECKSIG                                                      
 # Irene 持有的第 1 个承诺交易                                  
                                                                
 # 这个 Tx 对 Hitesh 更有利,因为它马上会给 Hitesh 5 BTC        
 # Hitesh 已经签名,给 Irene 持有(Irene 自己签名后可以上链)   
 # 但 Irene 没有把签名给 Hitesh(所以 Hitesh 没有办法提交上链) 
 # 注:Tx 的 Input 是 2/2 多签,所以需要两人签名才能提交上链    
                                                                
 Output 0 [5 bitcoin]:                                          
     [Hitesh's Public Key] CHECKSIG                             
                                                                
 Output 1 [5 bitcoin]:                                          
 IF                                                             
     # Revocation penalty output                                
     [Revocation Public Key]                                    
 ELSE                                                           
     [1000 blocks]                                              
     CHECKSEQUENCEVERIFY                                        
     DROP                                                       
     [Irene's Public Key]                                       
 ENDIF                                                          
 CHECKSIG                                                       
 Hitesh 必须撤销(公布他掌握的撤销密语)之前他持有的承诺交易, 
 Irene 才会对 Hitesh 持有的下一个承诺交易进行签名              
 Irene 必须撤销(公布他掌握的撤销密语)之前他持有的承诺交易,   
 Hitesh 才会对 Irene 持有的下一个承诺交易进行签名               
 # Hitesh 持有的第 2 个承诺交易                                
                                                               
 # Irene 已经签名,给 Hitesh 持有(Hitesh 自己签名后可以上链) 
                                                               
 Output 0 [3 bitcoin]:                                         
     [Irene's Public Key] CHECKSIG                             
                                                               
 Output 1 [7 bitcoin]:                                         
 IF                                                            
     # Revocation penalty output                               
     [Revocation Public Key]                                   
 ELSE                                                          
     [1000 blocks]                                             
     CHECKSEQUENCEVERIFY                                       
     DROP                                                      
     [Hitesh's Public Key]                                     
 ENDIF                                                         
 CHECKSIG                                                      
                                                               
 # 如果 Hitesh 提交旧的(第 1 个承诺交易),则 Irene 可得到所  
 # 有输出:1. 马上得到一个输出,2. 利用撤销密语得到另一个输出  
 # Irene 持有的第 2 个承诺交易                                  
                                                                
 # Hitesh 已经签名,给 Irene 持有(Irene 自己签名后可以上链)   
                                                                
 Output 0 [7 bitcoin]:                                          
     [Hitesh's Public Key] CHECKSIG                             
                                                                
 Output 1 [3 bitcoin]:                                          
 IF                                                             
     # Revocation penalty output                                
     [Revocation Public Key]                                    
 ELSE                                                           
     [1000 blocks]                                              
     CHECKSEQUENCEVERIFY                                        
     DROP                                                       
     [Irene's Public Key]                                       
 ENDIF                                                          
 CHECKSIG                                                       
                                                                
 # 如果 Irene 提交旧的(第 1 个承诺交易),则 Hitesh 可得到所   
 有输出:1. 马上得到一个输出,2. 利用撤销密语得到另一个输出     

2.4. 哈希时间锁合约(HTLC)

支付通道可以通过哈希时间锁(Hash Time Locked Contracts,HTLC)进一步扩展。

实现 HTLC 的脚本(Tx Output 锁定脚本)可能如下所示:

IF
    # Payment if you have the secret R. Node: H=Hash(R)
    HASH160 <H> EQUALVERIFY
ELSE
    # Refund after timeout.
    <locktime> CHECKLOCKTIMEVERIFY DROP
    <Payer Public Key> CHECKSIG
ENDIF

它有两个分支:

  1. 任何知道密钥 R,其哈希值等于 H 的人,都可以通过行使 IF 语句的第一个子句来兑换该输出。
  2. 如果密钥 R 没有被透露,HTLC 中写明了,在一定数量的区块之后,付款人可以使用 IF 语句中的第二个子句申请退款。

这是 HTLC 的基本实现。任何拥有秘密 R 的人都可以兑换这种类型的 HTLC。通过对脚本进行略微变化,HTLC 可以采用许多不同的形式。例如,在第一个子句中添加一个 CHECKSIG 运算符和一个公钥来将哈希值的兑换限制为指定收款人,这个人还必须知道密钥 R。

HTLC 有两个常见应用:

  1. 跨链的原子交换;
  2. 在闪电网络中实现“可路由”的支付通道。

关于 HTLC 的第 1 个应用,可以参考 Cross-Chain Atomic Swaps,这里不进行介绍;本文只介绍 HTLC 的第 2 个应用。

3. 闪电网络(可路由的支付通道)

闪电网络是一种端到端连接的双向支付通道的可路由网络。这样的网络可以允许任何参与者在不信任任何中间人的情况下将支付从一个通道路由到另一个通道。

3.1. 路由实例

假设 Alice 和 Bob 之间,Bob 和 Chan 之间,Chan 和 Dina 之间已经开通了通道。但 Alice 和 Dina 之间没有通道,如图 所示,Alice 想往 Dina 支付 50,000 satoshi,如何实现呢?

ln_routing_example0.png

Figure 6: 没有直接的通道,Alice 可以向 Dina 支付吗?

ln_routing_example1.png

Figure 7: Dina 生成秘密 R,把秘密的哈希 H 告诉 Alice

ln_routing_example2.png

Figure 8: Alice 和 Bob 实现 HTLC(Bob 知道秘密 R 就可以取走 50, 200);类似地,Bob 和 Chan;Chan 和 Dina 之间都实现 HTLC

ln_routing_example3.png

Figure 9: 秘密 R 开始反向传播,由 Dina 传给 Chan 后,Dina 可从 Chan 处拿走 50,000

ln_routing_example4.png

Figure 10: 秘密 R 由 Chan 传给 Bob 后,Chan 可从 Bob 处拿走 51,000

ln_routing_example5.png

Figure 11: 秘密 R 由 Bob 传给 Alice 后,Bob 可从 Alice 处拿走 52,000

ln_routing_example6.png

Figure 12: 最终各方通道中的余额

4. 参考

Author: cig01

Created: <2021-10-29 Fri>

Last updated: <2022-01-12 Wed>

Creator: Emacs 27.1 (Org mode 9.4)