在比特币网络中,每个用户的身份是通过公钥来识别的,由此实现了一定程度的用户的匿名性。那么,直觉上,自然而然地我们会认为每一笔交易是通过公钥来指明支付的对象,毕竟现在公钥就等价于用户的身份z号码。然而实际上并非如此,每一笔交易的输出实际上只是指明了一个脚本(script),通过脚本,间接地指明这笔交易会把多少比特币转给谁。那么为什么交易的输出不是直接用公钥来指明比特币的支付对象,而要通过脚本来指明呢?
实际上这是为了保证两点,其一,支付对象的匿名性;其二,所支付的比特币只能被支付对象所使用。举个例子,如下图所示,假如Alice在交易a的输出中,将十个比特币给了Bob,在交易b中,Bob又将这十个比特币转给了Carol,那么Alice在交易a中应该怎么做才能保证这十个比特币在后续的交易中只能被Bob使用,而不是被别人偷走?
Alice应该在交易输出中给出Bob的公钥哈希,并且要求,假如Bob要使用这个十个比特币,那就必须要提供Bob的公钥以及Bob的数字签名,只有当Bob给出的公钥的哈希与Alice给的相等,并且Bob的数字签名有效时,才能使用这十个比特币。为什么Alice不是在交易输出中直接指明Bob的公钥,而是指明Bob的公钥哈希?这是为了实现匿名性,具体原因可以参考这篇博客为何使用地址而不是公钥?。
当Alice在交易输出中使用Bob的公钥哈希时,Alice可以证明这笔支付是给了Bob;而当Bob在后续的交易公开给出公钥和他的数字签名时,可以向大家证明他是Bob,从而解锁Alice所支付的比特币,注意,Bob需要在后续交易中公开公钥,而不是简单地给出他的公钥哈希,这样才能让别人在验证他的数字签名是有效的同时,也证明上一次Alice所支付的地址的确是Bob的公钥哈希。Alice支付的过程就是通过给出输出脚本来实现的,而Bob解锁Alice所支付给他的比特币的过程则是通过输入脚本来实现的。当Bob要解锁Alice支付的比特币时,Bob会给出输入脚本,这个输入脚本会和Alice给出的输出脚本拼接到一起,组成一个完整的脚本,然后执行脚本,如果结果是True,那么就解锁成功,Bob的这次交易就能被成功地添加到区块中,否则这次交易无效,不会被添加到区块中。
比特币脚本语言结构从上面一节可以看出,Bob要完成一次交易,需要执行一个比特币脚本,该脚本由输入脚本(scriptSig)和输出脚本(scriptPubKey)两部分组成,输出脚本由Alice在之前的交易(交易a)的输出中给出,输入脚本则由Bob在本次交易(交易b)中给出。比特币脚本使用方法主要有以下几种。
P2PK (Pay to Public Key)P2PKH (Pay to Public Key Hash)P2SH (Pay to Script Hash)多重签名Proof of Burn在本文中介绍的例子将会使用第二种(P2PKH),这种是最常用的方法,有关其它方法的细节,可以参考比特币脚本原理和使用方法一文,这里不再细述。一个P2PKH输出脚本(scriptPubKey)的例子如下所示,在上面交易例子中由Alice在交易a的输出中给出,输出脚本里包含了Bob的公钥哈希(69e02e18…),以及一些 *** 作,后面会提到这些 *** 作。
OP_DUP
OP_HASH160
69e02e18...
OP_EQUALVERIFY
OP_CHECKSIG
一个输入脚本(scriptSig)的例子如下图所示,在上面的交易例子中由Bob在交易b的输入中给出。这里的输入由两部分组成,一是Bob用他自己的私钥对本次交易(即交易b)进行签名所得到的数字签名(sig, signature),另一部分就是Bob的公钥(pubKey, public key)。给出公钥主要有两个目的,一个是证明Alice在交易a中支付的对象的确是Bob,前面提到,Alice在交易a中只是给出了一个公钥哈希,但是并没有明确指明Bob的公钥,那么别人怎么能知道Alice给的这个公钥哈希就是Bob的公钥哈希呢?因此,为了证明这点,Bob需要在交易b公开他的公钥,然后取哈希,一旦得到的哈希与Alice给的相等,那就证明了Alice给的公钥哈希的确是Bob的公钥哈希,换言之,Alice这十个比特币的确是支付给Bob的。另外一个目的就是为了进行数字验签,Bob需要给出公钥,别人才能用他的公钥和数字签名进行验签,才能确认他的数字签名有效,即他的确是Bob。
<sig>
<pubKey>
Bob在进行交易b时,需要证明他是Bob,以解锁交易a输出中给Bob的十个比特币,这个证明的过程是通过执行脚本来实现的。Bob会将Alice在交易a输出中给出的输出脚本拼接到他给的输入脚本后面,组成一个完整的脚本,然后执行该脚本,拼接后Bob所执行的完整的脚本如下所示。
<sig>
<pubKey>
------------------------
OP_DUP
OP_HASH160
69e02e18...
OP_EQUALVERIFY
OP_CHECKSIG
脚本执行过程
比特币脚本所使用的语言是一门基于堆栈的语言,脚本的每一行要么是数据,要么是指令,执行过程从脚本的第一行开始,自上到下。如果是数据的话,就将其压入到堆栈中,如果是指令的话,就执行该指令。
还是以上面的例子来进行说明,当Bob在交易b要解锁Alice在交易a支付给他的十个比特币时,Bob需要执行上面的这个完整的比特币脚本,执行过程如下。
第一步,将Bob在交易b的输入脚本中给出的他对当前交易(即交易b)的数字签名上面的执行过程可以用下图表示,大家可以参考这张图,结合上面的描述来理解整个过程。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)