深入解读闪电网络:HTLC 的工作方式与多跳支付的实现方式


深入解读闪电网络:HTLC 的工作方式与多跳支付的实现方式
文章图片

文章图片
在上一篇文章里 , 我们详细解释了支付通道的运作 , 以及多种保证支付安全发生的方法 。不过 , 这些功能 , 还不足以支撑一个可用的支付通道网络:即使我们很确定在每个通道内每个参与者都是诚实守信的 , 也没法保证通过多个通道来支付同样是安全的 。这就是我们需要 “HTLC(哈希-时间锁-合约)” 这种智能合约的原因 。在本文中 , 我们会讲解 HTLC 工作的方式 , 并使用一个例子来展示多跳支付是如何在闪电网络中实现的 。
哈希时间锁合约(HTLC)
HTLC 的结构并不复杂 , 但非常高效 。它使我们可以创建具有明确 “过期时间” 的支付 。你可能也猜得到 , HTLC 合约由两部分组成:哈希验证和过期验证 。
我们先从哈希值(hash)开始 。要创建一笔带有 HTLC 的支付事务 , 你先要生成一个 秘密数值 R , 然后计算出其哈希值 。任何词语、任何数字都可以充当这个秘密值 , 因为 , 对哈希函数来说 , 它们都是一堆数据的组合 , 没有什么分别 。
H = Hash(R)
这个哈希值 H 会放在事务输出的锁定脚本中 。如此 , 只有知道 H 所对应的秘密值的人才能使用这个输出 。而 R 就是所谓的 “原像(preimage)” 。
HTLC 的第二部分是过期时间的验证 。如果秘密值没有及时地公开 , 这笔支付就用不了了 , 发送者会收回所有的资金 。
我们来考虑一个发给某人的 HLTC 支付事务:
# 检查所提供的 R 是否为 H 的原像
HASH160EQUAL
IF
# 检查公开 R 的人是否为事务最初的接收者
CHECKSIG
ELSE
# 检查时间锁是否已终止
CHECKLOCKTIMEVERIFY
# 检查请求返回资金的是不是事务最初的发送者
CHECKSIG
ENDIF
在正确的 R(哈希值 H 的原像)公开之后 , 我们进入 IF 流程 , 进一步验证提供 R 的是不是这笔支付事务一开始的支付对象 。在花费这个输出时 , 接收方只需提供一个非常简单的解锁脚本:
如果解锁脚本所提供的 R 是错的 , 我们跳转入 ELSE 流程 , 首先验证时间锁解锁了没有 。如果时间锁已然解锁 , 发送者就可以收回所有的资金 。收回资金这个操作的解锁脚本也差不多 , 唯一的区别在于 , 为了进入 ELSE 流程 , 需要提供一个错误的秘密值:
当然 , 这只是 HTLC 的一个非常基础的实现 , 代表着一个普通的时间锁支付 。你可以在脚本中加入任意多的其它条件 , 比如说 , 在 IF 流程中移除公钥验证 , 这样只要知道秘密值 R 的人都可以使用这个输出;也可以在其中加入多签名限制 , 要求提供多个预设私钥的签名才能解锁 。
多说一句 , 在这个案例中 , 我们使用的操作码是CHECKLOCKTIMEVERIFY , 这个操作码使用绝对数值来定义时间锁 , 意思就像:“这个输出在区块 #546212 之前是无法动用的” 。而在闪电网络中 , 还用上了另一种时间锁 , 更 “灵活” 的一种:CHECKSEQUENCEVERIFY , 它用到的是相对数值 , 意思近于:“这个输出 , 在使用它的事务上链之后的 1000 个区块内 , 是无法使用的”(译者注:这里的数值都是例子 , 实践中当然可以使用别的数值) 。
闪电网络案例
现在 , 我们终于讲解完所有元素了 , 可以尝试理解闪电网络运作的全景了 。
我们假设现在闪电网络有 5 个参与者:Alice、Bob、Carol、Diana 和 Eric , 他们各自有一个支付通道相连 , 而每个通道的每一边都有 2 btc 的余额可用 。现在 , 我们尝试让 Alice 通过通道链条给 Eric 支付 。
深入解读闪电网络:HTLC 的工作方式与多跳支付的实现方式