问题的提出:比特币系统中并没有账户的概念,那么用户是怎么知道自己有多少钱并能花掉自己的bitcoin的,即进行bitcoin的交易呢?
问题的理解:在比特币系统的交易(也叫转账记录)中为了进行交易权限校验,即验证某人是否有权利动用发送给他的比特币,使用了脚本系统来进行权限验证。常用的权限验证方式例如利用公钥和签名进行,又或者例如多人投票机制等。
该脚本系统是一种简单的、基于堆栈的、从左到右处理的、非图灵完整的脚本系统,它比起以太坊、EOS等下一代区块链技术中使用的智能合约是要简单太多了,所以功能也比较有限。其本质是包含多个指令的列表,只要这些指令在逐个的运行过程中没有失败,一直到该指令列表中的指令都正常执行,那么表明交易有效,即该用户可以动用这个交易中发给他的比特币。只要在指令列表的指令执行过程中,有一个失败或异常,则表明交易无效,该用户无权动用这个交易中发给他的比特币,因为他可能是非法使用者。
脚本系统中常用的指令包括:
1.堆栈处理指令:OP_DUP(进行复制操作)、OP_DROP(删除栈顶元素)、OP_SWAP(栈顶的两个元素进行交换)
2.脚本流程控制指令:OP_RETURN(标记交易无效)\OP_VERIFY(如果栈顶元素为false,标识交易无效。如果为true,则交易有效)
3.加密签名指令:OP_HASH256(进行hash散列计算)、OP_CHECKSIGVERIFY(进行签名验证)、、等;
4.逻辑操作指令:OP_EQUAL(判断是否相等)、OP_EQUALVERIFY(判断是否相等后进行脚本流程控制判断,如果栈顶元素为false就标识交易无效)
5.算术操作指令:OP_ADD(加)\OP_SUB(减)\OP_MAX(取最大值)\OP_MIN(取最小值)等。
问题的解释:
下面我们以一个例子来形象的说明一下比特币的脚本系统的执行过程。
假设有下面一系列的交易执行过程,Alice交易了一些bitcoin给Bob,Bob又交易了一些bitcoin给Carol,Carol又交易了一些bitcoin给Dave。那么在交易b中,系统是如何验证Bob是有权将Alice转给他的bitcoin又转给Carol呢?
一个交易的数据结构包括三部分,HASH、输入交易和输出交易。如下图所示:
我们知道在每个交易中,其输入交易是包含了前一个交易的txid以及scriptSig,这个scriptSig就是验证用户是否有权花掉前一个交易中转给自己的比特币,
例如
在Bob->Carol的交易b中,Bob为了转账给Carol,必须在交易b的输入交易里提供足够的信息才能证明Bob是可以动用交易a中Alice转给Bod的bitoin,交易b的输入交易信息是和交易a的输出交易信息进行配对的,两者的执行成功才能证明Bob是合法的拥有者并且可以花掉交易a中转给他的bitcoin。
Bob为了转账给Carol,在交易b中提供输入交易的输入脚本scriptSig信息如下:
3046022100ba1427639c9f67f2ca1088d0140318a98cb1e84f604dc90ae00ed7a5f9c61cab02210094233d018f2f014a5864c9e0795f13735780cafd51b950f503534a6af246aca301
03a63ab88e75116b313c6de384496328df2656156b8ac48c75505cd20a4890f5ab
这么一长串其实就是一个签名和一个公钥。
与之对应的,是在交易a中的输出交易的输出脚本scriptPubKey信息了,其内容如下:
OP_DUP OP_HASH160be10f0a78f5ac63e8746f7f2e62a5663eed05788 OP_EQUALVERIFY OP_CHECKSIG
这么一长串其实就是一个指令的脚本列表,比特币系统将在脚本系统堆栈中逐个执行这些指令以验证权限。
下面看看是如何执行这组脚本来进行验证权限的。
第一步、执行交易b的输入脚本,因为是两个元素,一个签名和一个公钥,所以将这两个元素加入堆栈;
第二步、根据输入脚本引用的txid找到交易a的输出脚本,得到输出脚本的那个指令列表,逐个执行;
第三步、第一个指令是OP_DUP,表示复制操作,也就是对当前堆栈中的栈顶元素进行复制,那就复制一份吧
第四步、第二个指令是OP_HASH160,表示计算hash值,也就是对当前堆栈中的栈顶元素计算其hash值,那就将计算出来的hash值入栈
第五步、第三个指令是一组数字,所以将这个元素加入堆栈;
第六步、第四个指令是OP_EQUALVERIFY,表示检查是否相等,也就是从堆栈中取出最上面的两个元素,判断是否相等,如果相等就正常进行,如果不相等,则中断执行,返回失败。
第七步、第五个指令是OP_CHECKSIG,表示检查签名校验,也就是从堆栈中取出最上面的两个元素,判断其签名是否正确,如果相等就正常进行,如果不相等,则中断执行,返回失败。
这样,交易b的输入脚本和交易a的输出脚本所包含的一串指令列表执行下来,就可以验证Bob是否有权利动用交易a中转给他的bitcoin,即转账给Carol了。