详解以太坊的工作原理

尚力财经 183 0

本文主要讲解以太坊的基本原理,对技术感兴趣的朋友可以看看。

译者:许立原地址:以太坊到底是怎么运作的?

不管你知不知道什么是以太坊区块链,你大概都听说过。最近多次出现在新闻中,包括一些专业杂志的封面,但是如果你对以太坊是什么没有一个基本的了解,看这些文章会觉得是在读天书。那么,以太坊是什么?本质上,它是一个公共数据库,保存数字交易的永久记录。重要的是,这个数据库不需要任何中央机构来维护和保护它。相反,它作为一个“不可信”的交易系统运行——一个个人在不信任任何第三方或另一方的情况下进行点对点交易的框架。

详解以太坊的工作原理-第1张图片-尚力财经

还在迷茫?这就是这篇文章存在的原因。我的目标是在技术层面上解释以太坊的工作原理,但不会有复杂的数学问题,也不会有可怕的公式。即使你不是程序员,我也希望你看完之后至少对技术有更好的理解。如果有些部分技术性太强,理解不了,这是很正常的,真的没有必要去完全理解每一个小细节。我建议我们只是对事物有一个宏观的认识。

本文中的很多点都是以太坊黄皮书中所讨论的概念的细分。为了更容易理解以太坊,我添加了自己的解释和图解。那些足够勇敢的人可以挑战技术,阅读以太坊黄皮书。

好了,开始吧!

一个区块链是一个具有共享状态的密码安全事务性单机。[1]这有点长,不是吗?我们分开来看:

“密码安全”是指使用一种复杂的数学机制算法,很难求解,来保证数字货币的生产安全。你可以把它想象成一个防火墙。它们使得欺骗系统几乎是不可能的(比如构造一个假的交易,消除一个交易,等等。).“事务性单例机器”意味着只有一个权威的机器实例负责系统中生成的事务。换句话说,每个人都相信的全球真理只有一个。“共享状态”意味着存储在这台机器上的状态是共享的,对所有人开放。

以太坊实现了区块链的这个例子。

以太坊本质上是一个基于事务的状态机。在计算机科学中,a?状态机?指的是能够读取一系列输入的东西,然后根据这些输入,将其转化为一种新的状态。详解以太坊的工作原理-第2张图片-尚力财经

根据以太坊的状态机,我们从创世态开始。这几乎类似于一张白纸,网络中没有任何交易。当事务被执行时,这个起源状态将被转换成最终状态。在任何时刻,这个最终状态都代表以太坊的当前状态。详解以太坊的工作原理-第3张图片-尚力财经

以太坊状态下有数百万笔交易。这些事务被“分组”到一个块中。一个块包含一系列事务,每个块都与其前一个块相链接。详解以太坊的工作原理-第4张图片-尚力财经

为了从一个状态转移到下一个状态,事务必须有效。为了使一个交易被认为是有效的,它必须通过一个验证过程,这就是挖掘。挖掘是一组节点(即计算机)使用它们的计算资源来创建包含有效事务的块。

网络上任何声称是挖掘者的节点都可以尝试创建和验证块。世界各地的许多矿工同时创建和验证区块。 每个矿工在向区块链提交区块时,都会提供一份数学机制的“证明”。这个证明就像一个保证:如果这个证明存在,那么这个块一定是有效的。

为了将块添加到主链中,一个矿工必须比其他矿工更快地提供这个“证明”。通过矿工提供的一种数学机制的“证明”来验证每个区块的过程,称为工作证明。

确认一个新区块的矿工会获得一定数值的奖励。奖励是什么?以太坊使用一个固有的数字令牌——以太作为奖励。矿工每证明一个新块,就会产生一个新的以太币奖励给矿工。

你可能在想:什么能保证所有人都只在同一条区块链上?怎么能确定部分矿工不会自创链条呢?

在前面,我们将区块链定义为具有共享状态的单个事务机器。利用这个定义,我们可以知道正确的当前状态是一个全局真理,每个人都必须接受它。拥有多个状态(或链)会破坏系统,因为不可能得到一个关于哪个是正确状态的统一结果。如果链是分叉的,你可能一条链上有10个硬币,一条链上有20个硬币,另一条链上有40个硬币。在这种情况下,没有办法确定哪个链是最“有效”的。

每当生成多条路径时,就会出现一个“分叉”。我们通常希望避免分叉,因为它们会破坏系统,迫使人们选择相信哪条链。详解以太坊的工作原理-第5张图片-尚力财经

为了确定哪条路径最有效,并防止多条链的产生,以太坊使用了一种数学机制,称为“GHOST协议”。

鬼?=?贪婪最重观察子树

简单来说,GHOST协议让我们不得不选择一条路径,在这条路径上完成最多的计算。确定路径的一种方法是使用最新块(叶块)的块号,它代表当前路径上的块总数(不包括Genesis块)。块号越大,路径就会越长,也就是说在这条路径上要消耗更多的挖掘计算能力才能到达叶子块。使用这种推理可以让我们同意当前状态的权威版本。详解以太坊的工作原理-第6张图片-尚力财经

现在你可能对什么是区块链有了理性的理解。让我们更深入地了解一下以太坊系统的主要组成部分:

账户(状态)损失和费用(气和费)事务(块)事务执行(挖掘)工作证明

在开始之前,我们需要注意:每当I. Hash,这是以太坊使用的Hash算法。

以太坊的全局“共享状态”由许多小对象(账户)组成,这些小对象可以通过消息传递架构相互交互。每个账户都有一个州和与之相关的20字节地址。在以太坊中,地址是一个160位的标识符,用于标识账户。

这是两种类型的帐户:

外部拥有的帐户,由私钥控制且没有任何与其相关联的代码的合同帐户,以及由其合同代码控制且与其相关联的帐户

详解以太坊的工作原理-第7张图片-尚力财经

外部拥有的帐户和合同帐户之间的比较了解外部拥有的帐户和合同帐户之间的基本差异非常重要。外部拥有的帐户可以通过用自己的私钥创建和签署交易来向另一个外部拥有的帐户或合同帐户发送消息。在两个外部拥有的帐户之间传输的消息只是简单的值传递。然而,从外部拥有的账户到合同账户的消息将激活合同账户的代码,允许它执行各种动作。(如转移令牌、写入内存、挖掘新令牌、执行某些操作、创建新契约等。).

与外部拥有的账户不同,合约账户不能自己发起交易。 相反,合约账户仅在收到交易(来自外部拥有的账户或另一合约账户)后触发交易以响应交易。我们将在“事务和消息”一节中了解合同之间的通信。

详解以太坊的工作原理-第8张图片-尚力财经

因此,以太坊中的任何动作总是由外部控制账户触发的交换发起的。

详解以太坊的工作原理-第9张图片-尚力财经

帐户状态帐户状态有四个组成部分,无论帐户类型如何都存在:

nonce:如果帐户是外部拥有的帐户,nonce表示从此帐户地址发送的交易序列号。如果账户是合同账户,nonce表示该账户创建的合同序列号余额:该地址的号码为Wei。1 ether=10 18 weistorageroot:Merkle Patricia树的根节点的哈希值(我们后面会解释Merkle树)。Merkle tree会对这个账号的存储内容的哈希值进行编码,默认值为null codeHash:这个账号的EVM(以太坊虚拟机,后面会详细描述)代码的哈希值。对于合约帐户,它是经过哈希处理并保存为codeHash的代码。对于外部拥有的账户,codeHash字段为空字符串Hash值

详解以太坊的工作原理-第10张图片-尚力财经

world state 好了,我们知道以太坊的全局状态是由账户地址和账户状态的映射组成的。这种映射存储在一种叫做Merkle Patricia Tree

Merkle Tree(也称为Merkle trie)的数据结构中,是一种由一系列节点组成的二叉树,这些节点包括:

一系列中间节点,在树的底部包含大量源数据的叶子节点,这些叶子节点是两个子节点和一个根节点的哈希值。也是两个子节点的Hash值,也就是说整个树

详解以太坊的工作原理-第11张图片-尚力财经

的底层数据是通过把我们要保存的数据分离成块,然后把块分成桶,然后获取每个桶的Hash值,重复这个过程,直到只剩下一个Hash: root hash。详解以太坊的工作原理-第12张图片-尚力财经

这个树要求树中的所有值都有一个对应的键。从树的根节点开始,键会告诉你可以跟随哪个子节点获得相应的值,这个值存在于叶节点中。在以太坊中,key/value是地址和与地址关联的账户之间的状态映射,包括每个账户的余额、nonce、codeHash和存储根(存储根本身就是一棵树)。详解以太坊的工作原理-第13张图片-尚力财经

相同的树结构用于存储交易和收据。更具体地说,每个块Hash一个header,其中保存了三种不同Merkle trie结构的根节点的Hash,包括:

状态树、事务树、收据树

详解以太坊的工作原理-第14张图片-尚力财经

在Merkle tries中存储所有信息的效率对于以太坊中的“轻客户端”和“轻节点”是相当有用的。记住,区块链是由一组节点维护的。广义来说,有两种类型的节点:全节点和轻节点。

所有节点通过下载整个链来同步,执行从Genesis块到当前块包含在其中的所有事务。通常,挖掘者会存储所有节点,因为他们在挖掘过程中需要所有节点。也可以下载一个完整的节点,而不执行所有的事务。在任何情况下,一个完整的节点包含整个链。

但是除非一个节点需要执行所有事务或者方便地访问历史数据,否则没有必要保存整个链。这就是光节点概念的由来。与下载存储整个链并执行其中的所有事务相比,light节点只下载链的头,从Genesis块到当前块的头,不执行任何事务,也不检索任何关联状态。因为轻节点可以访问块的头,并且头包含三次尝试的散列,所以所有轻节点仍然可以容易地生成和接收关于事务、事件、余额等等的可验证的答案。

这样做是因为哈希值在Merkle树中向上传播——如果恶意用户试图用一个伪造的事务交换Merkle树底部的事务,这将改变它上面的节点的哈希值,它上面的节点的值的改变也将导致前一个节点的哈希值的改变,以此类推,直到树的根节点。

详解以太坊的工作原理-第15张图片-尚力财经

任何想验证某些数据的节点都可以通过Merkle proof来验证。Merkle proof由

一个需要验证的数据树的根节点Hash,一个“分支”(from?从组块到根的路径上的所有哈希值)

详解以太坊的工作原理-第16张图片-尚力财经

任何能阅读证明的人都能验证分支的哈希是连贯的,所以给定块在树中的实际位置在这里。

简而言之,使用Merkle Patricia树的好处是,结构的根节点的加密依赖于树中存储的数据,点的hash也可以作为数据的安全标识符。由于块头包含状态、交易和收据树的根hash,任何节点都可以验证以太坊状态的一小部分,而不需要保存整个状态,整个状态的大小可能非常大。

气和费用以太坊中一个更重要的概念是费用。以太坊网络上交易产生的每一个计算都会产生费用——天下没有免费的午餐。这笔费用由所谓的“煤气”支付。

gas用于衡量特定计算中所需的成本单位。汽油价格是你愿意在每种汽油上花费的乙醚量,用“gwei”来衡量。“卫”是乙醚的最小单位,1Ether的意思是10 ^ 18卫。1 g卫就是1亿个卫。

对于每笔交易,发送方设置燃气限额和燃气价格。气体限制和气体价格表示发送者愿意为执行交易支付的最大Wei。

例如,假设发送方设置气限为50000,气价为20g魏。这意味着发送者愿意支付至多50,000 * 20g魏=1,000,000,000,000魏=0.001乙醚来执行该交易。

详解以太坊的工作原理-第17张图片-尚力财经

记住,燃气限额代表用户愿意在燃气上花费的最大金额。如果他们的帐户余额中有足够的乙醚来支付这笔最高费用,那么就没有问题。在交易结束时,任何未使用的气体将被返还给发送者,并按照原始价格进行交换。

详解以太坊的工作原理-第18张图片-尚力财经

如果发送方没有提供足够的gas来执行交易,那么交易执尚力财经小编2022行将是“gas不足”,然后将被视为无效。在这种情况下,事务处理将被终止,所有已更改的状态将被恢复,最后我们将返回到事务之前的状态——完全之前的状态,就好像事务从未发生过一样。因为机器在用完气之前还在努力计算,所以理论上不会有气返回给发送方。

详解以太坊的工作原理-第19张图片-尚力财经

这些油钱都去哪了?寄件人花在煤气上的所有钱都寄到“受益人”地址,这个地址通常是矿工的地址。因为矿工已经努力计算和核实交易,矿工接受天然气的成本作为奖励。

尚力财经小编2022详解以太坊的工作原理-第20张图片-尚力财经

通常,发送方愿意支付更高的气价,矿工总能从这笔交易中获得更多价值。所以矿商更愿意选择这种交易。这样,矿工可以自由选择他们想要核实或忽略的交易。为了指导发送方应该设置多少天然气价格,矿工可以选择建议最低天然气价格,并且他们愿意执行交易。储存也有成本,不仅是天然气仅是用来支付计算这一步的费用,而且也用来支付存储的费用。存储的总费用与所使用的32位字节的最小倍数成比例。

存储费用有一些比较细微的方面。比如,由于增加了的存储增加了所有节点上的以太坊状态数据库的大小,所以激励保持数据存储量小。为了这个原因,如果一个交易的执行有一步是清除一个存储实体,那么为执行这个操作的费用就会被放弃,并且由于释放存储空间的退款就会被返回给发送者。费用的作用是什么?

以太坊可以运作的一个重要方面就是每个网络执行的操作同时也被全节点所影响。然而,计算的操作在以太坊虚拟机上是非常昂贵的。因此,以太坊智能合约最好是用来执行最简单的任务,比如运行一个简单的业务逻辑或者验证签名和其他密码对象,而不是用于复杂的操作,比如文件存储,电子邮件,或机器学习,这些会给网络造成压力。施加费用防止用户使网络超负荷。

以太坊是一个图灵完备语言(短而言之,图灵机器就是一个可以模拟任何电脑算法的机器。对于图灵机器不太熟悉的人可以看看这个?和这个?)。这就允许有循环,并使以太坊受到停机问题?的影响,这个问题让你无法确定程序是否无限制的运行。如果没有费用的话,恶意的执行者通过执行一个包含无限循环的交易就可以很容易的让网络瘫痪而不会产生任何反响。因此,费用保护网络不受蓄意攻击。你也许会想,“为什么我们还需要为存储付费?”其实就像计算一样,以太坊网络上的存储是整个网络都必须要负担的成本。

交易和消息

之前说过以太坊是一个基于交易的状态机。换句话说,在两个不同账户之间发生的交易才让以太坊全球状态从一个状态转换成另一个状态。

最基本的概念,一个交易就是被外部拥有账户生成的加密签名的一段指令,序列化,然后提交给区块链。有两种类型的交易:消息通信和合约创建(也就是交易产生一个新的以太坊合约)。

不管什么类型的交易,都包含:

nonce:发送者发送交易数的计数gasPrice:发送者愿意支付执行交易所需的每个gas的Wei数量gasLimit:发送者愿意为执行交易支付gas数量的最大值。这个数量被设置之后在任何计算完成之前就会被提前扣掉to:接收者的地址。在合约创建交易中,合约账户的地址还没有存在,所以值先空着value:从发送者转移到接收者的Wei数量。在合约创建交易中,value作为新建合约账户的开始余额v,r,s:用于产生标识交易发生着的签名init(只有在合约创建交易中存在):用来初始化新合约账户的EVM代码片段。init值会执行一次,然后就会被丢弃。当init第一次执行的时候,它返回一个账户代码体,也就是永久与合约账户关联的一段代码。data(可选域,只有在消息通信中存在):消息通话中的输入数据(也就是参数)。例如,如果智能合约就是一个域名注册服务,那么调用合约可能就会期待输入域例如域名和IP地址

在“账户”这个章节中我们学到交易—消息通信和合约创建交易两者都总是被外部拥有账户触发并提交到区块链的。换种思维思考就是,交易是外部世界和以太坊内部状态的桥梁。

详解以太坊的工作原理-第21张图片-尚力财经但是这也并不代表一个合约与另一个合约无法通信。在以太坊状态全局范围内的合约可以与在相同范围内的合约进行通信。他们是通过“消息”或者“内部交易”进行通信的。我们可以认为消息或内部交易类似于交易,不过与交易有着最大的不同点—它们不是由外部拥有账户产生的。相反,他们是被合约产生的。它们是虚拟对象,与交易不同,没有被序列化而且只存在与以太坊执行环境。

当一个合约发送一个内部交易给另一个合约,存在于接收者合约账户相关联的代码就会被执行。详解以太坊的工作原理-第22张图片-尚力财经

一个重要需要注意的事情是内部交易或者消息不包含gasLimit。因为gas limit是由原始交易的外部创建者决定的(也就是外部拥有账户)。外部拥有账户设置的gas limit必须要高到足够将交易完成,包括由于此交易而长生的任何”子执行”,例如合约到合约的消息。如果,在一个交易或者信息链中,其中一个消息执行使gas已不足,那么这个消息的执行会被还原,包括任何被此执行触发的子消息。不过,父执行没必要被还原。

区块详解以太坊的工作原理-第23张图片-尚力财经

所有的交易都被组成一个”块”。一个区块链包含了一系列这样的链在一起区块。

在以太坊中,一个区块包含:Ommers解释

“ommer”到底是什么? ommer就是一个区块的父区块与当前区块父区块的父区块是相同的。让我们快速了解一下ommers是用来干嘛的,并且为什么一个区块需要为ommers包含区块头。

由于以太坊的构造,它的区块生产时间(大概15秒左右)比其他的区块链例如Bitcoin(大概10分钟左右)要快很多。这使得交易的处理更快。但是,更短的区块生产时间的一个缺点就是:更多的竞争区块会被矿工发现。这些竞争区块同样也被称为“孤区块”(也就是被挖出来但是不会被添加到主链上的区块)。Ommers的目的就是为了帮助奖励矿工纳入这些孤区块。矿工包含的ommers必须是有效的,也就是ommers必须在父区块的第6个子区块之内或更小范围内。在第6个子区块之后,陈旧的孤区块将不会再被引用(因为包含老旧的交易会使事情变得复杂一点)。

Ommer区块会收到比全区块少一点的奖励。不管怎样,依然存在激励来让矿工们纳入孤区块并能从中获得一些报酬。

区块头

让我们再回到区块的问题上。我们前面提到每个区块都有一个“区块头”,但这究竟是什么?

区块头是一个区块的一部分,包含了:

注意每个区块是怎么样包含三个树结构的,三个树结构分别对应:

状态(stateRoot)交易(transactionsRoot)收据(receiptsRoot)

这三个树结构就是我们前面讨论的Merkle Patricia树。详解以太坊的工作原理-第24张图片-尚力财经

另外,上面描述的有几个术语值得说明一下,接下来来看一下。

日志

以太坊允许日志可以跟踪各种交易和信息。一个合约可以通过定义“事件”来显示的生成日志。

一个日志的实体包含:日志被保存在bloom过滤器?中,过滤器高效的保存了无尽的日志数据。

交易收据

自于被包含在交易收据中的日志信息存储在头中。就像你在商店买东西时收到的收据一样,以太坊为每笔交易都产生一个收据。像你期望的那样,每个收据包含关于交易的特定信息。这些收据包含着:

区块序号区块Hash交易Hash当前交易使用了的gas在当前交易执行完之后当前块使用的累计gas执行当前交易时创建的日志等等

区块难度区块的难度是被用来在验证区块时加强一致性。创世纪区块的难度是131,072,有一个特殊的公式用来计算之后的每个块的难度。如果某个区块比前一个区块验证的更快,以太坊协议就会增加区块的难度。

区块的难度影响nonce,它是在挖矿时必须要使用proof-of-work算法来计算的一个hash值。区块难度和nonce之间的关系用数学形式表达就是:

Hd代表的是难度。

找到符合难度阈值的nonce唯一方法就是使用proof-of-work算法来列举所有的可能性。找到解决方案预期时间与难度成正比—难度越高,找到nonce就越困难,因此验证一个区块也就越难,这又相应地增加了验证新块所需的时间。所以,通过调整区块难度,协议可以调整验证区块所需的时间。

另一方面,如果验证时间变的越来越慢,协议就会降低难度。这样的话,验证时间自我调节以保持恒定的速率—平均每15s一个块。详解以太坊的工作原理-第25张图片-尚力财经

交易执行

我们已经到了以太坊协议最复杂的部分:交易的执行。假设你发送了一笔交易给以太坊网络处理,将以太坊状态转换成包含你的交易这个过程到底发生了什么?

交易必须是正确格式化的RLP。”RLP”代表Recursive Length Prefix,它是一种数据格式,用来编码二进制数据嵌套数组。以太坊就是使用RLP格式序列化对象。有效的交易签名。有效的交易序号。回忆一下账户中的nonce就是从此账户发送出去交易的计数。如果有效,那么交易序号一定等于发送账户中的nonce。交易的gas limit 一定要等于或者大于交易使用的intrinsic gas,intrinsic gas包括:——-1.执行交易预订费用为21,000gas——-2.随交易发送的数据的gas费用(每字节数据或代码为0的费用为4gas,每个非零字节的数据或代码费用为68gas)——-3.如果交易是合约创建交易,还需要额外的32,000gas

发送账户余额必须有足够的Ether来支付”前期”gas费用。前期gas费用的计算比较简单:首先,交易的gas limit乘以交易的gas价格得到最大的gas费用。然后,这个最大gas费用被加到从发送方传送给接收方的总值。详解以太坊的工作原理-第26张图片-尚力财经

怎么样交易符合上面所说的所有要求,那么我们进行接下来步骤。

第一步,我们从发送者的余额中扣除执行的前期费用,并为当前交易将发送者账户中的nonce增加1。此时,我们可以计算剩余的gas,将交易的总gas减去使用的intrinsic gas。详解以太坊的工作原理-第27张图片-尚力财经详解以太坊的工作原理-第28张图片-尚力财经

第二步,开始执行交易。在交易执行的整个过程中,以太坊保持跟踪“子状态”。子状态是记录在交易中生成的信息的一种方式,当交易完成时会立即需要这些信息。具体来说,它包含:

自毁集:在交易完成之后会被丢弃的账户集(如果存在的话)日志系列:虚拟机的代码执行的归档和可检索的检查点退款余额:交易完成之后需要退还给发送账户的总额。回忆一下我们之前提到的以太坊中的存储需要付费,发送者要是清理了内存就会有退款。以太坊使用退款计数进行跟踪退款余额。退款计数从0开始并且每当合约删除了一些存储中的东西都会进行增加。

第三步,交易所需的各种计算开始被处理。详解以太坊的工作原理-第29张图片-尚力财经

当交易所需的步骤全部处理完成,并假设没有无效状态,通过确定退还给发送者的未使用的gas量,最终的状态也被确定。除了未使用的gas,发送者还会得到上面所说的“退款余额”中退还的一些津贴。

一旦发送者得到退款之后:

gas的Ether就会矿工交易使用的gas会被添加到区块的gas计数中(计数一直记录当前区块中所有交易使用的gas总量,这对于验证区块时是非常有用的)所有在自毁集中的账户(如果存在的话)都会被删除

最后,我们就有了一个新的状态以及交易创建的一系列日志。

现在我们已经介绍了交易执行的基本知识,让我们再看看合约创建交易和消息通信的一些区别。

合约创建(Contract creation)

回忆一下在以太坊中,有两种账户类型:合约账户和外部拥有账户。当我们说一个交易是“合约创建”,是指交易的目的是创建一个新的合约账户。

为了创建一个新的合约账户,我们使用一个特殊的公式来声明新账户的地址。然后我们使用接下来的方法来初始化一个账户:一旦我们完成了账户的初始化,使用交易发送过来的init code(查看”交易和信息”章节来复习一下init code),实际上就创造了一个账户。init code的执行过程是各种各样的。取决于合约的构造器,可能是更新账户的存储,也可能是创建另一个合约账户,或者发起另一个消息通信等等。

当初始化合约的代码被执行之后,会使用gas。交易不允许使用的gas超过剩余gas。如果它使用的gas超过剩余gas,那么就会发生gas不足异(OOG)常并退出。如果一个交易由于gas不足异常而退出,那么状态会立刻恢复到交易前的一个点。发送者也不会获得在gas用完之前所花费的gas。

不过,如果发送者随着交易发送了Ether,即使合约创建失败Ether也会被退回来。

如果初始化代码成功的执行完成,最后的合约创建的花费会被支付。这些是存储成本,与创建的合约代码大小成正比(再一次,没有免费的午餐)。如果没有足够的剩余gas来支付最后的花费,那么交易就会再次宣布gas不足异常并中断退出。

如果所有的都正常进行没有任何异常出现,那么任何剩余的未使用gas都会被退回给原始的交易发送者,现在改变的状态才被允许永久保存。

消息通信(Message calls)

消息通信的执行与合约创建比较类似,只不过有一点点区别。

由于没有新账户被创建,所以消息通信的执行不包含任何的init code。不过,它可以包含输入数据,如果交易发送者提供了此数据的话。一旦执行,消息通信同样会有一个额外的组件来包含输出数据,如果后续执行需要此数据的话就组件就会被使用。就像合约创建一样,如果消息通信执行退出是因为gas不足或交易无效(例如栈溢出,无效跳转目的地或无效指令),那么已使用的gas是不会被退回给原始触发者的。相反,所有剩余的未使用gas也会被消耗掉,并且状态会被立刻重置为余额转移之前的那个点。

没有任何方法停止或恢复交易的执行而不让系统消耗你提供的所有gas,直到最新的以太坊更新。例如,假设你编写了一个合约,当调用者没有授权来执行这些交易的时候抛出一个错误。在以太坊的前一个版本中,剩余的gas也会被消耗掉,并且没有任何gas退回给发送者。但是拜占庭更新包括了一个新的“恢复”代码,允许合约停止执行并且恢复状态改变而不消耗剩余的gas,此代码还拥有返回交易失败原因的能力。如果一个交易是由于恢复而退出,那么未使用的gas就会被返回给发送者。

执行模式

到目前为止,我们了解了从开始到结束执行的交易必须经历的一系列的步骤。现在,我们来看看交易究竟是怎么样在虚拟机(VM)中执行的。

协议实际操作交易处理的部分是以太坊自己的虚拟机,称之为以太坊虚拟机(EVM)。像之前定义的那样,EVM是图灵完备虚拟机器。EVM存在而典型图灵完备机器不存在的唯一限制就是EVM本质上是被gas束缚。因此,可以完成的计算总量本质上是被提供的gas总量限制的。

此外,EVM具有基于堆栈的架构。堆栈机器?就是使用后进先出来保存临时值的计算机。

EVM中每个堆栈项的大小为256位,堆栈有一个最大的大小,为1024位。详解以太坊的工作原理-第30张图片-尚力财经

EVM有内存,项目按照可寻址字节数组来存储。内存是易失性的,也就是数据是不持久的。

EVM也有一个存储器。不像内存,存储器是非易失性的,并作为系统状态的一部分进行维护。EVM分开保存程序代码,在虚拟ROM?中只能通过特殊指令来访问。这样的话,EVM就与典型的冯·诺依曼架构?不同,此架构将程序的代码存储在内存或存储器中。

EVM同样有属于它自己的语言:“EVM字节码”,当一个程序员比如你或我写一个在以太坊上运行的智能合约时,我们通常都是用高级语言例如Solidity来编写代码。然后我们可以将它编译成EVM可以理解的EVM字节码。

好了,现在来说执行。详解以太坊的工作原理-第31张图片-尚力财经

在执行特定的计算之前,处理器会确定接下来所说的信息是有效和是否可获取:

系统状态用于计算的剩余gas拥有执行代码的账户地址原始触发此次执行的交易发送者的地址触发代码执行的账户地址(可能与原始发送者不同)触发此次执行的交易gas价格此次执行的输入数据Value(单位为Wei)作为当前执行的一部分传递给该账户待执行的机器码当前区块的区块头当前消息通信或合约创建堆栈的深度

执行刚开始时,内存和堆栈都是空的,程序计数器为0。

1PC: 0 STACK: [] MEM: [], STORAGE: {}

然后EVM开始递归的执行交易,为每个循环计算系统状态和机器状态。系统状态也就是以太坊的全局状态(global state)。机器状态包含:

可获取的gas程序计数器内存的内容内存中字的活跃数堆栈的内容

堆栈中的项从系列的最左边被删除或者添加。

每个循环,剩余的gas都会被减少相应的量,程序计数器也会增加。在每个循环的结束,都有三种可能性:

机器到达异常状态(例如 gas不足,无效指令,堆栈项不足,堆栈项会溢出1024,无效的JUMP/JUMPI目的地等等)因此停止,并丢弃任何的更改进入后续处理下一个循环机器到达了受控停止(到达执行过程的终点)

假设执行没有遇到异常状态,达到一个“可控的”或正常的停止,机器就会产生一个合成状态,执行之后的剩余gas、产生的子状态、以及组合输出。

呼。我们终于过了一遍以太坊最难的部分了。如果你不能完全理解这个部分,也没关系。除非你在理解非常深层次的东西,否则你真的没有必要去理解执行的每个细节。

一个块是怎么样完成的?

最后,让我们看看一个包含许多交易的块是怎么样完成的。

当我们说“完成”,取决于此块是新的还是已存在的,可以指两个不同的事情。如果是个新块,就是指挖这个块所需的处理。如果是已存在的块,就是指验证此块的处理。不论哪种情况,一个块的“完成”都有4个要求:1)验证(或者,如果是挖矿的话,就是确定)ommers在区块头中的每个ommer都必须是有效的头并且必须在当前块的6代之内2)验证(或者,如果是挖矿的话,就是确定)交易区块中的gasUsed数量必须与区块中所列交易使用的累积gas量相等。(回忆一下,当执行一个交易的时候,我们会跟踪区块的gas计数器,也就跟踪了区块中所有交易使用的gas总数量)

3)申请奖励(只有挖矿时)受益人的地址会因为挖矿而获得5Ether(在以太坊EIP-649?提案中,5ETH很快将会被减少为3ETH)。另外,对于每个ommer,当前块的受益人会获得额外的1/32当前块奖励金的奖励。最近,每个ommer区块的受益人能够得到一定量的奖励(有个特殊公式可以进行计算)。

4)校验(或者,如果是挖矿的话,就是计算一个有效的)状态和nonce确保所有的交易和改变的结果状态都被应用了,然后在区块奖励被应用于最终交易结果状态之后定义一个新块为状态。通过检查最终状态与存储在头中的状态树来进行验证。

工作量证明挖矿

在“区块”这个章节简短的说明了一下区块难度这个概念。给予区块难度意义的算法叫做工作量证明(PoW)。

以太坊的工作量证明算法称之为“Ethash”?(之前叫做Dagger-Hashimoto)。算法正式定义为:

在”区块”章节,我们讨论了存在于区块头中的多项。其中两项叫做mixHash和nonce。也许你会回忆起:

mixHash:一个Hash值,当与nonce组合时,证明此区块已经执行了足够的计算nonce:一个Hash值,当与mixHash组合时,证明此区块已经执行了足够的计算

PoW函数就是用来估算这两项的。mixHash和nonce到底是怎么样使用PoW函数来计算出来的有点复杂,如果深入了解的话,我们可以另写一篇文章来讲解了。但是在一个高层面上,它大致就是这样计算的:会为每个区块计算一个”种子”。每个“时期”的种子都不一样,每个时期是30,000个区块长度。对于第一时期,种子就是32位0的hash值。对于后续的每个时期,种子就是前一个种子hash值的hash值。使用这个种子,节点可以计算一个伪随机“缓存”。详解以太坊的工作原理-第32张图片-尚力财经

这个缓存是非常有用的,因为它可以使“轻节点”的概念变成现实,轻节点概念在这篇文章的前面讨论过。轻节点的目的就是让某个节点有能力高效的校验交易而用不着存储整个区块链的数据集。一个轻节点可以仅基于缓存来校验一个交易的有效性,因为缓存可以重新生成需要校验的特定块。

使用这个缓存,节点可以生成DAG“数据集”,数据集中的每项取决于缓存中少量伪随机选择项。为了成为矿工,你需要要生成全数据集,所有全客户端和矿工都保存这个数据集,并且这个数据集随着时间线性增长。

然后矿工可以随机抽取数据集中的部分并将它们放入一个数学函数中Hash出一个”mixHash”。矿工会重复生成mixHash直到输出的值小于想要的目标值nonce。当输出的值符合这个条件的时候,nonce就被认为是有效的,然后区块就被添加到链中。

挖矿作为安全机制

总的来说,PoW的目的就是以加密安全的方式证明生成的一些输出(也就是nonce)是经过了一定量的计算的。因为除了列举所有的可能性,没有更好的其他方法来找到一个低于要求阈值的nonce。重复应用Hash函数的输出均匀分布,所以我们可以确保,在平均值上,找到满足要求的nonce所需时间取决于难度阈值。难度系数越大,所需时间越长。这样的话,PoW算法就给予难度这个概念的意义了:用来加强区块链的安全。

我们所说的区块链的安全又是什么意思?这非常简单:我们想要创造一个每个人都信任的区块链。像我们之前在这篇文章中讨论的那样,如果存在超过1条以上的链,用户的信任就会消失,因为他们没有能力合理的确认哪条链才是“有效的”。为了让一群用户接受存储在区块链中的潜在状态,我们需要有一群人信任的一个权威区块链。这完完全全就是Pow算法所做的事情:它确保特定的区块链直到未来都一直保持着权威性,让攻击者创造一个新区块来重写某个历史部分(例如清除一个交易或者创建一个假的交易)或者保持一个分叉变得非常困难。为了首先让他们的区块被验证,攻击者需要总是比网络上的其他人要更快的解决掉nonce问题,这样网络就会相信他们的链是最重的链(基于我们之前提到的GHOST协议原则)。除非攻击者拥有超过一半的网络挖矿能力(这种场景也被称为大多数51%攻击?),要不然这基本上是不可能的。

挖矿作为财富分配机制

除了提供一个安全的区块链,PoW同样也是分配财富给那些为提供这个安全而花费自己计算力的人的一种方法。回忆一下,一个矿工挖出一个区块的时候会获得奖励,包括:详解以太坊的工作原理-第33张图片-尚力财经为“获胜”区块提供的5 ether静态区块奖励(马上就会变成3 ether?)区块中的交易在区块内所消耗的gas纳入ommers作为区块的一部分的额外奖励

为了保证PoW共识算法机制对安全和财富分配的使用是长期可持续的,以太坊努力灌输这两个特性:在区块链网络中,一个与上面两个特性上述文章内容就是的一个问题是PoW算法是一个SHA256哈希函数。这种函数的缺点就是它使用特殊的硬件(也被称之为ASCIs)可以更加快速高效的解决nonce问题。

为了减轻这个问题,以太坊选择让PoW算法(Ethhash)?提高内存级别难度。意思是此算法被设计为计算出要求的nonce需要大量的内存和带宽。大量内存的需求让电脑平行的使用内存同时计算多个nonce变得极其困难,高带宽的需求让即使是超级电脑同时计算多个nonce也变得十分艰难。这种方式降低了中心化的风险,并为正在进行验证的几点提供了更加公平的竞争环境。

有一件值得注意的事情是以太坊正在从PoW共识机制渐渐转换为一个叫做“权益证明(PoS)”的共识算法。这就是一个比较野心的话题了,我们希望可以在未来的文章中探索这个话题。

总结

呼! 你终于坚持到最后了。我希望如此?

这篇文章中有很多的地方需要消化。如果需要你阅读好几遍才能理解怎么回事,这完全正常。我个人重复阅读了好几次以太坊黄皮书,白皮书,以及代码的不同部分才渐渐明白是怎么回事。无论怎么样,我希望你觉得这篇文章对你有帮助。如果你发现了任何的错误或失误,我很乐意你给我写个私人消息或者直接在评论区评论(我保证我会查看所有评论)。

记住,我是个人类(对,这是真的),我会犯错误。为了社区的利益,我花时间免费写了这篇文章。所以请你在反馈时不要带着没必要的攻击性,尽量是建设性的反馈。

以太坊的黄皮书

标签: p30

抱歉,评论功能暂时关闭!

微信号已复制,请打开微信添加咨询详情!