以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)

目录

这篇介绍性论文最初由以太坊创始人Vitalik Buterin于2013年发表,该项目于2015年启动。值得注意的是,以太坊和许多社区驱动的开源软件项目一样,从一开始就在不断发展。

虽然这篇文章已经出版好几年了,但我们仍然保留它,因为它继续作为一个有用的参考和以太坊及其愿景的准确代表。为了了解以太坊的最新发展,以及如何对协议进行更改,我们推荐本指南

下一代智能合约和去中心化应用平台

中本聪(Satoshi Nakamoto)在2009年开发的比特币,经常被誉为(be hailed as)货币和货币领域的重大发展,成为首个既没有后盾(backing)、也没有内在价值(intrinsic value)、也没有集中化发行方或控制器的数字资产。然而,比特币实验的另一个——可以说(arguably)是更重要的——部分是作为分布式共识工具的底层区块链技术,人们的注意力正迅速转移到比特币的另一个方面。常用的区块链技术的替代应用包括使用区块链数字资产来代表自定义货币和金融工具(彩色硬币),基础物理设备的所有权(智能财产),不可替代的资产,如域名(Namecoin),以及更复杂的应用程序,包括由实现任意规则(智能合约)的代码直接控制数字资产,甚至基于区块链的去中心化自治组织(DAOs)。Ethereum打算提供的是一个区块链,它内置了一种成熟的图灵完整编程语言,可以用来创建“合约”,用来对任意状态转换函数进行编码,允许用户创建上面描述的任何系统,以及我们尚未想象到的许多其他系统,只需在几行代码中写出逻辑。

介绍比特币和现有概念

历史

去中心化数字货币的概念,以及财产登记等替代应用,已经存在了几十年。20世纪80年代和90年代的匿名电子现金协议大多依赖于一种称为Chaumian blinding的加密原语,为货币提供了高度的隐私,但这些协议由于依赖于一个集中的中介机构,基本上未能获得吸引力。1998年,Wei Dai的b-money成为第一个提出通过解决计算难题以及去中心化共识来创造货币的提案,但提案中对于如何真正实现分散共识的细节却很少提及。2005年,Hal Finney引入了可重用工作量证明的概念,这个系统使用了b-money的思想和Adam Back的计算困难的Hashcash谜题来创建加密货币的概念,但由于依赖可信计算作为后端,再次没有达到理想的效果。2009年,中本聪(Satoshi Nakamoto)首次在实践中实现了一种去中心化货币,它结合了通过公钥加密来管理所有权的既定原语,以及用来跟踪谁拥有硬币的共识算法(称为“工作量证明”(proof of work))。

工作量证明背后的机制是该领域的一个突破,因为它同时解决了两个问题。首先,它提供了一种简单且适度有效的共识算法,允许网络中的节点集体同意对比特币分类帐状态的一组规范更新。第二,它提供了一种机制,允许自由进入共识进程,解决了决定谁能够影响共识的政治问题,同时防止sybil攻击。它通过用经济障碍取代参与的正式障碍,例如要求在特定名单上登记为一个独特的实体,来实现这一点——一个节点在协商一致投票过程中的权重与该节点带来的计算能力成正比。此后,一种被称为==权益证明(proof of stake)==的替代方法被提出,它计算一个节点的权重与它的货币持有量成比例,而不是计算资源;关于这两种方法的相对优点的讨论超出了本文的范围,但应该注意的是,这两种方法都可以用作加密货币的支柱。

以下是以太坊创始人Vitalik Buterin关于以太坊史前史的一篇博文。这是另一篇有更多历史的博文

比特币作为一种状态过渡系统

《以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)》
从技术角度来看,比特币等加密货币的账本可以被认为是一个状态转换系统,其中存在一个由所有现有比特币的所有权状态组成的“状态”和一个“状态转换函数”,该函数接受一个状态和一项交易,并输出一个新的状态,即结果。例如,在标准银行系统中,状态为资产负债表,交易是将$X从A移动到B的请求,状态转换功能将A账户中的值减少$X,并将B账户中的值增加$X。如果A的帐户首先少于$X,状态转换函数将返回一个错误。因此,可以正式定义:

APPLY(S,TX) -> S' or ERROR

在上述银行体系中:

APPLY({ Alice: $50, Bob: $50 },"send $20 from Alice to Bob") = { Alice: $30, Bob: $70 }

但是:

APPLY({ Alice: $50, Bob: $50 },"send $70 from Alice to Bob") = ERROR

比特币中的“状态”是所有已开采但尚未使用的硬币(技术上称为“未花费的交易输出”或UTXO)的集合,每个UTXO都有一个面额和一个所有者(由一个20字节的地址定义,该地址本质上是一个加密公钥1).交易包含一个或多个输入,每个输入包含对现有UTXO的引用和由与所有者地址关联的私钥生成的加密签名,以及一个或多个输出,每个输出包含要添加到状态的新UTXO。

状态转移函数APPLY(S,TX) -> S'可大致定义如下:

  1. 对于TX的每一个输入:

    ∘ \circ 如果引用的UTXO不在S中,则返回一个错误。

    ∘ \circ 如果提供的签名与UTXO的所有者不匹配,则返回一个错误。

  2. 如果所有输入UTXO的面额之和小于所有输出UTXO的面额之和,则返回一个错误。

  3. 返回S’,删除所有输入UTXO并添加所有输出UTXO。

第一步的前半部分阻止交易发送者消费不存在的硬币,第一步的后半部分阻止交易发送者消费其他人的硬币,第二步强制执行价值守恒。为了使用它进行支付,协议如下。假设爱Alice想把11.7 BTC发送给Bob。首先,Alice将寻找一组可用的UTXO,该UTXO的总容量至少为11.7 BTC。事实上,Alice将无法得到准确的11.7 BTC;假设她能得到的最小值是6+4+2=12。然后用这三个输入和两个输出创建一笔交易。第一个输出将是11.7个BTC,其所有者是Bob的地址,第二个输出将是剩下的0.3个比特币“找零”,所有者是Alice自己。

挖矿

《以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)》
如果我们可以访问一个值得信任的中央服务,这个系统将是微不足道的实现;它可以完全按照描述进行编码,使用集中式服务器的硬盘驱动器来跟踪状态。然而,对于比特币,我们正试图建立一个去中心化的货币系统,因此我们需要将状态转换系统与共识系统结合起来,以确保每个人都同意交易的顺序。比特币的去中心化共识过程要求网络中的节点不断尝试产生被称为“区块”的交易包。网络的目的是大约每十分钟产生一个块,每个块包含一个时间戳,一个随机数,一个引用(比如前一个区块的哈希,以及自前一个区块以来发生的所有交易的列表。随着时间的推移,这创造了一个持续的、不断增长的“区块链”,它不断更新,以代表比特币分类帐的最新状态。检查一个块是否有效的算法,在这个范例中表示如下:

  1. 检查该块引用的前一个块是否存在并且有效。
  2. 检查该块的时间戳是否大于前一个块2的时间戳并且小于不到未来的2小时。
  3. 检查区块上的工作量证明是有效的。
  4. S[0]为前一个块末尾的状态。
  5. 假设TX是有n个交易的块交易列表。对于所有i0…n-1,设置S[i+1] = APPLY(S[i],TX[i])如果有任何应用程序返回错误,那么退出并返回false。
  6. 返回true,并在该块的末尾注册S[n]作为状态。

本质上,块中的每个交易都必须提供一个有效的状态转换,从交易执行前的规范状态转换到某个新状态。注意,状态并没有以任何方式编码到块中;它纯粹是一个需要验证节点记住的抽象,并且只能(安全地)通过从生成状态开始并连续地应用每个块中的每个交易来计算任何块。另外,注意到矿工将交易包含到区块中的顺序很重要;如果一个块中有两个交易A和B,以至于B花费了A创建的UTXO,那么如果A在B之前,那么这个块将是有效的。

上述列表中存在的一个在其他系统中没有的有效性条件是“工作量证明”的要求。精确的条件是,每个块的双sha256哈希值(作为一个256位的数字)必须小于一个动态调整的目标值,该目标值在写入数据时大约为2187。这样做的目的是使块的创建是计算“困难”的,从而防止sybil攻击者重新制作整个区块链而使他们自己受益。因为SHA256被设计成一个完全不可预测的伪随机函数,创建有效块的唯一方法就是反复试验,反复增加nonce,看看新的哈希是否匹配。

在当前目标~2187处,网络必须平均尝试~269次才能找到一个有效的块;一般来说,每2016个区块由网络重新校准一个目标,平均每10分钟由网络中的某个节点产生一个新的区块。为了补偿这种计算工作的矿工,每个块的矿工有权包括一个不知道从哪里给自己12.5比特币的交易。此外,如果任何交易的输入总面额大于输出总面额,那么差额也会作为“交易费”转给矿工。顺便说一下,这也是BTC发行的唯一机制;创世状态里根本没有硬币。

为了更好地理解挖矿的目的,让我们检查一下在恶意攻击发生时发生了什么。由于已知比特币的底层密码学是安全的,攻击者将攻击比特币系统中没有直接受到密码学保护的部分:交易顺序。攻击者的策略很简单:

  1. 发送100比特币给商家以换取某些产品(最好是快速交付的数字商品)
  2. 等待产品交付
  3. 生成另一个向自己发送相同100比特币的交易
  4. 试着让网络相信他和自己的交易是最先发生的

一旦步骤(1)完成,几分钟后,一些矿工将把该交易包含在一个块中,比如块号270。大约一小时后,该区块之后又有五个区块被添加到链中,每个区块都间接指向该交易,从而“确认”该交易。此时,商户将接受最终付款并交付产品;因为我们假设这是一种数字产品,所以交付是即时的。现在,攻击者创建另一个发送100比特币给自己的交易。如果攻击者只是简单地将其释放到外面,事务将不会被处理;矿工将尝试运行APPLY(S,TX),并注意到TX消耗的UTXO已不再处于状态。因此,攻击者创建了区块链的一个“分叉”,从挖掘另一个版本的块270开始,指向相同的块269作为父块,但是用新的事务代替旧的事务。因为块数据是不同的,这就需要重新做工作量证明。此外,攻击者的新版本的区块270有一个不同的哈希值,所以原始的区块271到275并不“指向”它;因此,原始链和攻击者的新链是完全分开的。规则是,在分叉中,最长的区块链被认为是真理,因此合法的矿工将在275链上工作,而攻击者独自在270链上工作。为了让攻击者使他的区块链最长,他将需要比网络其余部分加起来的计算能力更强,以便赶上(因此,“51%攻击”)。

默克尔树

《以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)》
左:只在Merkle树中呈现少量节点就足以证明分支的有效性。

右:任何改变Merkle树任何部分的尝试最终都会导致链上某处的不一致。

比特币的一个重要的可伸缩性特征是,块存储在一个多层次的数据结构中。块的“哈希”实际上只是块头的哈希,一个大约200字节的数据块,包含时间戳、nonce、以前的块哈希和存储在块中的所有事务的名为Merkle树的数据结构的根哈希。Merkle树是二叉树的一种,由一组节点和大量的位于树的底部的包含基础数据的叶节点,一组中间节点,这些中间节点都是它们各自的两个孩子节点的哈希,最后一个根节点,也是两个孩子节点的哈希,代表树的“顶级”。Merkle树的目的是允许零散地传递块中的数据:节点只能从一个源下载块的头,从另一源下载树的一小部分与它们相关,并且仍然可以放心所有数据都是正确的。之所以起作用,是因为哈希向上传播:如果恶意用户试图将假交易交换到Merkle树的底部,则此更改将导致上方的节点发生更改,然后导致上方的节点发生更改,最后更改树的根,进而更改该块的哈希,从而使协议将其注册为完全不同的块(几乎可以肯定带有无效的工作证明)。

默克尔树协议可以说对于长期可持续性至关重要。 比特币网络中的一个“完整节点”,用于存储和处理每个块的全部,截至2014年4月在比特币网络中占据约15 GB的磁盘空间,并且每月增长超过1 GB。当前,这对于某些台式机而不是手机是可行的,并且在以后的将来,只有企业和业余爱好者才能参加。 称为“简单支付验证”(SPV)的协议允许存在另一类节点,称为“轻节点”,这些节点下载区块头,验证区块头上的工作量证明,然后仅下载“分支” 和与之相关的交易相关联。 这使轻节点能够以强大的安全性确定任何比特币交易的状态及其当前余额,同时仅下载整个区块链的一小部分。

可替代的区块链应用

将潜在的的区块链思想应用到其他概念上的想法也有很长的历史。1998年,Nick Szabo提出了“拥有所有权的安全产权”的概念,这是一份描述“复制数据库技术的新进展”的文件。将允许基于区块链的系统存储谁拥有土地的注册管理机构,精心设计的框架,包括房屋维护,逆权占有和格鲁吉亚土地税等概念。但是,不幸的是,当时没有有效的复制数据库系统可用,因此该协议从未在实践中实现。 但是,在2009年之后,一旦比特币的去中心化共识被开发出来,许多替代应用便迅速出现。

∙ \bullet Namecoin – 创建于2010年,最能描述为去中心化的名称注册数据库。在Tor,Bitcoin和BitMessage等去中心化协议中,需要某种方式来识别帐户,以便其他人可以与它们进行交互,但是在所有现有解决方案中,唯一可用的标识符是伪随机哈希,例如1LW79wp5ZBqaHW1jL5TCiBCrhQYtHagUWy。理想情况下,人们希望能够拥有一个名称为“ george”的帐户。 但是,问题在于,如果一个人可以创建一个名为“ george”的帐户,那么其他人也可以使用相同的过程为自己注册“ george”并模拟他们。唯一的解决方案是先注册的模式,第一个注册者成功,第二个注册者失败——这个问题非常适合比特币共识协议。Namecoin是使用这种理念的最古老、最成功的名称注册系统。

∙ \bullet Colored coins – 它的目的是作为一种协议,使人们可以创建自己的数字货币-或者,在重要的琐碎情况下,在比特币区块链上的一个单位的数字代币。在彩色硬币协议中,一个人通过公开指定一种颜色给特定的比特币UTXO来“发行”一种新货币,并且协议递归地定义了其他UTXO的颜色与创建它们的交易花费的输入的颜色相同(一些特殊规则适用于混合颜色输入的情况)。这使用户可以维护仅包含特定颜色的UTXO的钱包,并像常规比特币一样将它们发送到周围,在区块链中回溯以确定他们收到的任何UTXO的颜色。

∙ \bullet Metacoins – metacoin背后的想法是有一个基于比特币的协议,使用比特币交易来存储metacoin交易,但有一个不同的状态转换功能,APPLY'。因为metacoin协议不能防止无效的metacoin交易出现在比特币区块链中,所以添加了一条规则,如果APPLY'(S,TX)返回错误,协议默认为APPLY'(S,TX) = S。这为创建任意加密货币协议提供了一种简单的机制,可能具有无法在比特币内部实现的高级特性,但开发成本非常低,因为比特币协议已经处理了挖掘和网络的复杂性。metacoin已被用于实现一些类别的金融合约、名称注册和去中心化交易。

因此,一般来说,构建共识协议有两种方法:构建独立的网络,以及在比特币之上构建协议。前一种方法虽然在Namecoin等应用中相当成功,但很难实现;每个实现都需要引导一个独立的区块链,并构建和测试所有必要的状态转换和网络代码。此外,我们预计去中心化共识技术的应用程序集将遵循幂律分布,其中绝大多数应用程序将太小,无法保证自己的区块链,我们注意到存在大量的去中心化应用程序,特别是去中心化自治组织,它们需要彼此交互。

另一方面,基于比特币的方法有一个缺陷,它没有继承比特币简化的支付验证特性。SPV适用于比特币,因为它可以使用区块链深度作为有效性的代理;在某种程度上,一旦交易的祖先足够久远,就可以说他们是国家合法的一部分。另一方面,基于区块链的元协议不能强制区块链不包含在其自己的协议上下文中无效的交易。因此,完全安全的SPV元协议实现需要一直向后扫描比特币区块链的开头,以确定某些交易是否有效。目前,所有基于比特币的元协议的“轻”实现都依赖于一个受信任的服务器来提供数据,可以说这是一个非常次优的结果,尤其是当加密货币的主要目的之一是消除对信任的需要时。

脚本

即使没有任何扩展,比特币协议实际上也促进了“智能合约”概念的弱版本。比特币中的UTXO不仅可以由公钥拥有,还可以由用简单的基于堆栈的编程语言表示的更复杂的脚本拥有。在这个范例中,交易花费UTXO必须提供满足脚本的数据。实际上,甚至基本的公钥所有权机制都是通过脚本实现的:脚本将椭圆曲线签名作为输入,针对拥有UTXO的交易和地址验证它,如果验证成功则返回1,否则返回0。其他更复杂的脚本存在于各种额外的用例中。例如,可以构建一个脚本,该脚本需要从给定的三个私钥中的两个签名来验证(“multisig”),这是一种对公司账户、安全储蓄账户和一些商人托管情况有用的设置。脚本还可以用来支付赏金解决计算问题,甚至可以构建一个脚本,说“如果你能提供一个SPV证明你对我发送这个面额的Dogecoin交易,那么这个比特币UTXO是你的”,本质上允许去中心化的交叉加密货币交换。

然而,在比特币中实现的脚本语言有几个重要的限制:

∙ \bullet 缺乏图灵完整性 – 也就是说,虽然比特币脚本语言支持大量的计算子集,但它几乎不支持所有东西。缺少的主要类别是循环。这样做是为了避免交易验证过程中的无限循环;从理论上讲,这是脚本程序员可以克服的障碍,因为任何循环都可以通过使用if语句多次重复底层代码来模拟,但它确实会导致脚本的空间效率非常低。例如,实现一个替代的椭圆曲线签名算法可能需要256个重复的乘法轮,所有的都单独包含在代码中。

∙ \bullet Value-Blindness – UTXO脚本无法对可以提取的金额提供细粒度控制。例如,预言机合同的一个强大的用例是对冲合同,其中a和B存入价值1000美元的BTC, 30天后脚本将价值1000美元的BTC发送给a,其余的发送给B。这将需要oracle来确定1比特币的美元价值,但即便如此,在信任和基础设施需求方面,与目前可用的完全集中的解决方案相比,这是一个巨大的改进。然而,由于UTXO是全有或全无的,实现这一点的唯一方法是通过非常低效的黑客操作来拥有许多不同名称的UTXO(例如。一个UTXO为2k,每k最多为30),并有O选择哪个UTXO发送给A,哪个发送给B。

∙ \bullet 缺少状态 – UTXO可以被使用,也可以未使用;不存在保留任何其他内部状态的多阶段合同或脚本。这使得多阶段期权合约、去中心化交换要约或两阶段加密承诺协议(安全计算悬赏所必需的)难以制定。这也意味着UTXO只能用于构建简单的、一次性的契约,而不是更复杂的“有状态的”契约,比如去中心化的组织,这使得元协议难以实现。二元状态加上价值盲视也意味着另一个重要的应用——退出限制——是不可能的。

∙ \bullet Blockchain-blindness – UTXO看不到区块链数据,比如nonce、时间戳和之前的块散列。这严重限制了赌博和其他类别的应用,因为它剥夺了脚本语言具有潜在价值的随机性来源。

因此,我们看到在加密货币上构建高级应用程序的三种方法在比特币上使用脚本构建新的区块链,以及在比特币上构建元协议。构建一个新的区块链允许在构建特性集方面有无限的自由,但要付出开发时间、引导工作和安全性的代价。使用脚本很容易实现和标准化,但其功能非常有限,而元协议虽然容易,但在可伸缩性方面存在缺陷。通过以太坊,我们打算建立一个替代框架,在开发的便捷性和更强大的轻客户端属性方面提供更大的收益,同时允许应用程序共享经济环境和区块链安全性。

以太坊

以太坊的目的是为构建去中心化应用程序创建一个替代协议,提供一组不同的权衡,我们认为这对大型去中心化应用程序非常有用,尤其是在快速的开发时间、小型应用程序安全性低、应用程序使用很少的情况下。很少使用的应用程序以及不同应用程序进行非常有效的交互的能力非常重要。以太坊通过构建本质上是终极抽象基础层来做到这一点:带有内置图灵完备编程语言的区块链,允许任何人编写智能合约和去中心化应用程序,他们可以在其中创建自己的所有权,交易格式和状态转换功能。Namecoin的基本版本可以用两行代码编写,其他协议如货币和信誉系统可以用不到20行代码构建。智能合约,即包含价值的加密“盒子”,只有在满足某些条件的情况下才能解锁,也可以建立在平台之上,由于图灵完整性、价值感知、区块链感知和状态等附加功能,智能合约的威力远远超过比特币脚本提供的威力。

原理

以太坊的设计遵循以下原则:

  1. 简单:以太坊协议应该尽可能的简单,即使以一些数据存储或时间效率低下为代价3。一个普通的程序员在理想情况下应该能够遵循并实现整个规范4,从而充分实现加密货币带来的前所未有的民主化潜力,并进一步实现以太坊作为一种对所有人开放的协议的愿景。任何增加复杂性的优化都不应该包括在内,除非该优化提供了非常实质性的好处。
  2. 广泛性:以太坊设计原理的一个基本部分是以太坊没有“特性”5。相反,以太坊提供了一种内部的图灵完备脚本语言,程序员可以使用它来构建任何可以用数学定义的智能合约或交易类型。想发明自己的金融衍生品吗?通过以太坊,你可以。想要创造自己的货币吗?将其建立为以太坊合约。想要建立一个全面的守护程序或天网吗?您可能需要几千个联锁合约,并确保慷慨地提供这些合约,但没有什么能阻止您随时使用以太坊。
  3. 模块性:以太坊协议的各个部分应该设计成尽可能模块化和可分离的。在开发过程中,我们的目标是创建这样一个程序:如果在一个地方对协议进行了小的修改,应用程序堆栈将继续运行,而不需要任何进一步的修改。像Ethash(参见黄皮书附录wiki文章)、修改的Patricia trees(黄皮书wiki)和RLP (YP, wiki)这样的创新应该被实现为独立的、功能完整的库。这样,即使它们在以太坊中使用,即使以太坊不需要某些特性,这些特性在其他协议中也可以使用。以太坊的发展应该最大限度地造福整个加密货币生态系统,而不仅仅是它自己。
  4. 灵活性:以太坊协议的细节并不是一成不变的。以太坊协议的细节并不是一成不变的。尽管我们会非常谨慎地修改高层结构,例如分片路线图,抽象执行,只有数据可用性被共识保护。稍后在开发过程中的计算测试可能会让我们发现某些修改,例如对协议架构或以太坊虚拟机(EVM)的修改,将大幅提高可伸缩性或安全性。如果有这样的机会,我们会加以利用。
  5. 非歧视性和非审查性:协议不应该试图积极地限制或阻止特定类别的使用。议定书中的所有管制机制都应设计成直接管制危害,而不是试图反对具体的不受欢迎的应用。程序员甚至可以在以太坊上运行一个无限循环脚本,只要他们愿意继续支付每个计算步骤的交易费用。

以太坊账户

在以太坊中,状态由称为“账户”的对象组成,每个账户都有一个20字节的地址,状态转换是账户之间的直接价值和信息转移。以太坊账户包含四个字段:

∙ \bullet nonce是一个计数器,用于确保每个交易只能被处理一次

∙ \bullet 该账户的当前以太余额(ether balance)

∙ \bullet 帐户的合约代码,如果存在

∙ \bullet 帐户的存储(默认为空)

以太坊(Ether)”是以太坊的主要内部加密燃料,用于支付交易费用。通常,有两种类型的帐户:由私钥控制的外部拥有帐户(externally owned accounts)和由其契约代码控制的合约帐户(contract accounts)。外部拥有的帐户没有代码,人们可以通过创建和签署交易来从外部拥有的帐户发送消息;在合约帐户中,每当合约帐户收到一条消息时,它的代码就会激活,允许它读取和写入内部存储,并发送其他消息或依次创建合约。

请注意,以太坊中的“合约”不应被视为应该“履行”或“遵守”的东西;相反,它们更像是生活在以太坊执行环境中的“自治代理”,总是在被消息或交易“poked”时执行特定的代码段,并直接控制自己的以太平衡和自己的键/值存储,以跟踪持久变量。

消息和交易

术语“交易”在以太坊中用于指已签名的数据包,该数据包存储从外部拥有的帐户发送的消息。交易包含:

∙ \bullet 消息的接收者

∙ \bullet 标识发件人的签名

∙ \bullet 要从发送方转移到接收方的以太量

∙ \bullet 可选的数据字段

∙ \bullet STARTGAS值,表示允许执行交易的最大计算步骤数

∙ \bullet GASPRICE值,表示发送方每一计算步骤支付的费用

前三个字段是任何加密货币的标准字段。数据字段默认没有功能,但是虚拟机有一个操作码,合约可以使用它来访问数据;作为一个示例用例,如果一个合约作为区块链上的域注册服务,那么它可能希望将传递给它的数据解释为包含两个“字段”,第一个字段是要注册的域,第二个字段是要注册到的IP地址。合约将从消息数据中读取这些值,并将它们适当地放置在存储中。

STARTGASGASPRICE域对以太坊的反拒绝服务模型至关重要。为了防止意外的或恶意的无限循环或代码中的其他计算浪费,每个交易都需要对它可以使用的代码执行的计算步骤设置一个限制。最基本的计算单位是“gas”;通常,一个计算步骤的成本为1 gas,但有些操作的成本更高,因为它们的计算成本更高,或者增加了必须存储为状态一部分的数据量。交易数据中的每个字节还要支付5 gas的费用。收费系统的目的是要求攻击者按比例支付他们所消耗的每一个资源,包括计算、带宽和存储;因此,任何导致网络消耗更多这些资源的交易都必须有大致与增量成比例的gas费用。

消息

合约能够向其他合约发送“消息”。消息是虚拟对象,从不序列化,只存在于以太坊执行环境中。一个消息包含:

∙ \bullet 消息的发送者(隐含的)

∙ \bullet 消息的接收者

∙ \bullet 要与消息一起传输的以太量

∙ \bullet 可选的数据字段

∙ \bullet STARTGAS

从本质上讲,消息类似于交易,只不过它是由合约而不是外部参与者产生的。当当前执行代码的合约执行CALL操作码时,将生成一条消息,该操作码将生成并执行一条消息。与交易一样,一条消息导致收件人帐户运行其代码。因此,合约可以以与外部行为者完全相同的方式与其他合约建立关系。

请注意,由交易或合约分配的gas限额适用于该交易和所有子执行所消耗的gas总量。例如,如果一个外部actor A向B发送一个1000 gas的交易,B在发送消息给C之前消耗600 gas,而C的内部执行在返回之前消耗300 gas,那么B可以在耗尽gas之前再消耗100 gas。

以太坊状态交易函数

《以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)》
以太坊的状态转换函数APPLY(S,TX) -> S'可以定义如下:

  1. 检查交易是否格式良好(例如。具有正确数量的值),签名是有效的,并且nonce与发件人帐户中的nonce匹配。如果不是,则返回一个错误。
  2. 计算交易费用为STARTGAS * GASPRICE,并根据签名确定发送地址。从发件人的帐户余额中减去费用,并增加发件人的nonce。如果没有足够的余额来花费,则返回一个错误。
  3. 初始化GAS = STARTGAS,并从每个字节中提取一定数量的gas,以支付交易中的字节。
  4. 将交易值从发送方帐户转移到接收方帐户。如果接收帐户还不存在,则创建它。如果接收帐户是一个合约,则运行合约的代码直至完成或直到执行结束。
  5. 如果由于发送方没有足够的钱而导致值转移失败,或者代码执行耗尽了gas,则恢复除支付费用外的所有状态更改,并将费用添加到矿工的帐户中。
  6. 否则,将剩余gas的费用退还给发送方,并将已支付的gas费用发送给矿工。

例如,假设合约的代码是:

if !self.storage[calldataload(0)]:
    self.storage[calldataload(0)] = calldataload(32)

注意,实际上合约代码是用低级EVM代码编写的;为了清晰起见,这个示例是用我们的高级语言之一Serpent编写的,可以编译成EVM代码。假设合约的存储一开始是空的,发送的交易包含10个ether值、2000个gas、0.001个ether gasprice和64字节的数据,其中0-31字节表示数字2,32-63字节表示字符串CHARLIE6。在这种情况下,状态转换函数的处理过程如下:

  1. 检查交易是否有效和格式良好。
  2. 检查交易发送方至少拥有2000 * 0.001 = 2 ether。如果是,那么从发送者的帐户中减去2 ether。
  3. 初始化gas = 2000;假设交易长度为170字节,字节费为5,减去850,那么还剩下1150个gas。
  4. 再从发送方的账户中减去10个ether,然后将其添加到合约的账户中。
  5. 运行代码。在本例中,这很简单:它检查索引2处的合约存储是否被使用,注意到没有,因此它将索引2处的存储设置为值CHARLIE。假设这需要187个gas,那么剩余的gas量是1150 – 187 = 963
  6. 将963 * 0.001 = 0.963 ether返回到发送者的帐户,并返回结果状态。

如果在交易的接收端没有合约,那么总交易费用将等于所提供的GASPRICE乘以交易的字节长度,与交易一起发送的数据将是无关的。

注意,就恢复而言,消息的工作等价于交易:如果消息执行耗尽gas,则该消息的执行以及由该执行触发的所有其他执行将恢复,但父执行不需要恢复。这意味着一个合约调用另一个合约是“安全的”,就好像A用G gas调用B,那么A的执行保证最多损失G gas。最后,注意有一个操作码CREATE,它创建了一个合约;它的执行机制通常与CALL类似,但执行的输出决定了新创建合约的代码。

代码执行

以太坊合约中的代码是用一种低级的、基于堆栈的字节码语言编写的,被称为“以太坊虚拟机代码”或“EVM代码”。代码由一系列字节组成,每个字节代表一个操作。在一般情况下,代码的执行是一个无限循环,由反复进行操作的当前程序计数器(从0开始),然后递增程序计数器,直到达到最终的代码或检测到一个错误或STOPRETURN指令。操作可以访问存储数据的三种类型的空间:

∙ \bullet ,一个后进先出的容器,可以向其推送和弹出值

∙ \bullet 内存,一个无限扩展的字节数组

∙ \bullet 合约的长期存储,一个键/值存储。堆栈和内存在计算结束后重置,与之不同的是,存储会长期存在。

该代码还可以访问传入消息的值、发送者和数据,以及块头数据,该代码还可以返回数据的字节数组作为输出。

EVM代码的正式执行模型非常简单。当以太坊虚拟机运行时,其完整的计算状态可以由元组(block_state、transaction、message、code、memory、stack、pc、gas)定义,其中block_state是全局状态,包含所有账户,包括余额和存储。在每一轮执行开始时,通过取CODEpc-th字节找到当前指令(如果pc >= len(code),则为0),并且每个指令都有自己对元组的影响定义。例如,ADD将两个项目从堆栈中取出并推入它们的总和,将gas减少1,将pc增加1,SSTORE将顶部的两个项目从堆栈中取出,并将第二个项目插入到合约存储中,该存储位于第一个项目指定的索引处。虽然有很多方法可以通过即时编译来优化以太坊虚拟机的执行,但以太坊的基本实现只需几百行代码就可以完成。

区块链和挖矿

《以太坊系列(一)---以太坊白皮书(更新于2021年2月9日版本)》
以太坊区块链在很多方面与比特币区块链相似,但也有一些不同之处。以太坊和比特币在区块链架构方面的主要区别在于,与比特币(只包含交易列表的副本)不同,以太坊区块包含交易列表和最新状态的副本。除此之外,块号和难度这两个其他值也存储在块中。以太坊的基本块验证算法如下:

  1. 检查前面引用的块是否存在并且有效。
  2. 检查该块的时间戳大于引用的前一个块的时间戳,并且小于未来15分钟的时间戳。
  3. 检查区块号、难度、交易根、uncle根和gas限制(各种以太坊特定的低级概念)是否有效。
  4. 检查区块上的工作量证明是有效的。
  5. S[0]为前一个块末尾的状态。
  6. TX为块的交易列表,有n个交易。对于所有i0…n-1,设置S[i+1] = APPLY(S[i],TX[i])。如果任何应用程序返回一个错误,或者直到此时块中消耗的总gas超过了GASLIMIT,则返回一个错误。
  7. S_FINALS[n],但增加付给矿工的块奖励。
  8. 检查状态S_FINAL的Merkle树根是否等于块头中提供的最终状态根。如果是,则该块有效;否则,它是无效的。

乍一看,这种方法可能效率非常低,因为它需要将整个状态存储在每个块中,但实际上,效率应该与比特币相当。原因是状态存储在树结构中,每个块之后只需要改变树的一小部分。因此,一般来说,在两个相邻的块之间,树的绝大部分应该是相同的,因此数据可以存储一次,并使用指针(哈希的子树)引用两次。一种称为“Patricia树”的特殊树用于实现这一点,包括对Merkle树概念的修改,允许有效地插入和删除节点,而不仅仅是更改节点。此外,由于所有的状态信息都是最后一个区块的一部分,所以不需要存储整个区块链历史——如果该策略适用于比特币,可以计算出节省5-20倍的空间。

一个常见的问题是,就物理硬件而言,合约代码在“何处”执行。这有一个简单的答案:执行合约的过程代码状态转换函数的定义的一部分,这是块验证算法的一部分,如果一个交易添加到B的代码块执行产生的交易将由所有节点执行,现在和将来,下载并验证块B

一个常见的问题是合约代码在物理硬件上的“执行位置”。 这有一个简单的答案:执行合同代码的过程是状态转换函数定义的一部分,状态转换函数是块验证算法的一部分,因此,如果将交易添加到块B中,则由该交易产生的代码执行将被执行。 由现在和将来的所有节点执行,这些节点下载并验证块B。

注意

  1. 老练的读者可能会注意到,实际上比特币地址是椭圆曲线公钥的哈希,而不是公钥本身。然而,将公钥哈希称为公钥本身实际上是完全合法的密码术语。这是因为比特币的密码学可以被认为是一种定制的数字签名算法,其中公钥由ECC pubkey的哈希组成,签名由ECC pubkey与ECC签名串联而成,验证算法涉及根据ECC pubkey哈希检查签名中的ECC pubkey作为公钥提供,然后根据ECC公钥验证ECC签名。
  2. 技术上,是之前11个区块的中位数。
  3. 以太坊协议应该尽可能简单实用,但可能有必要具有相当高的复杂性,例如规模、存储、带宽和I/O的内化成本、安全性、私密性、透明度等。在需要复杂性的情况下,文档应该尽可能清晰、简洁和最新,这样完全没有接受过以太坊教育的人就可以学习它并成为专家。
  4. 请参阅以太坊虚拟机的黄皮书(作为一个规范和从零开始构建以太坊客户机的参考),以太坊wiki中也有许多主题,如分片开发、核心开发、dapp开发、研究、Casper研发和网络协议。对于研究和未来可能的实施,有[ethresearch .ch](ethresearch .ch)。
  5. 另一种表达方式是抽象。最新的路线图正在计划抽象执行,允许执行引擎不必遵循一个规范规范,但是可以为特定的应用程序和一个分片进行定制。 (这种执行引擎的异构性在路线图中没有明确说明。还有一种是Vlad Zamfir提出的异构分片。)
  6. 在内部,2和“CHARLIE”都是数字,后者以大端256为基数表示。数字至少为0,最多为2256-1。
    原文作者:「已注销」
    原文地址: https://blog.csdn.net/qq_39869387/article/details/115422702
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞