在比特币交易浏览器(Block Explorer for Bitcoin, Ethereum, Litecoin and More | BlockCypher)上面 随机找一个交易实例.
能够观察到 交易有一个输入两个输出,交易输入中交易者转给地址bc1qyajmwnf8nvqgaagphxuz6nwrf6rcya29gnaan5了0.0013BTC,并给自己找零转回了0.00141605 BTC
具体input、output信息:
"inputs": [
{
"prev_hash": "ca115a875a5e74f24829b6bffc3ef395d07f87f9bbafb9fb6916d78c1d6fea0e",
"output_index": 33,
"output_value": 277245,
"sequence": 4294967295,
"addresses": [
"bc1qxmhk0njy28kn8pp4dq33xjct7h55rlxxvygnq5"
],
"script_type": "pay-to-witness-pubkey-hash",
"age": 828154,
"witness": [
"3045022100975b6371addc4930ae96f04eb03dac46b99193891c75542ce5112ededfda62be02207b13df4e483ff777c22e509abc2e92f611f7939a7e083095c5aa2a9290e64c0801",
"03d184fad72722afe0a7e3a818d59596d8d0702c4e0d0ce3501ffb50f778283431"
]
}
],
"outputs": [
{
"value": 130000,
"script": "00142765b74d279b008ef501b9b82d4dc34e87827545",
"addresses": [
"bc1qyajmwnf8nvqgaagphxuz6nwrf6rcya29gnaan5"
],
"script_type": "pay-to-witness-pubkey-hash"
},
{
"value": 141605,
"script": "001436ef67ce4451ed3384356823134b0bf5e941fcc6",
"addresses": [
"bc1qxmhk0njy28kn8pp4dq33xjct7h55rlxxvygnq5"
],
"script_type": "pay-to-witness-pubkey-hash"
对于输入(inputs):
witness
字段包含了解锁脚本的数据,这是一系列的数据,用于证明交易发起者有权从之前的交易中花费那些比特币。script_type
字段表明了脚本的类型,这里是"pay-to-witness-pubkey-hash"(P2WPKH),它允许直接支付到一个公钥的哈希而不是整个公钥本身。
对于输出(outputs):
script
字段包含了锁定脚本的数据,这是一系列的数据,用于指定谁可以花费这个输出。在这个例子中,输出的script
字段包含了一个哈希值,这个哈希值对应于可以花费这些比特币的收款人的公钥。script_type
也是"pay-to-witness-pubkey-hash",意味着这个输出可以被拥有相应私钥的人花费。
比特币脚本
比特币脚本是一个基于栈的语言,在本节的脚本语言为了简洁 都没有加入 OP_ 前缀
在转帐中,A->B.B->C(,B使用的是A->B的UTXO)
这个时候 会将转账给B的output script(这个脚本主要是是PUSHDATA(PubKey)、CHECKSIG,指定了转给哪个地址)
和B转给C的input script(用签名进行验证自己是这个UTXO的接收者)进行拼接在一起验证 拼接形式如下:
input script | output script
1.Pay to Public Key (P2PK)
形式:
进行拼接之后
PUSHDATA(Sig)来自输入脚本 PUSHDATA(PubKey)、CHECKSIG来自输出脚本。
过程:
1. 首先将输入脚本的签名压入栈
2. 将输出脚本中的公钥压入栈
3. 将栈顶的元素弹出来,用公钥检查签名是否正确
正确返回true,否则执行出错,交易非法
2.Pay to Public Key Hash (P2PKH)
P2PKH和P2PK的区别在于,没有直接给出收款人的公钥 而是直接给出哈希,公钥是在输入脚本中给出的(既有签名又有公钥)
形式:
过程:
1.将签名压入栈
2.将公钥压入栈
3. 把栈顶的元素复制一遍 栈顶 增加一个公钥
4.栈顶元素弹出来取hash,将得到的hash值再次压入栈(将刚刚复制的公钥变成公钥哈希值)
5.将输出脚本中的公钥hash值压入栈
6.弹出栈顶的两个元素 对比是否相等 (也就是对比输入和输出脚本的公钥hash是不是一样的,防确定是持有者的公钥)
7.检查签名是否正确
在验证的时候 任何过程验证失败都不能通过验证,代表这个交易是非法的
3.Pay to Script Hash(P2SH)
这种形式的输出脚本是收款人提供的脚本的hash,脚本名为redeemScript。
验证时分为两步:
1.验证输入脚本给出的赎回脚本是不是和输出脚本中的给出的hash值匹配,不匹配说明给出的赎回脚本是不对的。
2.如果赎回脚本是正确的,还需要将赎回脚本的内容当作操作指令再执行一次,并观察是否能执行
如果两个验证都通过了,这个交易才是合法的。
用P2SH实现P2PK
形式:
第一阶段的验证
PUSHDATA(Sig)
PUSHDATA(seriRS) //input
HASH160 //output
PUSHDATA(RSH)
EOUAL
过程:
将输入脚本和输出脚本拼接在一起
1.将签名压入栈
2. 将赎回脚本压入栈
3.取出赎回脚本并取hash,得到赎回脚本的hash并压入栈
4. 将输出脚本中的赎回脚本hash值压入
5.验证是否相等,相等则当前栈只剩签名了 一阶段验证结束
第二阶段的验证
PUSHDATA(PubKey)
CHECKSIG
过程(执行赎回脚本)
注意 当前栈顶有签名(第一阶段)
1. 将公钥压入栈中
2.通过公钥验证签名
验证成功则完成
用P2SH实现多重签名
多重签名
执行脚本为
用P2SH实现多重签名,是将输出脚本中的复杂度转到赎回脚本中
脚本执行过程1(输入脚本和输出脚本拼接)
FALSE
PUSHDATA(Sig 1)
PUSHDATA(Sig 2)
PUSHDATA(seriRS)
HASH160
PUSHDATA(RSH)
EOUAL
过程
1.执行压入false入栈(针对于bug需要,实际不怎么用这个元素)
2-3.依次压入两个签名入栈
4.序列化的赎回脚本入栈
5.对赎回脚本取hash 并压入栈
6.赎回脚本hash值入栈
7.判断赎回脚本的hash是否相等
现在栈中 sig_2 | sig_1 | False
脚本执行过程2 赎回脚本
2
PUSHDATA(pubkey 1)
PUSHDATA(pubkey 2)
PUSHDATA(pubkey 3)
3
CHECKMULTISIG
检查多重签名的正确性 只要包含这个三个公钥中两个正确的签名就能够完成这次交易
Proof of Burn
假如有一个交易的input指向这个output,不论input里的input script如何设计,执行到RETURN命令之后都会直接返回false,不会执行RETURN后面的其他指令,所以这个output无法再被花出去,其对应的UTXO也就可以被剪枝了无需保存。
这个脚本是证明销毁比特币的一种方法,所有节点、用户均可使用,写入内容