时间锁功能让比特币交易拥有了时间维度,这篇文章介绍时间锁的详细内容。
nLocktime
回忆一下比特币交易的结构。
通过最后 4 字节的nLockTime字段,可以实现交易粒度的时间锁。
nLockTime = 0,表示这笔交易没有时间锁定,可以被“随时”写入账本,“即时生效”
nLockTime < 500,000,000,指示块高度,这笔交易在块高度nLockTime之后,才可以被写入账本
nLockTime >= 500,000,000,指示具体的 Unix 时间戳,这笔交易在 Unix 时间戳nLockTime之后,才可以被写入账本
Unix 时间戳是一种时间表示法,它的值,表示从1970年1月1日 0时0分0秒 UTC开始,经历的秒数。
设想这样的需求,父亲想立个遗嘱,在自己去世后,儿子可以拥有自己所有的比特币,并需要保证:
父亲在世时,可以随时修改遗嘱
父亲过世后,儿子确定可以拿到币
设置交易的nLockTime字段,可以满足这样的遗嘱需求。
父亲计算出自己 80 岁时的 Unix 时间戳,值为T
父亲构造一笔 P2PKH 交易,将自己所有的比特币,付款到儿子的公钥哈希,并设置交易nLockTime字段的值为T
父亲用自己的私钥,对这笔交易签名(设置正确的解锁脚本),将签名后的交易数据交给儿子
这笔交易是合法的,但因为时间锁的设置,即使向网络“展示”这笔交易,它也不会被提前写入账本。转账不会在父亲 80 岁前发生,即儿子不会在父亲 80 岁前拿到这笔钱。
如果父亲去世时没到 80 岁,儿子也可以在未来,在父亲 80 岁这天之后,向网络“展示”交易,拿到这笔钱。
如果父亲想修改遗嘱,只需要:
将所有比特币先转到自己的另一个公钥哈希上,即时生效
重新按照自己的意愿,构造交易并设置nLockTime,签名后分发
完成操作后,之前那笔签名过的交易会变得无效,因为对应的 UTXO 已经被消费。
一般的,Alice 签名了一笔交易,付款到 Bob 的公钥哈希,并将交易的nLocktime设为三个月后。Alice 把这笔交易发送给 Bob,此时,两人都知道:
在三个月过去之前,Bob 不会收到这笔钱
这三个月内,Alice 可以随时构造另外的交易,即时生效,消费同样的 UTXO,即 Alice 可以在这三个月内,随时花费付给 Bob 的这笔钱
Bob 无法保证 Alice 不这么做
这正是nLocktime的局限性。nLocktime唯一能保证的,是这笔交易在时间锁释放之前,无法被写入账本,即收款人无法在时间锁释放之前,收到资金。
交易粒度的nLocktime时间锁,只在下列情况满足时,才会释放。
nLocktime = 0,没有时间锁
nLockTime < 500,000,000,且当前的区块高度,已经超过了nLockTime的值
nLockTime >= 500,000,000,且当前的 Unix 时间戳,已经超过了nLockTime的值
OP_CHECKLOCKTIMEVERIFY
为了改善交易nLocktime时间锁的局限性,有更细粒度的控制,时间锁需要跟 UTXO 关联,即放到锁定脚本中。
2015年12月,BIP-65 引入操作码OP_CHECKLOCKTIMEVERIFY(CLTV,Check Lock Time Verify),来实现 UTXO 粒度的时间锁定。
对一般的 P2PKH,其锁定脚本为
OP_DUP OP_HASH160 [公钥哈希] OP_EQUALVERIFY OP_CHECKSIG
如果一个 UTXO 的锁定脚本形如
[过期时间] OP_CHECKLOCKTIMEVERIFY OP_DROP OP_DUP OP_HASH160 [公钥哈希] OP_EQUALVERIFY OP_CHECKSIG
我们说,这是一个被CLTV锁定的 UTXO,只能在锁定脚本中的CLTV时间锁释放后才可以被消费。
其中,[过期时间]与交易的nLockTime字段有相同的格式,指示一个区块高度(< 500,000,000),或一个 Unix 时间戳(>= 500,000,000)。
即,只有在当前区块高度超过[过期时间],或当前 Unix 时间戳超过[过期时间]时,CLTV时间锁才会释放,这个 UTXO 才可以被消费。
逻辑上CLTV很好理解,但其工作方式稍显复杂,具体在 BIP-65 里定义,这里也做个说明。
如果一笔交易要消费CLTV锁定的 UTXO,需要同时满足下列所有条件。
这笔交易(消费这个 UTXO 的)输入的nSequence字段的值,必须小于0xffffffff
这个 UTXO 锁定脚本中[过期时间]的值,必须大于等于0
这笔交易的nLockTime和这个 UTXO 锁定脚本中的[过期时间],必须同时大于等于500,000,000或同时小于500,000,000,即要么都指示 Unix 时间戳,要么都指示区块高度
这笔交易的nLockTime字段的值,必须大于等于这个 UTXO 锁定脚本中[过期时间]的值
你能看到,交易要消费CLTV锁定的 UTXO,还需要配合使用nLockTime字段。
这些条件组合有些复杂,与当前区块高度或当前 Unix 时间戳,好像并没有什么关系。
让我们换个角度看,着重关注最后一个条件。对一笔交易,
为了保证交易能“即时生效”,你需要将nLockTime的值,设置为小于等于当前的区块高度或小于等于当前的 Unix 时间戳,否则这笔交易不会被写入账本
为了满足上述最后一个条件,你需要将nLockTime的值,设置为大于等于锁定脚本中[过期时间]的值,否则时间锁不会释放
对于使用nLockTime字段的交易时间锁与使用CLTV操作码的 UTXO 时间锁,
这两种时间锁都是指定某个具体的绝对时间点为过期时间的绝对时间锁。
nSequence
nSequence字段最初被设计为,标识某些还未被写入账本(仍在内存池中)的交易,允许它们在之后被更新。
如果某个交易的输入,其nSequence字段的值,小于0xffffffff,表示这笔交易尚未“确定”,还不是最终版本
这笔交易会被暂时搁置,等待被另一个消耗了同样输入的,并且有一个更大nSequence值的交易替换
直到收到消耗了同样输入的、nSequence值为0xffffffff的交易,才认为这笔交易已经准备就绪,可以随时被写入账本
但这个功能没有实现,从未在系统中使用过。
BIP-68 通过复用交易输入的nSequence字段,实现交易粒度的相对时间锁。
相对时间的意思是,从被引用的交易写入账本后,经过的时间。
高度 10,000 的区块中有一笔交易,创建了一个 UTXO
你现在创建一笔新交易消费这个 UTXO,并设置新交易输入nSequence字段的值为 100 个区块
那么,这笔新交易不会被写入账本,除非当前区块高度已经达到或超过 10,100。
nSequence是输入的一个字段,交易可以包含多个输入。
只有在满足了所有输入上的nSequence相对时间锁(如果有)要求后,交易才被认为合法,才会被写入账本。
根据 BIP-68 的设计,如果nSequence字段的值小于 ,即小于0x80000000,表示启用了nSequence相对时间锁
OP_CHECKSEQUENCEVERIFY
通过 BIP-112 引入的操作码OP_CHECKSEQUENCEVERIFY(CSV,Check Sequence Verify),可以实现 UTXO 粒度的相对时间锁定。
锁定脚本形如
复制
[过期时间] OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 [公钥哈希] OP_EQUALVERIFY OP_CHECKSIG
|<---------------CSV时间锁--------------->|
简单的说,被CSV锁定的 UTXO,从创建它的交易被写入账本开始计时,只有在经过一定的秒数或一定的区块数后,这个 UTXO 才可以被消费。
与CLTV类似,在消费一个CSV锁定的 UTXO 时,要求满足下列所有条件。
交易的nVersion字段的值,必须大于等于2
输入的nSequence字段的值,必须小于0x800000000
锁定脚本中[过期时间]的值,必须大于等于0且小于0x800000000
输入的nSequence和锁定脚本中的[过期时间],要么都指示秒数,要么都指示区块数
输入的nSequence的值,必须大于等于[过期时间]的值
总结
这篇文章介绍了四种比特币交易时间锁:
基于交易粒度的nLockTime绝对时间锁,在达到指定的区块高度或具体的 Unix 时间戳前,这笔交易不会被写入账本
基于交易粒度的nSequence相对时间锁,这笔交易不会被写入账本,除非其输入引用的那笔已经被写入账本的交易,经过了指定的时间或区块数
基于 UTXO 粒度的CLTV绝对时间锁,在达到指定的区块高度或具体的Unix时间戳前,这笔 UTXO 无法被消费
基于 UTXO 粒度的CSV相对时间锁,在创建这个 UTXO 的交易写入帐本后,除非经过了指定的时间或区块数,否则这个 UTXO 无法被消费
网友评论