我发现从word文档粘贴到,表格会消失,所以我改成图片了,可能在未来的某天我会在别的地方再发表一次这个文章吧。
第一章 以太坊技术初探
本章将带领想要走进区块链领域的同学们初步看一看区块链技术的风采。主要要解决这么几个问题:什么是区块链?那什么是区块?什么又是链?区块链的作用是什么?它的原理又是什么?
1.1什么是区块链?
1.1.1区块链的基本定义
在写以太坊区块链技术介绍之前,总有一个问题没办法绕过去,那就是炒的火到不行行了的区块链到底是个什么东西?
打开网上的介绍,千奇百怪五花八门,各种术语层出不穷,对于我这样天赋不行又没什么开发经验的开发人员一点都不友好。从5个W的角度介绍的话,一般性的介绍是这样子的:
●What:一种分布式的账本。
●When:2008年,比特币创始人中本聪写的论文中,首次出现该概念。
●Where:目前主要应用于比特币/莱特币等数字货币平台以及以太坊等智能合约平台。
●Why:去中心化的真正点对点交易(p2p),不可篡改和伪造。
●How:通过使用区块链这种数据结构。在这种结构中,每个区块(block)都包含了上一个区块的哈希值(hash)。这样,就保证了历史数据可公开而不会被篡改。一旦某一个区块信息内容被改变,它的哈希值就会被改变,与下一个区块保存的哈希值不一致。
现在网络中的很多介绍性的文章就是一上来就砸出来这几大概念,看起来是很high,big and
up,都内什么是些什么玩意?看了之后简直头大:账本具体是什么?账本跟数据库有什么区别?如何采用的分布式技术?数据结构是什么样子的?又是如何实现的?
对于我这种小愚人,看理论性的东西都很费劲。所以我们还是得落实到细节,这样的东西比较清晰。本文别的啥都不多,就是例子多。
这就来先举个例子说明区块链技术中的基本道理。
小A与小C是一对关系非常好的基友合作伙伴。小A是很多品牌的全国总代理,旗下运营了包括“康帅博”、“脉劫”、“可日可乐”、“白事可乐”、“雷碧”等诸多驰名品牌,而小C则是小A手下的分销商。每周小C都要从小A手中进货,因为两人很熟,所以通常是先记账,之后到季度结束再结账。
但是可能是后来小C喝“王老古”喝多了,智商下降严重,常年记错账,导致两人所记账目对不上。之后小A和小C两个人商量了这么一个记账的办法:
1.每次记账,小A和小C中,选择一个人负责记账。具体由谁来记,采用猜拳的方式决定(假设小C赢了)。选一张干净的白纸来记,并给这张纸加上页码和小C的签名。
2.小C记账之后,给这一页纸做一个扫描件,发给小A;小A审核一遍这一页账目,之后认认真真仔仔细细抄一份一模一样的账目,留给自己。
3.每个人都把写好的每一页账目都按顺序贴到一个本子里,用透明胶带覆盖粘贴整页账目,防止破损撕毁和修改,通过页码来确定顺序。
4.每周要记账的时候,都重新选一张白纸,按顺序加上页码,之后按照上面的(1)(2)(3)步骤再来。
其实区块链技术就是对这种记账方法的一种演绎:小A和小C,就相当于区块链中的不同节点;账本中的每一页,就相当与区块链中一个区块;小A与小C猜拳来竞争记账权,就是区块链中的共识算法;小C把扫描件发送给小A,小A再抄一遍,相当于全网络中的账本同步;每一页账目用透明胶带粘贴保存,相当于区块链中每个区块做哈希,防止本页面篡改;页码的顺序记录,是防止历史数据丢失或增加,比如缺少区块之类的问题。
从上面的描述可以看到,区块链技术套路也就这么深。在我们看来,所有的区块链平台,一般而言,需要修改的内容只有这么几个方面:第一是共识算法,就是竞争记账权的方式;第二是账本结构,就是都要记录哪些内容;第三是网络协议,就是节点间互相通信的方式。
现在的各个区块链平台,具体的实现方法各不相同了。比如对于共识算法,不同平台就使用了不同的方法,比特币和以太坊目前使用pow算法,原理是谁的电脑最好用,谁来记账;以太坊计划以后使用的pos算法,谁股份多,谁来记账;IBM的超级账本项目使用pbft算法,大家一起投票选一个人来记账。
下面我们就具体的介绍一下以太坊的相关机制。
1.1.2以太坊技术背景
以太坊(ethereum)是目前规模和市值仅次于比特币的一个区块链应用平台。与比特币(BitCoin)等等数字货币平台不同,以太坊为首的区块链应用平台,虽然也有自身的数字货币——以太币(Ether/eth),但它的目标却是建立一个区块链2.0阶段的应用。以太币的作用是为了①购买计算资源②形成一个生态上的闭环。
tips:
区块链技术应用领域,预计有三大阶段。
区块链1.0,就是目前的比特币模式,区块链平台提供给所有人具备公信力的数字货币。
区块链2.0,目前的以太坊模式,区块链平台提供给所有人写具备公信力的智能合约。
区块链3.0,去中心化的公共服务。2015年美国一对新婚夫妇把结婚誓言写到了某个比特币交易的文本注释字段(这个字段的内容一般是写一句我用这一个比特币买了一杯咖啡)的作为公证。这一段誓言会永久的存放到比特币区块链的账本中。
简单地说,对于比特币这样的数字货币模式,会在区块链网络中,记录下内容是诸如“A把10块钱转给B”这样的流水信息。而对于以太坊的区块链的使用就会灵活很多。除了保存账户流水信息之外,还可能会保存“用户A在网络上部署了一个合约,合约内容是在拍卖中出价最高的人可以赢得拍卖”这样一条信息。该信息发布之后,其他用户可以在区块链中向合约发送出价信息,合约可以自动判断谁赢得了拍卖。
1.2以太坊的gas机制
以太坊的消息和区块头数据结构都包含与gas相关的字段,那这些字段究竟是做什么用的呢?
在以太坊中,记账是需要消耗计算资源的,为了激励大家去记账,所以有了一个gas机制。gas的意思是汽油,如果你不给汽车加油,它就不给你干活;要让它多干活,你就得多耗汽油,这个名字是不是还挺生动形象?
以太坊账本记录下的每一条消息都会消耗相应的计算资源。这些消息可能会是转账,也可能是部署一份智能合约,也可能是执行智能合约。根据你要执行的功能不同,相应消耗的计算资源多少也会不同。要计算一次加法,可能只消耗3点gas;计算一次乘法消耗5点gas;但是循环定义一个string类型的数组,就可能会消耗上千gas;而建立一个合约的基本消耗就高达32000点gas。
每条向以太坊区块链发送的消息,都是带有gas数量和gasPrice(gas价格)的,当你发送一条消息,附带有10000点gas,价格为0.00014eth,那么此时就会从你账户扣除10000*0.00014=14eth。当消息内容执行完毕之后,消耗的gas会转给记账的人,而剩余gas会返还给消息的发送者;当gas消耗完毕,命令还没有执行完,那么所有gas都会转给记账人,而且交易将会回滚到初始状态。相当于花了钱,还什么都没做成。
最后提示,如果gasPrice价格定的比较高,记账的人就更愿意记录你的消息,你发送的消息就会优先执行。
gas机制的作用是①鼓励记账②防止DDOS攻击③防止用户自己的合约错误④控制区块中的交易个数。
1.3以太坊的账本结构
前面介绍了一些相对宽泛的技术原理,而本节中将详细地介绍以太坊的底层账本结构。
在介绍账本结构之前,要先明确一点,就是区块链中并不是所有信息都保存在区块链这个数据结构中的。举例,就像在第一节中提出的例子,小C已经从小A那里提货了,但是还没有把这些消息记录到账本上的时候,这个状态怎么说?这些信息其实都保存在小A和小C的脑子里了。在区块链系统中,就相当于保存到了所有节点的内存里,学名叫做“交易池”(transaction pool)。除此之外,还有很多其他内容保存到了内存上。那么究竟哪些内容会保存在内存上,哪些内容会保存到区块上最终存入硬盘(落盘)呢?
总的来说,大体上的概念是这样的:
1.区块链保存所有的交易(消息)信息。对于账户而言,类似于账户流水;或者说类似于银行系统接收到的所有消息(IMAGE表)。每个区块包含区块体和区块头两个部分。
2.内存保存账户的信息,也叫世界状态(world state)。内容类似于银行中的账户概念。
3.(附一条:以太坊中交易的执行类似于reposting)
根据所有接收到的消息,我们可以得到所有账户的当前状态。
这里可以举两个例子简单描述一下。
(1)当前系统中只有两个区块,第一个区块中保存的消息是账户A有100块钱,第二个区块保存的消息是账户A给账户B转账10块钱。那么当前的内存保存的世界状态就是账户A有90块钱,账户B有10块钱。
(2)对于智能合约来说,第一个区块保存的消息是A发布了一个拍卖竞标的智能合约,第二个区块保存的消息是B向这个合约发出了竞标价格是100。
tips:我们就可以解释一个问题了,那就是为什么区块链经常把自己叫做分布式的“账本”?因为它保存的不是账户有多少钱,而是与账本一样,保存的是流水信息。所有的账户的状态(比如余额)都是可以根据整个系统中的流水消息推演出来的!所有的智能合约都是可以根据系统接收到的消息推演出来的!所有智能合约的执行结果也都是可以根据系统接收到的消息推演出来的!比如新加入一个节点,它就开始同步,同步的过程中它就可以计算出当前的所有账户状态,所有的合约地址等等等等。(节点间也可以同步这些数据)
是不是好像还可以理解?下面,我们一起来仔细八一八各种乱七八糟的数据结构究竟是什么样子的。
1.3.1区块体
区块体是一个交易列表,用于保存当前区块上的所有消息(就是交易,二者等同)。区块体理论上是可以为空的。
某一笔消息(或者说是交易Transaction)的结构如下所示。
(1)gasPrice
为本消息指定gas价格。gas价格越高,记账的人(也叫矿工)越喜欢把交易计入账本。就像账本的一页纸张大小有限一样,每个区块的交易也是有限制的,gas价格较低,就可能会较晚记录到账本上。同时,为了防止有人用过低的gas价格滥发消息,使用DDOS攻击整个系统,记账人都会设置可接受的最低gas价格。
(2)gasLimit
为本消息指定gas限额,即本消息可能花费的最大gas值。如上面章节所述,系统会先在账户中扣除gasLimit*gasPrice的以太币金额。消息执行完毕,剩余gas返还发送者的账户。而当达到这个gasLimit消息还没有执行完,系统会将状态回滚至原状态。这样一方面防止有人滥用消息,执行DDoS攻击;另一方面防止用户自身合约编写错误,发生死循环等问题。
(3)to
消息接收人的地址。可以是用户账户,也可以是智能合约。如果设为空,表示本消息要建立一个新的智能合约。
(4)value
转账金额。单位是wei。
tips:以太币的单位,某种意义上说,看上去还挺浪漫的。
(5)v,r,s
与交易签名有关。更重要的是,通过这三个字段,使用ECDSA算法,可以还原出发送者的地址。
(6)nonce
用于说明本消息是该交易发起人发起的第几笔交易。主要作用是区分两笔交易,我们可以看到,上面的所有字段是可以重复的,A账户可以发出多起转给B账户10块钱的交易,设定相同的gas价格和限制。这样会导致两笔交易包括hash值在内的所有内容都完全相同。这影响了交易的检索等功能(怎么区分一个区块中,多笔A给B转账相同金额的交易?)。为了防止这种情况发生,所以增加了nonce字段。
(7)init
据说,对于创建合约的消息会包含init字段。init字段保存了EVM虚拟机初始化所需要执行的代码,就是智能合约被编译之后的结果。init字段长度没有限制。
请注意:为什么我在上一段说“据说”呢?那是因为该字段只存在于以太坊黄皮书中,在实际上创建合约的消息使用的也是下面的data字段。
(8)data
如果消息的接收人是合约账户,会有data字段。data是发送给合约的数据,内容是调用方法的签名和传入参数。比如说拍卖合约有个竞标函数bid(address
account, int price),用于保存当前最高价出价人和最高价。发给拍卖合约的消息需要包含account和price的信息,这些信息都会在data里保存。具体的编码方式是:“0x”+sha3(“bid(address,int)).substring(0,8)+to_32bit_Hex_str(6)。其中前面的部分是函数名和函数传入参数的类型的哈希值的前4个字节,后面to_32bit_Hex_str()方法的实现会根据不同的变量内容而有所不同,具体规则请参考Ethereum Contract ABI文档(地址:https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI)。data字段长度没有限制。
1.3.2区块头
区块头(Block Header)是实现区块链原理、形成区块链的数据结构。每个区块头都包含如下数据结构:
tips:除了区块头和区块体这两个部分,还可能会有叔伯区块的区块头列表(和区块头结构一样)。
1.3.3世界状态
世界状态(world state)其实就是账户状态。以太坊中有两种账户,外部账户和合约账户。
外部账户(externally owned account, EOA)简单的讲就是由人来控制的账户。它的特点是:
●有以太币余额,
●可以发送交易(以太币交易或引发合约代码),
●由私钥控制,
●没有相关代码。
合约账户(smart contract)就是智能合约。它的特点是
●有以太币余额,
●有相关代码,
●代码执行由从其他合约接收的交易或消息(调用)触发,
●执行的时候—执行任意复杂的操作(图灵完备的)—操控它自己的永久存储,例如,可以有自己的持久状态—可以调用其他合约
本质上账户信息是一个这样的数据结构:
(1)nonce
当前账户发出的消息计数器。
tips:以太坊中nonce这个字段有三个,有时候容易混淆。区块nonce是pow的衍生品,与mixhash属性都是在进行pow计算时得出的结果。而账户nonce与交易nonce则含义相似。账户nonce是指该账户发出过多少次交易;交易nonce是发起交易的账户发出的交易数。
(2)balance
当前账户的余额。
(3)storageRoot
存储根。也是一棵MPT树的根节点,这棵MPT树保存了智能合约账户的内部数据存储空间。当合约账户调用suicide()方法时,该值将被置为null。
(4)codeHash
智能合约账户的代码hash值并指向合约代码,如果为EOA则该值为空。
tips:要这么理解区块链中的账户:它是不需要建立的。一个账户就是一个地址,谁拥有这个地址对应的私钥,谁就可以控制这个账户。就好像现在有无数上锁的房间,谁打开了哪个房间,谁就是这个房间的拥有者。
我们生成账户的过程,本质上是一个先配钥匙,后找房间的过程。步骤是①通过随机数生成一个32字节的私钥(64个十六进制字符)②通过非对称加密算法ECDSA生成公私钥对(公钥有64字节,128个十六进制字符)③取公钥的最后20个字节(40个十六进制字符)作为账户地址。
所以我们可以看到其中的安全风险,就是如果有人想配你房间的钥匙怎么办?解决办法是降低概率。以太坊一共有2^160个地址。这个数量非常非常非常大,地球上沙子和天上星星数量大概都是2^70。账户数比二者相乘还高出很多个数量级。这样使得通过这种碰撞攻击,计算出指定私钥的难度无限提高。
1.3.4交易回执
交易回执(Transaction Receipt)是交易的返回结果。区块链系统是异步的系统,与传统架构不同,不能直接返回交易执行是否成功,而需要去在回执中查看交易结果。
简单用一个列表来表示这个交易吧。由于交易结果不同,下列列表有些字段并不总是全部存在的。所以有些字段尚不明确是否存在,因为在实操过程中没看到,已在描述部分注明。
1.4以太坊的共识算法简述
共识算法分为很多种,以太坊当前采用的算法是工作量证明算法(proof of work,pow)。
pow的原理是选出计算功能最强的节点来记账。一般性的方法是出一个计算题,大家一块算。谁先算出来,区块链网络上的所有节点就公认它的计算能力最强,就让它来记账。
由于在pow共识机制下,通常在记账的同时会发行新的数字货币,所以节点们通常被称为矿工,竞争记账权的过程也被称为挖矿。
以太坊认为,对于第二个或者第三个解出题的节点,它们的工作也不是没有用处。因为任何一个子区块,都会保存父区块的hash,这对防止区块链出现分叉、同时防止区块历史被篡改都是有帮助的。所以这些稍晚解出题的节点也会获得少量的奖励。同时,每个区块都会保存其叔伯区块的区块头。
tips:因为区块中保存的交易和交易顺序都是不一致的,叔伯区块头与父区块的区块头是不一致的。
以太坊当前采用的ethash共识算法,是一种pow算法(略)
1.5以太坊的通信协议
以太坊采用devp2p通信协议实现。(略)
参考资料:
ethereum
wiki:https://github.com/ethereum/wiki/wiki
1.6关于图灵完备
图灵完备性是一个自治系统的重要的特性。
以太坊的图灵完备是半图灵完备。所谓的半图灵完备是因为并不是不会出错,而是在出错的时候,通过gas消耗强制性的中断。