乐趣区

如何在CKB上实现闪电网络一

闪电网络主要解决了比特币的可扩展性问题,闪电网络可以分为两部分:双向支付通道和通道间支付,本文主要介绍如何在 CKB 上实现双向支付通道。

双向通道的主要分为以下几个流程:通道建立、余额更新、通道关闭。

其中交易包括以下几种:

  • Funding Transaction,用于通道建立。
  • Commit Transaction,用于更新余额。
  • Exercise Settlement Transaction,用于关闭交易通道。

通道建立

通道建立是通过在链上广播 Funding Transaction 完成,Funding Transaction 是一个 2 - 2 的签名交易,为了方便我们将参与双方命名为 Alice 和 Bob。通道建立的步骤如下:

  1. 新建 Funding Transaction
  2. 新建 Commit Transaction
  3. 各自对 Commit Transaction 签名
  4. 交换 Commit Transaction 签名
  5. 各自对 Funding Transaction 签名
  6. 交换 Funding Transaction 签名
  7. 到链上广播 Funding Transaction

这里为什么要首先构造出 Commit Transaction 呢?因为如果 Alice 和 Bob 都对 Funding Transaction 签名后,任何一方都可以将交易广播到链上,但是花费 Funding Transaction 的 Output 需要双方的签名,如果任何一方不合作则会导致资金永远锁在 Funding Transaction 中,所以这里首先先构造出可以消费 Funding Transaction 的 First commitment Transaction 再对 Funding Transaction 签名,这样任何一方都可以从 Funding Transaction 中取出自己的资金,而不需要对手方去进行配合。

举例,Alice 提供一个 300 ckb 的 Input,Bob 提供一个 300 ckb 的 Input,然后 Output 为 600 ckb,锁定脚本为 2 - 2 的多签脚本,需要 Alice 和 Bob 的签名才能花费 Output。

(闪电网络白皮书中的一张图,将就看)

由于 Funding Transaction 的 Output 是一个 2 - 2 的多签脚本锁定,所以我们可以先部署一个 2 - 2 的多签合约。

合约代码如下:

https://github.com/u2/lightni…

我们可以看到 CKB 是可以用 C 语言写合约的。在部署 Funding Transaction 之前,我们可以先部署 2 - 2 的锁定脚本,这样 Funding Transaction 直接引用 2 - 2 多签合约即可。这样如果在 CKB 中有很多双向支付通道,可以共享一个多签脚本,而不必每个支付通道单独在合约中包含多签合约,减少合约的交易手续费,降低 CKB 的存储空间的占用。

闪电网络实现的一个前提是,必须要解决交易延展性问题,否则交易的 Hash 是不确定的,可能导致 Funding Transaction 的资金无法解锁。比如 Alice 和 Bob 构造完成 First commitment Transaction(1a, 1b)并广播 Signed Funding Transaction,但是这个时候矿工修改了 Signed Funding Transaction 中 Input 的签名脚本,Funding Transaction 最终上链,但是交易 Hash 和原来不一致。由于 First commitment Transaction 通过交易 Hash 来引用 Funding Transaction,此时找不到合法的 Funding Transaction,First commitment Transaction 将无法被消费,如果 Alice 或者 Bob 其中的任何一方采取不合作的方式,另一方将无法取出自己的资金。

比特币通过实现隔离见证解决了交易延展性问题,CKB 也实现了自己的隔离见证。在 CKB 中,用户只需要选择将签名等解锁参数放入交易中的 witnesses 中即可:

https://github.com/nervosnetw…

由于交易 hash 不包括用户解锁参数,

https://github.com/nervosnetw…

这样就可以是交易 hash 只包含 Inputs 和 Outputs 等交易处理的相关信息而不包含解锁脚本,解决交易延展性问题。

更新余额

Funding Transaction 被广播到链上之后,双向支付通道就成功建立了,后续 Alice 和 Bob 就可以构造离线的 Commitment Transaction 来更新双方的金额了。闪电网络的每一笔 Commitment Transaction 交易都是建立在 Funding Transaction 之上的。

在构造 Commitment Transaction 时,需要解决以下两个问题:

  • 追责问题。因为每笔 Commitment Transaction 都是合法的,而且都是建立在 Funding Transaction 之上。Alice 和 Bob 都各有一份不同 commitment transaction,如果其中任何一方将历史 commitment transaction 发送到链上,可以对其进行罚没。
  • 罚没机制。如果任何一方不遵循双向通道的机制,将历史交易发送到链上,则需要能将其资金进行罚没。

追责问题。解决追责问题,需要 Alice 和 Bob 构造两个不同的交易,我们可以将这两个交易分别命名为 2a,2b。假设最新的余额为 Alice 400,Bob 200,commitment transaction 具体的流程如下:

  1. 对于 Alice,其创建新的 Commitment Transaction 结构为,Output- 0 为 400,花费条件为 Alice 需要在 10 个高度可以花费或者拥有 Alice2(Alice2 的新私钥)+ Bob 的签名可以立即花费。Output- 1 为 200,需要 Bob 的签名可以立刻花费。
  2. 双方交换签名。

通过这种机制,可以构造一种交易,Alice 如果广播其交易 a1 交易,则 Alice 可以在 10 个高度之后花费 Output-0,Bob 可以立刻花费其 Output-1。

在介绍罚没机制之前,我们先介绍下比特币中的时间锁机制。在比特币中使用 nLocktime 来对交易进行时间限制,使交易必须在某个绝对高度或者时间之后才可以被记录到链上,CHECKLOCKTIMEVERIFY 指令可以配合 nLockTime 一起使用。交易 Inputs 中的 nSequence 可以用来对相对时间进行限制,是某个 Input 必须在 Output 上链一定时间后,其所在交易才可以被打包,CHECKSEQUENCEVERIFY 可以配合 nSequence 来使用。

在 CKB 中使用 Transaction Valid Since 机制,即可以表示相对时间或者区块,也可以表示绝对值,所以可以起到 Bitcoin 中的 nSequence 和 nLocktime 作用,设计上更简洁。由于 CKB VM 可以通过 syscall 获取到交易 Input 中的 since 值:

https://github.com/nervosnetw…

所以可以在不增加任何指令的情况下实现相对时间锁的作用。

例如代码

https://github.com/u2/lightni…

表示取出 Input 中的 since,并判断其是否是使用相对块高度,且必须在相对块高度大于 10 是才验证通过。这里保证了交易 Input 在当前条件下,只有在 10 个高度以后,才能被消费。

我们现在回到罚没机制上来,在上面的基础上,又加入了 Breach Remedy Transaction 机制,用来防止 Alice 或者 Bob 发送历史交易到链上。这样从建立通道到更新余额的完整流程为:

  1. Alice & Bob 构造完成各自的 First commitment Transaction(1a,1b),结构如上所示
  2. 广播 Funding Transaction 到链上。
  3. Alice & Bob 更新余额,构造各自新的 commitment transaction(2a, 2b),并交换签名
  4. Alice & Bob 分别向对方揭示 Alice2,Bob2 私钥(上一个 commitment transaction 中所用解锁 output 的私钥)。

在这种情况下,因为 Alice 拥有 Bob 的 Bob2 私钥,而 Bob 拥有 Alice 的 Alice2 私钥。如果 Alice 广播历史交易 a1,其交易 Output- 0 可以被 Alice2 + Bob 的签名理解花费,或者可以被 Alice 在 10 个高度后消费。在这种情况下,因为 Bob 已经拥有 Alice2 的私钥,所以 Alice 没有动机去广播历史交易 a1。同理对于 Bob 也适用。我们称这种 commitment transaction 为可以撤销的 commitment transaction(Revocable commitment transaction)。其 commitment transaction 的锁定脚本可以称为 revocable maturity script,代码:https://github.com/u2/lightni…

Alice 和 Bob 每次更新余额,都会构造一个新的可以撤销的 commitment transaction,并向对方揭示自己上一个 commitment transaction 的 output- 0 的私钥,这样自己的历史 commitment transaction 不需要保存,只需要保存对方揭示的私钥即可。双方都有检测链上对方是否有广播历史交易,如果对方有广播历史交易,可以使用自己的私钥和对方揭示的私钥构造 Breach Remedy Transaction 立即花费对方的 Output,这样可以将罚没对方的资金。

(闪电网络白皮书中的图,可以将就看)

关闭通道

Alice 和 Bob 可以选择合作构造 Exercise Settlement Transaction(ES transaction)来选择关闭通道。ES transaction 是没有任何时间锁的交易,这样 Alice 和 bob 可以选择直接广播交易来花费 Funding transaciton。

总结

在作者第一次实现的时候,和以上方案略有不同,并没有 revocable maturity 脚本,而是在构造每个 commitment transaction 时,双方各自事先构造好其上一个交易的 Breach Remedy Transaction 并互相交换签名。这种情况下,Alice 和 Bob 不需要生成很多私钥,但是缺点是 Alice 和 bob 需要保留历史的 Breach Remedy Transaction,因为交易比私钥更占空间,相对而言这种方案并不够合理。

在 CKB 中,实现了隔离见证以及灵活的时间锁机制,且用户可以通过提前部署闪电网络的相关合约,用更低成本来建立双向支付通道。对实现细节感兴趣的读者可以阅读下面项目中的代码。另外 CKB 中可以通过定义 Type Script 而实现 User defined Token 的闪电网络,这里不再赘述。

项目地址:https://github.com/u2/lightning

相关文章:《漫谈闪电网络》

比特币时间锁机制相关 Bips:

  • https://github.com/bitcoin/bi…
  • https://github.com/bitcoin/bi…
  • https://github.com/bitcoin/bi…

CKB 的时间锁机制:https://github.com/nervosnetw…

闪电网络白皮书:https://lightning.network/lig…

退出移动版