比特币的区块链架构主要围绕支持虚拟货币的实现,虽然它有一定的灵活性,但用来支撑虚拟货币以外的应用场景还显得非常 局限。近年来,区块链逐渐引起IT业界的关注,并逐渐成为独立于比特币的一个平台架构,其重要性越来越受到重视。区块链2.0的概念也随之产生。其核心理 念是把区块链作为一个可编程的分布式信用基础设施,支撑智能合约应用,以与过去比特币区块链作为一个虚拟货币支撑平台区别开来。具体说来就是,不仅仅把区 块链作为一个去中心化的虚拟货币和支付平台,而是通过增加链上的扩展性功能,把区块链的技术范围扩展到支撑一个去中心化的市场,交易内容可以包括房产的契 约、权益及债务凭证、知识产权,甚至汽车、艺术品等。
区块链2.0提供一套新的协议(区块链2.0协议)支撑新型的去中心化应用。如果用互联网协议来做类比,区块链1.0 就相当于TCP/IP协议,而区块链2.0就相当于HTTP、SMTP和FTP等高级协议。甚至有把区块链1.0比做电话,而区块链2.0相当于智能电话 的比喻。在比特币后,出现很多被称为区块链2.0的平台,其中,最具代表性的是以太坊平台。下面简单介绍一下以太坊架构。
以太坊的设计主要还是以比特币架构为基础。前面几章已经介绍了以太坊的基本架构,本章不再详细叙述,下面只对和比特币架构不同的几个主要方面做重点讨论。以太坊架构图3-9所示。
图3-9 以太坊架构
1.账户设计
比特币没有账户的概念。每个用户的余额都是从他们在区块链上的UTXO计算出来的。以太坊则有两种类型的账户:一种是 外部所有账户(EOA),另一种是合约(Contract)账户。外部所有账户就是我们一般意义上的用户账户,它由私钥控制。合约是一种特殊的可编程账 户,合约存在以太坊区块链上,它是代码(它的功能)和数据(它的状态)的集合。合约受代码控制并由外部所有账户激活。
以太坊的设计是将区块链作为一个通用的管理对象状态转换的去中心化平台,账户就是有状态的对象。外部所有账户的状态就 是余额,而合约账户的状态可以是余额、代码执行情况,以及合约的存储。以太坊网络的状态就是所有账户的状态,该状态由每个区块的交易来更新,同时需在全网 形成共识。用户和以太坊区块链的交互需要通过对账户的交易来实现。
每个以太坊的外部所有账户由一对密钥定义,一个是私钥,一个是公钥。区块链的EOA账户由它们的地址来做索引。取公钥 的后20位作为地址,这和比特币的地址不一样。每个公私钥对被编码存放在一个密钥文件(Keyfile)中。密钥文件采用JSON格式,可以用文本编辑器 打开来看。密钥文件的私钥都是用在建立账户时输入的口令来加密的。密钥文件存在以太坊节点的数据目录中的keystore子目录中。密钥文件需要经常备 份,否则如果失掉密钥文件,账户里的以太币也就无法找回了。
合约账户可以执行图灵完备的计算任务,也可在合约账户之间传递消息,合约编译成以太坊虚拟机字节码(EthereumVirtual Machine Bytecode),并记录在区块链上。
外部所有账户可以通过发送交易到合约来实现对合同的调用。这需要提供几个参数,例如EOA的地址、合约的地址,以及数 据。数据部分包括需要调用的合约里的方法(method)以及其传递的参数。这个需要用到Application Binary Interface(ABI)来作为传递数据的编码和解码的标准。关于ABI的详细信息可以参考以太坊wiki网页https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI 。
2.区块链设计
比特币采用Merkle树来将交易的哈希值按一定算法组成二叉树状结构[1] ,顶层节点的哈希值相当于整个交易清单的指纹,可以用来校验交易清单。中本聪采用Merkle树设计,也是为了轻量级节点能通过SPV(简化支付验证)方 式来方便地校验交易。SPV不用下载整个交易清单,而是只需要区块报文头中交易清单顶层节点的哈希值,以及与自身节点相关的交易,然后可以通过向其他节点 查询其他相邻交易,就可以完成对某个交易是否包含在区块链中某个区块的验证。
以太坊的区块链的每个区块不但保存着交易清单,还保存最新的状态。以太坊作为一个通用的区块链编程平台,引入了账户概 念,由此它也带来更为复杂的校验和查询需求。例如要查询账户的余额或判断一个账户是否存在,光用比特币的Merkle树就满足不了要求。因此以太坊采用 Merkle Patricia树来实现对交易和状态的校验和查询[2] 。下面看看交易和状态面临的问题。
以太坊的状态包含一个键值表(key-value map),其中键是地址,值是账户里声明的变量,包括余额、随机数(nonce)、代码和账户的存储(存储也以一棵树的形式来组织)。与交易数据只能增不能改不一样,账户的状态经常被改变,其余额、随机数经常变。
另外,新的账户也经常被插入,键在存储里也被经常插入和删除。因此Merkle树不适合这种情况,而需要一种可以在插 入、更新和删除操作后快速计算新的树根哈希值,而不需要重新计算整棵树的数据结构。同时,树的深度是有限的,即使在有攻击者试图通过故意发很多交易来尽量 增加树的深度的情况下,不然一个攻击者可以通过操纵树的深度,以使得每个更新都变得非常慢,来对平台实施拒绝服务攻击。
还有一个要求是树的根哈希只是与树的数据有关,而与更新的顺序无关。不同的更新顺序或者甚至重新计算整个树的根哈希值都不会改变树的根哈希值。Patricia树是符合这些要求的数据结构。
简单来说,以太坊的账户的状态由键值表(Key-Value Map)来表示,在Patricia树里,键被编码成向下访问树的路径。在以太坊的Patricia里,每个节点有16个子节点,所以路径用十六进制来编 码。例如,键“dog”的十六进制编码是6461567,所以要访问键“dog”所对应的值,就必须先从根节点开始,向下到第6个节点,然后再由该节点向 下到第4个节点,以此类推,一直到最后。
在区块链的区块报文头中,不像比特币那样仅仅存放一个交易清单的Merkle树根哈希值,而是存放了3个根哈希值:一个是交易的Merkle根哈希值,另外一个是状态的根哈希值,还有一个是收据的根哈希值。
另外一个和比特币的不同是,以太坊的区块链中的每个区块保存区块链号和区块难度。
3.PoW机制
以太坊的PoW(工作量证 明)算法叫Ethash算法(是一个经过修改的Dagger-Hashimoto算法),该算法主要寻找一个随机数作为输入,使得运算结果小于一个特定的 难度门槛。PoW机制的前提是,不存在比逐个试更好的找到该随机数的方法,同时验证结果必须非常方便且成本小。由于哈希运算的结果是均匀分布 (Uniform Distribution)的,所以可以保证,通常找到该随机数的时间取决于难度门槛。这样的话可以通过控制难度来控制在网络上找到一个新区块的时间。以 太坊是通过动态调控难度来达到平均每15s在全网中找到一个新区块的。每15s的“心跳”基本上是全网更新系统状态的节奏,并保证当攻击者的计算能力不超 过全网的计算能力的一半时,攻击者无法改写交易记录或进行分叉(以便进行双花交易)。这就是所谓的“51%”攻击。网络上的矿工的挖矿收入期望直接反映他 们拥有的计算力,或者哈希速率在整个网络中的占比。
比特币的工作量证明机制依靠的仅仅是CPU计算难度问题,以太坊的Ethash工作量证明机制加入内存难度,使得它具 有抵抗单凭哈希运算优化的ASIC挖矿机的属性。内存难度是通过在算法设计中要求选择由随机数和区块报文头决定的一部分固定资源,这些资源一般是几个GB 的数据,叫“有向无环图”(DAG)。每30000个区块后需要有一个全新的DAG。这相当于一个125小时的窗口,或5.2天,称为一个epoch。这 个图需要一段时间才能生成。因为DAG只和区块链深度相关,因此可以提前生成。如果没有现成的,以太坊的客户端需要等生成了DAG后才能产生新的区块。这 样的话在每个epoch转换的时候,如果客户端不预先生成DAG,网络就会出现大规模的延迟。当一个矿工节点第一次启动时,需要等DAG生成之后才能开始 挖矿。
以太坊的Go语言实现程序geth和C语言实现的挖矿程序ethminer都实现自动DAG生成,并在epoch转换 的过程中维护两个DAG。以太坊的Ethash算法可以在较慢的CPU环境中进行哈希运算,但在挖矿节点上可以通过增加内存和带宽来提升挖矿速度。对内存 的高要求使得大型矿的矿主没有太大的比较性超线性收益;对带宽的高要求使得用堆超快的计算单元来共享存储的方法并不能带来更好的收益。这样对矿池挖矿来说 没有太多好处,因此以太坊从设计上希望避免出现像比特币那样的矿池算力集中化的问题。
类似比特币,以太坊的挖矿静态收益将随着时间推移而逐渐减少,目前静态收益是每挖到一个区块获得5以太币。未来矿工的 收益将主要依靠发送交易的用户支付的“燃料”来获取收益。以太坊的矿工奖励制度比比特币复杂。很多参考资料没有给出具体的奖励数额,有些甚至是错误的,例 如对挖到“叔区块”的矿工奖励的描述,有些资料认为是(7/8)×5=4.375以太币,其实这是不准确的。笔者参考了计算奖金的源代码,具体的奖金机制 描述如下。
每当一个矿工挖到一个区块,他将获得5.0以太币(Ether)的静态收益,同时获得在区块上的“燃料”(gas), 价值取决于当前的“燃料”价格。另外矿工也获得一个将“叔区块”(uncle)包含进区块链的额外奖励,相当于每包含一个uncle区块将获得 (1/32)×5以太币的收益。而产生“叔区块”的矿工将按下面的公式获得奖励:
挖到“叔区块”矿工奖励=(叔区块ID+8-当前区块ID)×5/8
例如,假设当前区块ID是1600,叔区块ID是1598,那么挖到叔区块1598的矿工将获得(6/8)×5,等于3.75以太币。如果叔区块的ID是1599,那么挖到叔区块1599的矿工将获得(7/8)×5,也就是4.375以太币的奖励。
注意:所谓“叔区块”,是指符合难度条件,但区块里的交易不被确认的区块,或叫“废块”(Stale)。比如 矿工A挖到一个符合难度规定的合规区块a,而几乎同时矿工B也挖到符合标准的区块b,但由于网络延迟,区块b没有被确认,成了废块,而a成了网络共识的区 块,被包括在区块链中。由于以太坊产生区块的速度比比特币产生区块的速度要快很多,因此在网络繁忙的时候,相对于比特币系统更容易出现“废块”。在比特币 系统中,生产废块的矿工只能自认倒霉,是没有奖励的。而在以太坊中,产生“叔区块”的矿工和将“叔区块”包括在区块链上的矿工都能得到奖励。这样产生废块 的算力也被包括进来,有效地增强了安全性,使得攻击者不容易追上一个带“叔区块”的主链。同时通过给“叔区块”奖励,也避免出现像比特币那样计算力高度集 中的矿池,因为矿池相对来说不像单个挖矿节点那样容易产生废块。严格说来,“叔区块”是在当前链接区块往前推最多6个的“祖先”废块,每个区块最多能链接 两个“叔区块”。
以太坊采用一个与比特币不同的算法叫GHOST(幽灵)来构建区块链。GHOST的全称是Greedy Heaviest Observed Subtree,中文直译是“贪婪最重观察子树”。严格来说,以太坊的区块链不是一个链条,而像一棵树,它包含前面提到的“叔区块”。
在比特币系统中,矿工按一定的优先级把未确认的交易打包到新发现的区块上。交易的优先级按交易额和链龄(指UTXO存 在的时间)来决定。交易额越大、链龄越高,优先级就越高。交易费用是用户的输入和输出之差。如果输入和输出之差为零,随着交易发生的时间越来越久,其在交 易池的优先级会逐渐升高。因此一般来说,即使付给矿工零交易费用的交易都有机会被矿工包含在区块链上。当然个别矿工可以有自己的规则,可以拒绝零交易费的 交易。而在以太坊平台,不提供“燃料”的交易不会被执行,也不会被包含在区块链上。以太坊的交易费用按以下公式计算:
Total cost=gasUsed×gasPrice
其中gasUsed是执行该交易所消耗的燃料,燃料的价格由用户和矿工决定,一般来说在用户建一个交易的时候,可以提 一个燃料价格。在以太坊发布的第一版本Frontier(前线)中,以太坊客户端的默认燃料价格是0.05e12wei,大约是一亿分之五个以太币。矿工 一般不会接受低于普遍价的燃料价格。
4.计算和图灵完备
以太坊作为通用的区块链平 台,需要提供比比特币更强大的计算能力。前面说过,从安全角度出发,比特币的设计专门选择一个不具图灵完备性的脚本引擎,目前能通行的比特币脚本指令也不 多,但在虚拟货币的应用场景已经是绰绰有余了。而在以太坊上,一个和比特币非常大的不同点就是选择了图灵完备的计算环境——以太坊虚拟机(EVM)。这就 意味着在EVM上可以做所有的能想得到计算,包括无限循环。EVM指令包括一个JUMP的跳转指令,可让程序跳回前面的程序代码,也可以像条件判断语句那 样做条件跳转,当满足一定条件时将程序跳转到另一个地方执行。另外,一个合约可以调用其他合约,这提供了潜在的递归调用的功能。这就很自然地会导致一个问 题:一个搞破坏的用户能否通过强制矿工或全节点进入死循环而将他们基本关掉呢?这个其实也是一个“停机问题”,也就是说,通常没有任何办法去判定一个程序 会否停机。以太坊怎么解决这个问题呢?它首先要求每个交易要给出最大的计算步骤,交易的发起人要提供Gas作为交易费以供矿工把交易加进区块。如果实际运 行超过了该最大计算步骤,计算将被终止,而交易费会归挖到区块的矿工所有。因此以太坊采用经济的方法来保证以太坊平台的安全。
以太坊网络的每个节点都运行EVM并执行合约代码,因此以太坊就像一个并行运行的“世界电脑”,在所有的节点上同时进 行账户的状态转换,并形成网络层面对所有账户状态的共识。虽然这种P2P的运行方式并不是最高效的,但却是最有安全保障的,可以说,这部“世界电脑”永不 停机。
5.EVM高级语言
比特币不提供高级语言的支持,以太坊则提供高级语言让用户编写智能合约。以太坊的高级语言最后会编译成在EVM中执行的EVM字节码(bytecode),部署在以太坊区块链上。以太坊提供3种编程语言:Solidity、Serpent和LLL。
·Solidity类似JavaScript语言,是目前以太坊上最流行的智能合约编程语言。
·Serpent类似Python编程语言,它结合了低级语言的效率和易用的编程方式。Serpent用LLL语言来编译。
·LLL是Lisp Like Language的简称,顾名思义是一个像Lisp的语言。它有些像汇编语言,设计得非常简约,基本上就是在EVM上的一个微小的封装。
另外一个类似C的语言Mutan已经基本弃用,不再被维护。
6.以太坊P2P网络
(1)RLPx协议
以太坊网络节点间的通信采用DΞVp2p线上协议。节点间采用RPLx[3] 编码及认证的通信传输协议来传输消息包,即提供发送和接收消息的协议功能。节点可以自由地在任何TCP端口发布和接受连接,默认的端口是30303。目前正式版的RLPx实现了以下功能:
·单一协议的UDP节点发现
·ECDSA签名的UDP
·加密握手/认证
·节点持久性
·加密/认证TCP
·TCP帧处理
DΞVp2p节点采用RLPx的发现协议DHT(Distributed Hash Table)来实现邻节点的发现。节点间的连接也可以通过具体客户端的RPC API进行,并提供对方端点来连接邻节点。
当两个节点连接并握手时,它们互相交换状态信息,状态信息包括总难度和它们的区块哈希值。总难度相当于节点所有的区块 链上区块难度的总和。其中一个总难度小的节点会向对方索取对方整个区块链中区块的哈希值。这些哈希值的链条会存放在一个“工作池”中,供所有连接的邻节点 共享。当一个节点发现在哈希链上有它没有的区块哈希值时,它将向邻节点索取从该哈希值所代表的区块起往后的N个区块,并做好标记,这样不会从另外一个节点 获取这N个区块。
RLP(递归长度前缀)是一种编码方式,其目的是将二进制数据进行任意嵌套的数组编码。在以太坊里,RLP是用来对对象进行编码的主要方法。
(2)Whisper协议
Whisper协议是DApp间通信的通信协议。Whisper结合了DHT和数据包消息系统(如UDP),因此同时 具有以上两种协议的特性。Whisper是一个纯标志(identify)的消息系统,它提供一个低层次的(非应用相关)但又简易使用的API,而不需要 记忆底层的硬件属性。另外,就像DHT,有一个每条可配置的TTL(Time to Live生存时间)以及用来签名或加密的规则。在这个意义上,Whisper提供多索引,非单一的记录,也就是说同一记录可以有多个键,有些键可能和别的 记录一样。
Whispher不是一个典型的通信系统,它并不是设计来取代TCP/IP、UDP、HTTP或其他常见的协议的,也 不是用来提供一个面向连接的通信系统,更不是简单地在两个节点间传输数据。它的主要目标也不是提升带宽或降低延迟,而主要是直接设计来给新型的应用开发模 式用的一个新的通信协议。它是从头设计的为简便而高效使用多播(multi-casting)和广播(broadcasting)场景的协议。类似的低层 次部分异步通信也是一个重要的设计目标。降低低价值流量或迟滞也是另一目标,这相当于QoS控制。Whisper是为需要大规模的多对多数据发现、信号谈 判和最少的传输通信、完全的隐私保护的下一代DApp而设计的。
Whisper的使用场景有以下几种:
·DApp需要把少量的信息发布出去,而这些发布的信息要保留相当一段时间。例如一个外汇交易所将一个货币的挂牌卖价发布出去。这个卖价可能需要保留几分钟或几天时间。
·DApp需要发信号给其他DApp,希望它们参与对某个交易的协同。
·DApp之间需要提供非实时的提示或通常的通信,例如聊天室应用等。
·DApp需要提供暗通信,也就是通信的双方除了知道对方的哈希值外,不知道对方更多的底细。
7.事件
合约是在区块验证的时候被交易触发。如果设想在函数调用情况下,合约的执行是异步的,因此它没有返回的值。合约与外部 的通信是通过日志事件实现的。日志事件是交易执行时产生的收据一部分。收据保存在收据树上,它的完整性由当前收据树的根保证,收据树的根和状态树以及交易 树的根一起保存在区块的报文头。从外部的大的范围说,收据是以太坊系统状态的一部分,除了在合约内不能读取收据的数据以外。
以太坊中的事件是一个以太坊 日志和事件监测的协议的抽象。日志的记录中提供合约的地址,一组最多4个议题(Topics)和一些任意长度的二进制数据。事件利用现有的ABI功能来解 析日志记录。根据一个事件名和一些列的事件参数,可以把它们分为两个系列:一个是建立了索引的,一个是没有索引的。那些建了索引的(可以最多有3个)是用 来和事件的Keccak哈希签名一起作为议题的日志记录;那些没有建立索引的用来组成事件的字节数组。
[1] Vitalik Buterin.Merkling inEthereum.https://blog.ethereum.org/2015/11/15/merkling-in-ethereum.November 15th,2015.
[2] Ethereum Wiki,Patricia Tree.https://github.com/ethereum/wiki/wiki/Patricia-Tree.
[3] RLPx是一个采用密码方式通信的P2P网络协议,为应用在P2P网络上通信提供通用的传输和接口。RLPx是专门为去中心化应用设计的P2P通信协议。
来源:我是码农,转载请保留出处和链接!
本文链接:http://www.54manong.com/?id=1028