08 BTC-脚本

发布时间 2023-05-02 12:35:42作者: YangYi215

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。

比特币的脚本的设计是由用意的,不支持循环,就不会有死循环,就不用担心停机问题。其实,是最适合比特币的脚本语言。