注:没有全部复原,抽取了主体知识,加入了一些自己的理解,强烈建议去学习肖臻老师的课程,这绝对算得上是国内区块链讲解的顶级教程,纯学术和技术
BTC使用的脚本语言是非常简单的,唯一能访问的内存空间就是一个堆栈 ,不像C,C++那样有全局变量和局部变量还有动态分配的内存空间
所以叫基于栈的语言
stack base language
看一下交易的宏观信息,
-
size:交易的大小
-
locktime:用来表示交易的生效时间,0表示立即生效,10表示10个区块之后才能写进区块里面
-
time:交易产生的时间
-
blocktime:区块产生的时间
-
输出最简单的形式就是给出一个Public Key
-
reqSigs:需要的签名数量
有一个交叉,后面的交易的输入要放在前面,前面的交易的输出要放在后面
早期的BTC脚本中这两个脚本是拼接在一起的,从头到尾执行一遍
出于安全因素的考虑,现在这两个脚本分开执行,首先执行输入脚本,如果没有出错,再执行输出脚本,
最后栈顶的结果为非0值,也就是true,那么验证通过 ,这个交易就是合法的,如果执行过程中出现任何错误,这个交易就是非法的
如果一个交易有多个输入脚本,那么所有的输入脚本都要与对应的输出脚本匹配之后来进行验证,全都验证通过这个交易才是合法的
输入输出的形式:
1.最简单的形式: P2PK,Pay to Pubic Key
输出脚本里直接给出收款人的公钥
CHECKSIG是检查签名的操作
输入脚本直接给出签名就可以,私钥对输入脚本所在的整个交易的签名
注:拼接起来,第一行是输入脚本,后两行是输出脚本,实际执行中是分开执行的,PPT是为了方便,拼接在一起显示
流程:
- 把输入脚本提供的签名压入栈中,
- 把输出的公钥压入栈,
- 把栈顶的两个元素弹出来,用公钥检查一下签名是否正确,如果正确返回TRUE,说明验证通过,否则出错
2.最常用的形式:P2PKH:Pay to Public Key Hash
与第一种的区别是输出脚本里没有直接给出收款人的公钥
给出的是公钥的哈希
公钥是在输入脚本里给出的
输入脚本既要给出签名也要给出公钥
输出脚本里的DUP,HASH160都是为了验证签名的正确性
流程:
- 把签名压入栈中
- 把公钥压入栈中
- DUP:含义是把栈顶的元素复制一遍,所以栈顶又多了一个公钥
- HASH160是把栈顶元素弹出来取哈希,然后把得到的哈希值再压入栈中,所以栈顶变成了公钥的哈希值
- 把输出脚本中提供的哈希值压入栈,这时栈顶有两个哈希值
- EQUALVERIFY是弹出栈顶的两个元素,即刚刚的两个哈希值,比较它们是否相等,防止有人冒名顶替(用自己公钥冒充接受者的公钥)
- 弹出栈顶的两个元素,用公钥检查签名是否正确
3.最复杂的形式:P2SH: Pay to Script Hash
输出脚本给出的是一个接收者提供的脚本的哈希,这个脚本叫redeemScriptHash,赎回脚本
输入脚本要给出赎回脚本的具体内容,同时要给出能让这个赎回脚本正确运行的签名
第一阶段步骤:
-
把输入脚本的签名压入栈
-
把赎回脚本压入栈
-
得到赎回脚本的哈希
-
将输出脚本的哈希值压入栈,RSH是指redeemsrcipt hash
-
判断两个赎回脚本的哈希值是否相等
第二阶段步骤:
- 将输入脚本里提供的序列化的赎回脚本进行反序列化,反序列化的操作由每个节点自己完成,并不在PPT中展示,之后执行赎回脚本,将Public Key压入栈
- 然后验证输入脚本里给出的签名的正确性
在传输前需要将数据结构转换成方便网络传输的 字节流 形式,这个过程称为 序列化
从字节流“恢复”数据成数据结构的形式,这个过程称为 反序列化
输出脚本中需要N个,输入脚本只需要提供M个合法签名就可以验证通过,N>=M,N>1/2M
输入脚本有一个BUG,执行的时候会从堆栈中多弹出一个元素,所以第一个为多余的元素
M个签名的顺序要在N个公钥中签名的顺序一致才可以
-
FALSE就是多余的元素
-
将输入脚本的两个签名压入栈中
-
将阈值M=2压入栈
-
将三个公钥压入栈
-
将N=3压入栈
-
执行CHECKMULTISIG,看看是不是符合多重签名
本质是将复杂度从输出脚本转移到输入脚本
步骤:
- FALSE还是应对那个BUG
- 两个签名压入栈
- 序列化的数据压入栈
- 取Hash
- 将输出脚本里面的RSH压入栈中
- 最后判断这两个赎回脚本的hash值是否相同
至此,第一阶段的验证就结束了,下面是第二阶段的验证
- 把M压入栈
- 将三个公钥压入栈
- 将N压入栈
- 检查多重签名的正确性
只有RETURN操作,后面的都不执行,无论输入的什么内容,到输出脚本就RETURN,不再执行任何操作
这个脚本是证明销毁BTC的一种方法
为什么要销毁BTC?
两种应用场景:
- 其余的系统会要求销毁一些来进行置换其自己的
- 往区块链里面写入一些内容,比如要存一个知识产权的HASH,就可以放到RETURN 后面的[zero or more ops or text]里面,虽然不会执行,但是如果出现纠纷,就可以使用它
发布消息不需要记账权,发布区块需要记账权,任何用户都可以使用这种方法销毁少量的BTC
这种操作对全节点是比较友好的,因为不需要写入UTXO中,手续费全部都用来写入脚本,输出为0
coinbase脚本里面也可以写东西【前面讲的】
OP_CHECKSIG,PPT里都省略了OP
BTC的脚本不支持循环,也就不会陷入死循环
不像以太坊是图灵完备的,但是其密码学的功能很强大,比如CHECKMULTISIG一句话就可以支持多重签名验证,所以比特币的脚本看上去很简单,但是针对比特币的应用场景做了很好的优化
因为不需要写入UTXO中,交易费用全部都用来写入脚本,输出为0
coinbase脚本里面也可以写东西【前面讲的】
OP_CHECKSIG,PPT里都省略了OP
比特币的script不支持循环,也就不会陷入死循环
不像以太坊是图灵完备的,但是其密码学的功能很强大,比如CHECKMULTISIG一句话就可以支持多重签名验证,所以BTC的脚本看上去很简单,但是针对BTC的应用场景做了很好的优化