摘要:从区块链的数据结构到去中心,从哈希到挖矿,从共识到分叉,这段时间听我念叨了那么多,相信各位读者对区块链应有了一个大致的了解。但是有一个话题我一直想写,但是迟迟没有动笔,因为我担心自己理解得还不够全面和透彻,以免有误导之嫌。袁腾飞有说过,只有等自己有了一桶水的知识,才能教人一碗水。我对此深以为然,这也 ...

从区块链的数据结构到去中心,从哈希到挖矿,从共识到分叉,这段时间听我念叨了那么多,相信各位读者对区块链应有了一个大致的了解。但是有一个话题我一直想写,但是迟迟没有动笔,因为我担心自己理解得还不够全面和透彻,以免有误导之嫌。袁腾飞有说过,只有等自己有了一桶水的知识,才能教人一碗水。我对此深以为然,这也是为什么我们公众号文章更新得比较慢的原因。你也可以说我这人有点完美主义,所以对于知识分享,我一定得等自己琢磨得足够透彻才会教给大家。所以对于某个知识点我都会往里抠得比较深,比较细,而且我并不相信人云亦云的网络文摘,我只相信自己眼睛看到的代码。虽然这样子进度比较慢,但是我认为这才是做学问的根本。经过这1个月来的理解和升华,我终于有底气可以跟大家分享这一碗水。这碗水虽然不起眼,却格外重要,尤其在区块链里。甚至可以这么说,它奠定了从现在到未来整个去中心化应用(DAPP)王国的基石。这就是区块链的交易模型

区块链中的账号地址

交易首先得有账号,无论是付款人和收款人都一样。和支付宝转账类似,在区块链里面也需要一个特定的标识来指代一个账号,那就是钱包地址。无论是矿工还是用户,只要在这个游戏里面玩,都会先创建一个钱包地址。这个钱包地址就相当于自己的账户。它其实是一个34位的字符串。比如:1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE


这个字符串是由用户的公钥通过编码产生的。关于公钥和私钥之后会讲。用户通过这个地址就可以进行余额查询以及转账等操作了。

多对多的映射关系

一般大家可以想到的交易无非是现实生活中的买卖,最典型的就是谁给谁转了多少钱。比如说如果你要给某个人转账,那你首先要知道对方的账号。所以一个交易记录构成必然包含发送人(Sender)账号和接收人(Receiver)账号,这两者形成的一一对应关系是大家普遍可以接受的交易模型,如下图所示:


但是这种模型在区块链里面是很低效的。

首先,对于每笔交易的确认,都需要支付一定费用给矿工,所以你在转账的同时还需要发一笔交易费给矿工,这也就意味着接受端的地址数量至少会大于1。

其次,区块链的交易记录必须可回溯,所以我们需要建立一个和过去交易的链接,这样才能查到这笔资金的源头。而当前账户上每笔资金有可能来源于多个地址。

所以为了方便起见,我们把资金来源作为交易输入(TxIn),把资金流向作为交易输出(TxOut)。于是交易输入和交易输出是多对多的映射关系,其中每个交易输入又指向过去某一笔交易的输出。如下图所示:



有了以上的结构,我们再来看看在实际区块中的交易数据包含了哪些信息。以比特币为例:

除了交易输入和交易输出以外,它还包括了时间戳(timestamp),也就是交易发生的时间。还有这笔交易的哈希值(tx hash), 以及区块版本号(version)。如下图:

其中Tx hash是SHA256的16进制输出,也就是一个64位的字符串,比如:

8152e25169fde1cd2a81ca794b94a144ff07ae7061d4afe72ae9282a4c654081

这个值是通过以下公式求得:

Tx hash = SHA256(Timestamp + Version + Payload)

这里面的Payload就是指代具体的交易内容,包含了交易输入与输出的序列。无论是Timestamp, Version, 还是Payload, 在实际区块里都是以字节序列的形式呈现的,所以公式里的“+”就相当于把这些序列串联起来。SHA256这个函数相信大家已经不陌生,我在之前的文章也有详细讲述过。它没有逆函数,而且极少可能发现值域上的冲突,所以输入的改变会导致输出的改变。

大家可千万别小看了这个哈希值,其中可大有乾坤。把Timestamp引入作为SHA256输入的一部分,是中本聪用来解决双花(Double spend)问题的高招。


什么是双花?

通俗点说就是一张钞票被花了两次。现实中的法币肯定不可能双花的,因为制作伪钞还是很难的。但是比特币以及其他虚拟货币就很容易复制,因为它们其实是被交易输入来定义的。我可以轻易地把输入数据再复制一份,然后输出写不同的钱包地址。这个问题最初的解决方法是创建一个铸币节点,也就是说所有的比特币都统一由这个节点来分发。可是如果这样处理的话就又回到了中心化。


如何解决双花问题?

所以为了去中心,中本聪使用了一个叫时间戳服务器(Timestamp Server)的方法,即在一个区块内规定不允许超过一笔交易引用同样的输入但是输出为不同的地址。一旦发现就会被认为是“双花”。而此时矿工会记录最先发生的那笔交易,而其他的就会被扔掉。所以这里的time stamp就可以用来判断两笔交易的先后顺序。


细心的网友:可是为什么哈希值的计算需要把这个time stamp考虑进去呢?


这里就用到了SHA256良好的加密特性,可以用来防篡改。因为如果有人恶意修改时间戳的话,输出哈希值就会发生改变,最终会导致整个区块哈希改变并且超出目标值的范围。其他矿工自然会拒绝这样的区块。


所以SHA256输入的数据都是属于受保护的敏感数据,是不能够被轻易篡改的。


交易输入结构

看过了交易的数据结构,我们再来学习下它的输入与输出。拿比特币为例,我们看看里面到底包含了哪些东西。先来看交易输入:

(交易输入包含了3个元素:Prev Tx Hash, Tx Index, 和SigScript)


其中Prev Tx Hash是与当前输入相关联的前一个交易的哈希值,这也是为了实现区块链的可回溯特性,也就是说通过这个哈希可以查到你当前转账的那笔资金是来自于先前的哪一笔交易。

根据前面介绍的交易模型,每一笔交易会有多个输出对应于不同的地址,所以我们需要一个索引值来指向具体某一个输出,这就是Tx Index在这里的作用。


最后那个SigScript是签名脚本。这里我要给大家好好介绍下脚本(Script)的概念。


比特币协议的脚本

我觉得“脚本”是中本聪在比特币里最有前瞻性的一个创新。甚至可以这么说,它奠定了整个去中心化应用未来发展的基础。现在区块链2.0/3.0的代表作,诸如以太坊,EOS等都是基于这框架衍生出来的。

细心的网友 那什么是脚本呢?


脚本即一组有特定顺序的指令。这些指令是针对栈(Stack)元素进行操作。我们看看中本聪定义了哪些指令:


由于篇幅有限,这里无法给大家一一解释所有的指令。所有的指令描述可以上官网查看https://en.bitcoin.it/wiki/Script.


这里选取几个有代表性的给大家讲一下。


首先这些指令的所有操作都是针对“栈”上的元素。”栈“是计算机里的一种数据结构,有先进后出的特点。


部分指令介绍:

OP_PUSHDATA1:下一个字节入栈

OP_DUP:把栈的头元素复制一遍,然后再入栈

OP_HASH160:把栈的头元素哈希两次(先用SHA256,然后用RIPEMD-160进行编码),将输出结果推入栈。

OP_EQUALVERIFY:判断栈的头两位元素是否相等。

OP_CHECKSIG:验证签名


所以有了这些指令我们就能定义一些复杂的逻辑,来告诉矿工们这笔钱应如何被使用,用户有没有权利动用这笔钱。


理解了“脚本”这个形式以后,我们再来看签名脚本。签名脚本包含两个元素:签名(Signature)和公钥(public key)。它的作用就是为了验证签名。


公钥和私钥

区块链应用的一个最大特点就是安全。它可以确保你钱包里的币不会被别人盗取。


相信大家都有刷信用卡的经历,你在刷信用卡买东西的时候都要在发票上签名,相当于你确认了这笔交易。如果此时有人盗刷你的信用卡,而他的签名跟你本人的签名是不一致的话,银行就会撤销这笔交易。区块链也是用类似的原理,每一笔交易都需要有你的签名,交易才能确认。


细心的网友:那如何验证签名呢?


这就涉及到区块链里另一个重要的加密算法。

具体步骤是这样的:

首先你在开设钱包的账户的时候,系统会自动给你分配一个私钥(private key),其实就是一个随机字符串。这个东西非常重要,相当于你保险箱的钥匙,是不能分享给别人的。


有了私钥以后,系统会利用椭圆曲率加密法(ECDSA)产生另一个字符串,那就是公钥(public key)。椭圆曲率加密算法很复杂,这里不做赘述,下次我会专门写篇文章来探讨加密。


公钥,顾名思义就是公共的钥匙,是可以广播给整个矿工社群的。在公钥基础上经过特定的哈希编码,我们就可以得到钱包的地址。


接下来如果我们要给另一个钱包地址转账,就需要用私钥来对这笔交易进行签名,然后就可以获得另一个字符串,它就是我们的签名(signature)。


签名的过程也是通过椭圆曲率加密。有签名和公钥这两样东西,矿工们就可以验证这把私钥能否解锁这个地址上的比特币。这套算法的优势在于:


  1. 椭圆曲率加密没有逆函数,也就是说你可以通过私钥得到公钥,可以通过私钥获得签名,但是反过来不行。

  2. 整个解锁过程不需要暴露私钥。


以上两点的特征就可以确保在交易过程中,你的私钥信息不会被别人盗取。整个解锁过程如下图所示:


所以椭圆曲率加密也是目前市面上安全性最高的一种通用加密方式。


交易输出结构

讲完了交易输入,我们再来讲交易输出:

(交易输出包含了To Address, Value 和ScriptPubKey这些元素)


其中To Address为目标转账地址,Value就是指转账金额,PkScript就是公钥脚本。开头两个比较好理解,关键公钥脚本是什么。


公钥脚本顾名思义就是包含了公钥哈希值的脚本。在比特币协议里,整个交易的验证过程,需要将Tx In的签名脚本和Tx Out的公钥脚本合并起来,我们称为P2PKH(Pay-to-Public-Key-Hash)。除了这个以外还有P2SH(Pay-to-Script-Hash)等, 这里不一一赘述。举个P2PKH的例子:


公钥脚本: OP_DUP OP_HASH160 <公钥哈希> OP_EQUALVERIFY OP_CHECKSIG
签名脚本: <签名> <公钥>


我们可以分析下脚本的每一步是如何执行的:

image.png

这个是非常经典的也是比特币中最常用的脚本,它实现的是地址间的转账。我们通过不同的指令组合,还可以用来实现其他的复杂功能比如锁仓。


细心的网友:等等,这个不是智能合约里的功能嘛?


没错,其实中本聪创立“脚本”就是考虑到以后“智能合约”的应用。和简单的转账不同的是,合约需要涉及多方的签名认证。所以实现“智能合约”的功能,只要做一个从单签名到多签名的扩展就可以了。


可是比特币协议的这个脚本并不是特别好用。第一,指令集比较有限;第二,它并不支持循环,所以不是图灵完备;第三,可读性很差。所以以太坊就是在此基础之上建立了一个图灵完备的语言类似于Python这种,使用户可以方便地构建自己的合约。但是不管怎么样整个框架还是利用这个交易模型来实现的。


总结

看上去很普通的交易模型,其中是不是大有乾坤?里面包含了脚本,智能合约,时间戳服务器,公钥与私钥的加密等重要内容。它撑起了整个区块链协议的基石。

image.png

来自:公众号 Block-talk 区块链中那些事儿

更新日期:
文章标签: ,,
文章链接: 区块链中的交易模型  [复制链接]
站方声明: 比推所有文章都只代表作者观点,不构成投资建议。投资有风险,后果自负。