检查锁定时间验证(OP_CLTV)

2015年12月,一种新形式的时间锁被引入比特币作为软分叉升级。根据BIP65规范,新增了一个名为OP_CHECK LOCKTIMEVERIFY(OP_CLTV)的脚本操作符。OP_CLTV是一种基于输出的时间锁,而不是基于交易的时间锁,这与锁定时间不同。这样做可以增加时间锁的应用灵活性。

简单来说,通过在输出中使用OP_CLTV操作码,该输出受限制,只能在指定的时间过去后才能花费。

OP_CLTV并不取代锁定时间,而是限制特定的UTXO,使它们只能在具有设置为大于或等于指定值的锁定时间的未来交易中花费。

OP_CLTV操作码接受一个参数作为输入,以与锁定时间相同的格式表示(可以是区块高度或Unix纪元时间)。如同VERIFY后缀所示,OP_CLTV是一种如果结果为FALSE就会停止脚本执行的类型的操作码。如果结果为TRUE,则继续执行。

要使用OP_CLTV,您需要将其插入到创建输出的交易中输出的赎回脚本中。例如,如果Alice要支付Bob,他可能通常会接受以下P2SH脚本支付:

<Bob's public key> OP_CHECKSIG

为了将其锁定到一个时间,比如说从现在开始的3个月后,他的P2SH脚本将改为:

<Bob's pubkey> OP_CHECKSIGVERIFY <now + 3 months> OP_CHECKLOCKTIMEVERIFY

其中 <now + 3 months> 是一个块高度或时间值,从交易被挖掘时起预计的3个月后的值:当前块高度 + 12,960(块)或当前 Unix 时间 + 7,760,000(秒)。

当 Bob 尝试花费这个 UTXO 时,他构造一个引用该 UTXO 作为输入的交易。他在该输入的输入脚本中使用他的签名和公钥,并将交易锁定时间设置为等于或大于 Alice 设置的 OP_CHECKLOCKTIMEVERIFY 的 timelock。然后 Bob 将交易广播到比特币网络。

Bob 的交易如下评估。如果 Alice 设置的 OP_CHECKLOCKTIMEVERIFY 参数小于或等于花费交易的锁定时间,则脚本继续执行(就好像执行了无操作或 OP_NOP 操作码一样)。否则,脚本执行停止,并且交易被视为无效。

更确切地说,BIP65 解释了如果发生以下情况,OP_CHECKLOCKTIMEVERIFY 将失败并停止执行:

• 栈为空。

• 栈顶项小于 0。

• 栈顶项的锁定时间类型(高度与时间戳)与锁定时间字段不相同。

• 栈顶项大于交易的锁定时间字段。

• 输入的序列字段为 0xffffffff。

时间锁冲突

OP_CLTV和lock time使用相同的格式来描述timelocks,即块高度或自Unix纪元以来经过的秒数。关键是,当两者一起使用时,锁定时间的格式必须与输出中的OP_CLTV匹配——它们必须都引用块高度或以秒为单位的时间。

这意味着如果脚本必须执行两次不同的OP_CLTV调用,一次使用高度,一次使用时间,那么该脚本永远不会有效。在编写高级脚本时可能会犯这种错误,因此请务必在测试网络上彻底测试您的脚本,或者使用专为防止此问题而设计的工具,例如Miniscript编译器。

另一个影响是,在交易的任何脚本中只能使用一种类型的OP_CLTV。如果一个输入的脚本使用高度类型,而另一个输入的不同脚本使用时间类型,那么就无法构建一个有效的交易来花费这两个输入。

在执行后,如果OP_CLTV得到满足,那么它之前的参数将保持为堆栈中的顶部项目,并且可能需要使用OP_DROP将其移除,以便正确执行后续的脚本操作码。出于这个原因,您经常会看到脚本中的OP_CHECKLOCKTIMEVERIFY后面跟着OP_DROP。OP_CLTV和OP_CSV(参见“相对Timelocks”)不同于其他CHECKVERIFY操作码,因为它们保留了堆栈上的项目。这是因为引入它们的软分叉重新定义了旧的操作码,而这些旧的操作码不会丢弃堆栈中的项目,因此必须保留这些以前的无操作(NOP)操作码的行为。

通过将锁定时间与OP_CLTV结合使用,页面158中描述的情景将发生改变。“交易锁定时间限制”中所述的情况。Alice立即发送她的交易,将资金分配给Bob的密钥。Alice不再能够花费这笔钱,但Bob在3个月的锁定时间到期之前也不能花费它。

通过直接将Timelock功能引入脚本语言,OP_CLTV使我们能够开发一些非常有趣的复杂脚本。该标准在BIP65(OP_CHECKLOCKTIMEVERIFY)中定义。

Last updated