【摘要】 多重签名交易允许同一笔交易输出需要多个私钥才能解锁,即锁定脚本设置条件,有N个公钥(注意不是公钥hash)被记录在脚本中,其中至少有M个必须提供签名才能解锁,也被成为M-N方案。
一、多重签名交易
多重签名交易允许同一笔交易输出需要多个私钥才能解锁,即锁定脚本设置条件,有N个公钥(注意不是公钥hash)被记录在脚本中,其中至少有M个必须提供签名才能解锁,也被成为M-N方案。N是密钥的总数,M是验证所需的签名数量。
锁定脚本一般的形式为:
M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG
锁定脚本示例:2-3多重签名条件
2 <Public Key A> <Public Key B> <Public Key C> 3 CHECKMULTISIG
解锁脚本示例:
0 <Signature B> <Signature C>
第一位需要补0是因为比特币代码的一个BUG,调用时会从堆栈上多取出一个数字,取出后它被立刻丢去,并不用于之后的运算。这个数具体是什么值无关紧要,可堆栈上不能缺失它,不然无法正常执行CHECKMULTISIG。修复该代码会引起比特币分叉,所以现在通过补0的方式来规避
最终实际的解锁脚本验证如下:
0 <Signature B> <Signature C> 2 <Public Key A> <Public Key B> <Public Key C> 3 CHECKMULTISIG
二、P2SH(Pay-to-Script-Hash)
多重签名会有如下问题:
1.交易臃肿,N个公钥都要包含在交易的输出中(锁定脚本中),增加了交易的大小同时增加了交易费用,另外还增加了矿工维护UTXO的负担。
2.付款用户必须根据你提供的所有公钥信息对交易中的锁定脚本进行定制,给支付带来极大的不便利。
此处展开一下分析多重签名为什么要进行定制,而P2PKH不需要呢?
1.P2PKH的锁定脚本包含的内容是公钥哈希,公钥哈希可以通过比特币地址解码得到,所以只要知道比特币地址就可以正常生成锁定脚本进行支付。
2.多重签名锁定脚本需要包含N个公钥,不可能从单一的地址得到所有的公钥,所以锁定脚本必须定制。
P2SH的出现即是为了解决多重签名存在的这些问题,P2SH增加赎回脚本(Redeem Script)概念,P2SH脚本内容示例:
赎回脚本: 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
锁定脚本: HASH160 <20-byte hash of redeem script> EQUAL
解锁脚本: Sig1 Sig2 <redeem script>
从脚本内容可以看到,锁定脚本从原来的多重签名锁定脚本变成了原脚本的哈希,而赎回脚本内容即为原来的多重签名锁定脚本内容,解锁脚本中增加了赎回脚本的内容。
所以执行的情况变成如下:
1.先对比解锁脚本中的赎回脚本内容哈希与锁定脚本中是否一致
Sig1 Sig2 <redeem script> HASH160 <20-byte hash of redeem script> EQUAL
2.如果上面的对比结果一致,则变成执行如下内容(回到了多重脚本验证的情况)
Sig1 Sig2 2 PubKey1 PubKey2 PubKey3 PubKey4 PubKey5 5 CHECKMULTISIG
注:P2SH会使用P2SH地址,地址的内容即为赎回脚本哈希的base58check编码结果,P2SH地址版本前缀为0x05,编码后地址以“3”开头,如下
P2SH的好处:
1.锁定脚本简化,减小了交易的空间占用
2.P2SH地址使付款人无需关心复杂的操作,只需向地址支付即可
3.P2SH使多重签名脚本的负担转移到收款人身上,而不是付款人
(1)多重签名导致的交易大小扩大仍然存在,只是由锁定脚本转移到了解锁脚本上。
(2)只有当需要解锁P2SH地址上的比特币进行付款时才会发生,延迟了占用较多空间交易发生的时间。
(2)交易大小导致的交易速度减慢,交易费增加等负担转移到收款人承担。
三、数据记录输出(RETURN)
比特币去中心化分布式数据库的特性,使许多开发者开始利用交易脚本作出除支付以外的尝试,如数字公证服务、证券证明、智能合约等。基于上面的需求,RETURN命令出现,该命令可以用于范围特定的数据,并记录到比特币区块链当中作为永久保存,它有如下特点:
1.使用RETURN命令的输出无法被用于支付,所以不应该包含比特币在RETURN输出中,尝试包含RETURN的输出作为输入的交易会被认为无效。
2.RETURN的数据量大小限制为80bytes,通常包含hash值(如SHA256结果)与服务内容的前缀(如Proof of Existence的前缀为8-byte DOCPROOF)。
3.使用RETURN的输出不会被存储在矿工的UTXO集中,避免了内存占用,但是会写入到区块链中。
RETURN脚本示例
scriptPubkey:RETURN <data>
scriptSig:
从脚本可以看到通常输入脚本为NULL
四、时间锁(Timelock)
时间锁主要用于延迟支付,即指定某笔交易或UTXO在某一个区块高度或时间戳才进行支付或可以被使用。
1.交易时间锁(nLocktime)
比特币的交易中存在"locktime"参数,用于表示该笔交易在何时被广播到比特币网络中
0 < locktime < 500million:代表区块高度(block height)
locktime >= 500million:代表时间戳(从1970-1-1开始的Unix时间戳)
交易时间锁的特点:
交易时间锁要求该笔交易在指定时间后才向全网广播,所以在时间到达前该交易并不计入区块链中。导致如果在时间到达前付款人发起另一笔交易,双重支付并产生同一笔输入,则实际上前一笔交易会失效,这使收款人没有任何保障。
但是由于这个特性,给了付款人考虑时间,如果付款人对于交易后悔,可以防止该交易生效。
2.检查锁定时间验证(Check Lock Time Verify(以下简称CLTV))
CLTV是一种基于UTXO的时间锁,通过在P2SH赎回脚本(redeem script)中添加CHECKLOCKTIMEVERIFY命令对时间进行校验。将时间锁写入脚本中就保证了UTXO被锁定,在锁定时间到达前没有人可以使用该UTXO。
CLTV赎回脚本示例:
<Block height or Time> CHECKLOCKTIMEVERIFY DROP DUP HASH160 <Bob's Public Key Hash> EQUALVERIFY CHECKSIG
当要解锁前,需要先校验<Block height or Time>,如果校验成功,删除<Block height or Time>,正常执行解锁脚本。
如下情况将导致校验失败:
1.堆栈是空的
2.<Block height or Time>小于0
3.顶层堆栈项(<Block height or Time>)和nLocktime字段的锁定时间类型(区块高度或者时间戳)不相同
4.顶层堆栈项大于交易的nLocktime字段
5.输入的nSequence字段为0xffffffff
从失败情况可以发现,在CLTV交易中,nLocktime字段仍然要设置,并且要大于CLTV时间,时间类型需要保持一致。
到这里我们已经将比特币上主要的高级交易类型学习完了,随着时间的推移,比特币脚本的能力会被进一步挖掘,比特币将通过脚本进一步向区块链”平台“发展。
有兴趣可以去https://blockchain.info 查看一下区块中的信息,如果看见类似下面这种无法解码的output,说明不是标准的交易,很可能就是用于货币以外的其他用途了。
作者:Aaron