08 BTC-脚本
08 BTC-脚本
比特币使用的脚本语言是非常简单的,唯一能访问的内存空间,就是一个堆栈,叫做基于栈的语言。
上图Output Scripts有两个,分别对应每个输出。
交易的结构:
交易的输入:
上述代表一个交易输入。
比特币中的一个交易可能需要多个签名,因为有多个交易的输入。
交易的输出:
交易脚本的拼接:
之前,交易的执行是输入脚本和输出脚本拼接起来,一起执行。后来出于安全考虑,改为输入脚本和输出脚本分别执行,首先执行输入脚本,如果没有出错,在执行输出脚本,如果能顺利执行,最后栈顶的结果为非0值,也就是true,验证通过,那么这个交易就是合法的。如果执行过程中,验证出现任何错误,那么交易就是非法的。
如果一个交易有多个输入的话,每个输入脚本都要和所对应的交易的输出脚本匹配之后来进行验证,全部验证通过,交易才是合法的。
脚本形式:
第一种(最简单):
为了安全执行,脚本是分别执行的。
CHECKSIG 把栈顶的元素弹出来,用公钥检查签名是否正确。如果正确返回true,否则非法。
实例:
第二种(最常用):
交易输出脚本,其中地址存放的是转账的公钥的hash。
目的:防止有人冒名顶替,用自己的公钥代替收款人的公钥。
示例:
第三种:
输出脚本给出的不是第二种形式的,收款人的公钥的hash,而是收款人提供的一个脚本的hash,脚本叫做redeemScript(赎回脚本),将来花这笔钱的时候,输入脚本需要给出赎回脚本的具体内容,同时还要给出让赎回脚本能够正确运行所需要的签名。
第二阶段,执行赎回脚本。
疑问:为什么第三种这么复杂?要把功能嵌入到赎回脚本中?
最初版本的比特币中是没有的,后来通过软分叉的形式加进去,应用场景,对多重签名的支持。比如:公司账户,需要有5个账户,需要3个人的签名才能把钱取走。
可以通过设置 M 和 N 的值,来进行验证,比如 N=5, M=3。
输入脚本的第一行,有个 ❌,比特币中 CHECKMULTISIG的实现,有一个bug,执行的时候,会从堆栈中多弹出一个元素,这个bug现在已经没有办法改了,因为是个中心化的系统,要改的话,需要硬分叉。实际的解决方法,在输入脚本中往栈上多压进去一个 ❌,没用的元素。
另外,输入中的签名顺序和输出中的公钥顺序要一致才行。
3个签名中给出2个就行。
CHECKMULTISIG操作,看看堆栈中的元素是不包含3个签名中的两个,如果是的话,验证通过。
上述原生的多重签名的实现有什么问题吗?
不是很方便,转账的时候,输出脚本中需要给出五个公钥,M=5 和 N=3,不同的电商采用不同的多重签名的技术,给用户生成转账交易带来不方便的地方。所以需要用到P2SH。
好处:将复杂的地方从输出脚本转移到了输入脚本。收款人只要在网站上公布赎回脚本的hash值,转账人只需要在转账的时候,只需要输出脚本中包含赎回脚本的hash值就行。
第一阶段验证:
第二阶段验证:
现在的多重签名一般都是用P2SH的形式。
最后一种脚本:
RETURN:无条件返回错误,所以包含操作的脚本,永远不可能通过验证。
这样比特币就永远都花不出去。这个是销毁比特币的一种方法。
为什么要这样做呢?不是非常可惜?
应用场景:
一、小的币种,要求销毁一定数量的比特币,才能得到这个币种。这种小币种叫AltCoin(Alternative Coin)。
二、往区块链中写入一些需要永久保存的内容:比如,知识产权的内容的hash值(不会占太大的地方,而且也不会泄露知识产权的内容,将来如果出现纠纷,可以将具体内容公布出去)。【注:比特币中写入数据,① CoinBase交易(全节点可写) ② RETURN脚本(任何人都可以写入数据)】
矿工知道输出中包含RETURN之后,就没有必要将其保存在UTXO中,这样对全节点比较友好。
补充:为了简单起见,都没有加上前缀,比如:CHECKSIG 为 OP_CHECKSIG。
比特币使用的脚本语言是非常简单的,叫做比特币脚本语言。以太坊中使用solidity,是图灵完备的,所以需要gas。
比特币的脚本的设计是由用意的,不支持循环,就不会有死循环,就不用担心停机问题。其实,是最适合比特币的脚本语言。