第10课 交易安全性如何保证? -- scriptSig/scriptPubKey/Script Engine

在前面第8课 账号相关概念:公钥/私钥/Public Key Hash/P2PKH我们讲公/私钥的时候,说过:A给B转账的时候,会先用A的私钥进行签名,再转账给B的公钥。

这个过程,说明了2件事:用A的私钥签名,证明了这笔钱是A的;转账给B的公钥,证明了这笔钱是转给B的,不是转给别人的。

接下来,B要花这笔钱,比如转给C;同样的,要用B的私钥签名,转账给C的公钥。

下面就来详细的分析一下1个Transaction的内部结构,看看究竟都是如何用私钥签名的,又是如何转账给公钥的。

交易的详细结构

下图是用的比特币的命令行工具getrawtransaction来详细展示了1个Transaction ID为028cfae228f8a4b0caee9c566bd41aed36bcd237cdc0eb18f0331d1e87111743的交易的

内部结构:

该交易有3个输入(vin里面),2个输出(vout)。

我们会看到,每1个vin里面,都有1个txid字段,1个vout字段,这2个字段合在一起也就组成了我们上节课所说的UTXO。1个UTXO = 1个Transaction Id + output Index。

scriptSig字段就是我们所说的,私钥的签名。

每1个vout,有1个字段value,字段n,字段scriptPubKey。

value就是转账给对方的钱数,n是output里面的编号(也就是下1次花费这个UTXO时,对应的vin里面的字段vout)。

scriptPubKey就是我们所说的,对方的公钥。

scriptSig详细解释

scriptSig里面有asm和hex2个字段,都是什么意思呢?

上面的vin里面,第1个输入,这2个字段的值,分别为:

“asm” : “3044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c095030c12431a4d524902

2055523130a9d0af5fc27828aba43b464ecb1991172ba2a509b5fbd6cac97ff3af01

048aefd78bba80e2d1686225b755dacea890c9ca1be10ec98173d7d5f2fefbbf881a6e918f3b05

1f8aaaa3fcc18bbf65097ce8d30d5a7e5ef8d1005eaafd4b3fbe”,

“hex” : “473044022055bac1856ecbc377dd5e869b1a84ed1d5228c987b098c

095030c12431a4d5249022055523130a9d0af5fc27828aba43b464ecb1991172

ba2a509b5fbd6cac97ff3af0141048aefd78bba80e2d1686225b755dacea890c9ca1be10ec

98173d7d5f2fefbbf881a6e918f3b051f8aaaa3fcc18bbf65097ce8d30d5a7e5

ef8d1005eaafd4b3fbe”

细心的读者会发现,这2个字段的值其实是一样的,只是hex在开头插入了字符47,中间插入了一个字符41,其他部分完全一样。

asm为assembly(拼装,或者汇编的意思),hex为其16进制的表达。

所以呢,这里的asm和hex就是同1个东西,里面包含了2部分:

signature(付款人的私钥的签名) + pub key(付款人的公钥),以41这个字符隔开。

scriptPubKey详细解释

scriptPubKey里面有asm, hex, reqSigs(暂时忽略), type, address几个字段。

同样,asm和hex当中同1个意思,只是不同的编码格式;

type: 也就是前面我们说的P2PKH,Pay to Public Key hash;

address: 也就是对方的收款地址,或者说钱包地址。

第1个vout的scriptPubKey的值如下:

OP_DUP OP_HASH160 634228c26cf40a02a05db93f2f98b768a8e0e61b

OP_EQUALVERIFY OP_CHECKSIG

address值为:

“1A3q9pDtR4h8wpvyb8SVpiNPpT8ZNbHY8h”

这2者是什么关系呢? scriptPubKey的格式,看起来很奇怪,OP_DUP, OP_HASH160,都是啥???

这就是接下来要讲的script Engine.

Script Engine

单纯的看scriptPubKey是看不懂的,我们需要把scriptPubKey和下1个,要花费它的交易的scriptSig,拼接在一起来看。

scriptPubKey代表的是收款人的公钥信息;下1个要花费这个UTXO的交易里面的vin,必然有该公钥对应的私钥的前面信息,也就是scriptSig。

2部分拼接在一起,scriptSig在前,scriptPubKey在后(注意:scriptPubKey是当前交易的,scriptSig是下1个交易的,要花费这个UTXO的),就长这个样子:

OP_DUP OP_HASH160 634228c26cf40a02a05db93f2f98b768a8e0e61b

OP_EQUALVERIFY OP_CHECKSIG

其中,signature, pub key 这2部分的内容,就类似上面的vin里面的asm部分,因为字符串太长了,此处就省略了,用 代替。

上面这串东西,就是1个script,1个简单的DSL语言(关于什么是DSL,自己百度之)。

这串script,被丢进Script Engine里面执行,执行结果就是TRUE/FALSE,表示这个人有没有资格花这笔钱,或者说这笔交易是否有效。

Script Engine是一个基于栈的脚本解释器,下面就来详细解释一下这串脚本是如何执行的:

从左往右,扫描上面这个Script(也就是一个拼接的字符串),中间用空格隔开的,共7部分(7个子串)。

遇到字符串,则入栈; 遇到OP_打头的,要么是1元操作符,栈顶1个元素出栈,计算,结果再入栈;要么是2元操作符,栈顶的2个元素出栈,计算,结果再入栈。

下面看一下入栈/出栈的详细过程:

//第1个字符串,签名,入栈

//第2个字符串,pub key,入栈

OP_DUP //第3个字符串:1元操作符,DUP就是拷贝的意思。也就是把栈顶元素拷贝1份,入栈。现在栈顶元素是pub key , 也就是把pub key拷贝1份,入栈。

OP_HASH160 //第4个字符串:1元操作符,对栈顶元素,做HASH160运算。也就是对pub key做HASH160运算,再入栈

634228c26cf40a02a05db93f2f98b768a8e0e61b

//第5个字符串:其实就是pub key hash,入栈

OP_EQUALVERIFY

//第6个字符串:2元操作符,校验栈顶的2个元素是否相等。此时栈顶的2元素,

//1个是刚入栈的pub key hash, 一个是经过前面的Hash160计算出来的pub key hash。

//2者不等,整个就结束了,返回FALSE;

//2者相等,全部出栈,此时栈里还剩2个元素:signature, pub key

OP_CHECKSIG

//第7个字符串:操作符,检测栈顶的2个元素,pub key和signature是否能对应的上。对应的上,说明这个签名的私钥,和收款人的公钥可以对上。有资格花这笔钱。

总结

每1个节点上面都有这样1个Script Engine,对于接收到的每1笔交易的每个vin,都会把其scriptSig和引用的UTXO(也就是上1个交易的输出)的scriptPubKey拼接起来,形成1个字符串,塞入Script Engine,得到结果是True/False。

如果是False,说明该笔交易的付款人,没有资格花这笔钱,该笔交易不合法,会被直接丢弃。

这个过程,也就是我们在第4课里挖矿的环节里面所讲的,交易的验证过程。

相关链接:

《第9课 Transaction数据结构、UTXO、钱包 – 详解》
《第8课 账号相关概念:公钥/私钥/Public Key Hash/P2PKH》

有兴趣朋友也可以进一步关注公众号“架构之道与术”, 获取原文。
或扫描如下二维码:
第10课 交易安全性如何保证? -- scriptSig/scriptPubKey/Script Engine_第1张图片

你可能感兴趣的:(区块链技术)