请选择 进入手机版 | 继续访问电脑版

Hi,Tokens

 找回密码
 立即注册
查看: 917|回复: 7

以太坊文章汇编

  [复制链接]

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
发表于 2018-4-22 15:15:26 | 显示全部楼层 |阅读模式
根据以太坊网站介绍:“以太坊是一个去中心化且运行智能合约的平台。”这是一个精确的总结,但在我的经验里,当你第一次向朋友、家人和陌生人解释以太坊时,把以太坊比喻成比特币这会有有大帮助,因为在此之前,很多人至少听说过比特币。这初学者指南应该帮助那些对以太坊不熟悉的人理解两者间存在的高度差异。

比较
简单地说,比特币可以被称为数字货币。比特币已经存在八年了,并且被用于从一方到另一方的转账。它通常被用作价值存储,并且是公众理解分布式数字货币概念的关键方法。
以太坊与比特币不同,它可以允许智能合同被描述为高度可编程的数字货币。想象一下,只有当满足一定的条件时,才会自动将钱从一个人转到另一个人。例如,一个人想要从另一个人那购买房屋。传统上,交易涉及多个第三方,包括律师和托管代理,这使得该过程不必要地缓慢和昂贵。使用以太坊,一段代码可以在协议达成之后自动将自己的房屋所有权转让给买方,并将资金转移给卖方,而无需第三方代替他们执行。
它的潜力是不可思议的! 想想许多作为第三方应用的程序,基于某些设置逻辑(例如Uber,Airbnb,eBay)将您与他人连接。 今天我们使用的许多集中式系统可以以分布式的形式构建在以太坊上。 通过以太坊,您可以使这些交易不受信任,从而打开了分布式程序的整个世界。分布式是很重要的,因为它消除了单点故障或控制。 这使得内部串通和外部攻击不切实际。 分散式平台削减了中间商,最终降低了使用者的成本。我特别亢奋于一些分布式的应用程序。
身份
一个人可以在很多网站上(例如Facebook, Twitter, LinkedIn)创建数字身份。管理这个是很麻烦的,最终有一天,你就不能完全控制它了,因为你的信息是由一个集中实体掌控。使用以太坊,你可以有一个类似uPort的分布式身份管理系统,允许你完全掌控自己的数据。这里没有可以访问您的私人数据、遭受黑客攻击、编辑或关闭你信息的中心服务器。
现在在美国,我们有一些类似银行的机构,依靠把你的信用告诉他们的信用机构(例如Experian, TransUnion, Equifax)。信用局可以使某些群体,例如外国人和年轻人处于不利地位。Lending Club是一个P2P的借贷平台,解决传统金融服务仅
通过提供像房产权,收入和就业时长这些额外数据来给FICO评分。类似uPort的以太坊应用程序,允许你进一步控制自己的数据,身份和声誉。
计算能力/存储
考虑到一个普通人计算机上的所有空闲的计算能力和存储空间,如果它没有被使用,那么为什么不提供给其他人使用呢?这和在Airbnb上出租一间卧室的概念类似。使用分布式应用程序的另一个好处是没有集中的服务器,容易审查。
有几个让项目正在开发中,以允许人们出租多余的计算能力和存储空间。Filecoin项目允许人们出租他们计算机的存储空间而获得报酬。同样,Golem项目允许人们出租他们计算机的计算能力。像这样的想法不是全新的。自2000年以来Folding@home已经允许志愿者为斯坦福大学的科学研究提供多余计算能力。现在,这个概念可以货币化并应用于其他行业,潜在的降低成本。
社会化媒体
Akasha是一个分布式社交媒体平台,没有集中服务器,因此没有一方可以完全控制平台的内容,这意味着该平台抵制审查制度。在以太坊上为社交媒体构建分布式应用程序的另一个好处是,可以创建一个在财务上奖励高质量内容的系统,这就像Reddit,但你可以发送少量的金额给张贴者而不是只点个赞。
权限管理
分布式应用程序可以用来给多个行业带来透明度。例如SingularDTV提供一个娱乐权限管理的平台,允许透明地分配资金给创作者、投资者、船员、演员和其他参与项目的人员。没有集中方可以阻止某一方获得他们的资金,因为这些条款是由代码强制执行的。每个人都将根据前面讨论的条款获得报酬,并且不需要第三方进行调解。
管理公司
开始家新公司最费时间和成本的是分配和管理股份。 随着公司成长和筹集更多资金,他们最终需要发行和交易股票。 Aragon是一个有前景的项目的例子,它有一个易于使用的用于管理公司的财务报表和筹集资本的操作界面。
筹集资本
最后,以太坊的一个主要用途就是从全球投资者网络的分散筹集资金。Crowdsales降低了开发人员开发高风险项目的门槛。 自从以太坊于2015年7月推出以来,我们看到了通过众筹为去中心化应用筹集到前所未有的资金。 以太坊本身是通过一个大众筹集资金,筹集了1800万美元的比特币和一个名为DAO的项目筹集了1.6亿美元。 其他一些值得注意的众筹如下所示:

众筹时提出的金额(不包括估值)
White Paper:
https://github.com/ethereum/wiki/wiki/White-Paper

回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:16:48 | 显示全部楼层
以太坊设计原理
原则
以太坊协议的设计遵循以下几点原则:
1.三明治复杂模型
我们认为以太坊的底层协议应尽可能的简单,接口设计应易于理解,那些不可避免的复杂部分应放入中间层。中间层不是核心共识的一部分,且对最终用户不可见,它包含:高级语言编译器、参数序列化和反序列化脚本、存储数据结构模型、leveldb存储接口以及线路协议等。当然,这样的设置也并非绝对。
2.自由
不应限制用户使用以太坊协议,也不应试图优先支持或不支持某些以太坊合约或交易。这一点与“网络中立”概念背后的指导原则相似。比特币交易协议就没有遵循这一原则。在比特币交易协议中,并不鼓励为了“去除标签”而使用区块链(如,数据存储,元协议)。某些情况下,对准协议进行明显修改会引起不法分子以未经授权方式使用区块链来攻击应用。因此,在以太坊,我们强烈建议设置交易费用,且用户使用区块链的步骤越多,交易费用也就越多(类似庇古税)。这样,既可以将交易费用作为合法矿工的奖励,又能让那些不法分子付出代价,一举两得。
3.泛化
以太坊协议的特性和操作码应最大限度地体现低层次的概念(就像基本粒子一样),以便它们可以随意组合。因此,通过剥离那些不需要的功能,使低层次的概念更加高效。遵循这一原则的例子是,我们选择LOG操作码作为向dapps提供信息的方式,而不是像之前那样记录下所有交易和消息信息。在早先,“消息(message)”的概念完完全全是多种概念的集合,它包含“函数调用(function call)”和“外在观察者感兴趣的事情(event interesting to outside watchers)”,而两者是完全可以分离开来的。
4.没有特点就是最大的特性点
为了遵循泛化原则,我们拒绝将那些高级用例内嵌为协议的一部分,哪怕是经常使用的用例,也绝不这么做。如果人们真的想实现这些用例,可以在合约内创建子协议(如,基于以太坊的子货币,比特币/莱特币/狗币的侧链等)。比如,在以太坊中就缺少类似比特币中的“时间锁定”功能。但是,通过以下协议可以模拟出这个功能:用户发送签名数据包到特定的合约中处理,如果数据包在特定合约中有效,则执行相应的函数。
5.没有风险规避机制
如果风险的增加带来了可观的好处,我们愿意承担更高的风险(例如,广义状态转换,区块时间提升50倍,共识效率)。
这些原则指导着以太坊的发展,但它们并不是绝对的;某些情况下,为了减少开发时间或者不希望一次作出过多改变,也会使我们推迟作出某些修改,把它留到将来的版本中去修改。
区块链层协议
本节对以太坊中区块链层协议的改变进行了描述,包括区块和交易是如何工作的、数据如何序列化及存储、账户背后的机制。
账户 ,而非UTXO①
比特币及其许多衍生品,都将用户的余额信息存储在UTXO结构中,系统的整个状态由一系列的“有效的输出”组成(可以将这些“有效的输出”想象成钱币)。每个UTXO都有拥有者和自身的价值属性。一笔交易在消费若干个UTXO同时也会生成若干个新的UTXO。“有效的输出”中有效需满足下面几点约束:
1.每个被引用的输入必须有效,且未被使用过;
2.交易的签名必须与每笔输入的所有者签名匹配;
3.输入的总值必须等于或大于输出的总值。
因此,比特币系统中,用户的“余额”是该用户的私钥能够有效签名的所有UTXO的总和。下图展示了比特币系统中交易输入输出过程:
但是,以太坊抛弃了UTXO的方案,转而使用更简单的方法:采用状态(state)的概念存储一系列账户,每个账户都有自己的余额,以及以太坊特有的数据(代码或内部存储器)。如果交易发起方的账户余额足够支付交易费用,则交易有效,那么发起方账户会扣除相应金额,而接受账户则计入该金额。某些情况下,接受账户内有需要执行的代码,则交易会触发该代码的执行,那么账户的内部存储器可能就会发生变化,甚至可能会创建额外的信息发送给其他账户,从而导致新的交易发生。
尽管以太坊没有采用UTXO的概念,但UTXO也不乏有一些优点:
1.较高程度的隐私保护
如果用户每次交易都使用一个新的地址,那么账户之间的相互关联就很困难。这样做适用于对安全性要求高的货币系统,但对任何dapp应用来说就不合适了。因为dapp通常需要跟踪用户复杂的绑定状态,而dapp的状态并不能像货币系统中的状态那样简单地划分。
2.潜在地可扩展性
UTXO在理论上可扩展性更好。因为我们只能依靠那些金融货币拥有者来维护能够证明货币所有权的默克尔树,即使所有的人(包括数据的拥有者)都遗忘了某一数据,真正受损也只有数据的拥有者,其他人不受影响。
在以太坊账户系统中,如果一个账户对应在默克尔树中信息被所有人都丢失了,那么该账户将无法处理任何能够影响它的消息,包括发送给它的消息,它也无法处理。
不过,并非只有UTXO能够可扩展,也存在不依赖UTXO就能扩展的方式(此处没有扩展开来讲,译者注)。
账户的好处有以下几点:
1.节省大量空间
如果一个账户有5个UTXO,则从UTXO模式转成账户模式所需空间会从300字节降到30字节。具体计算如下:
300 = (20+32+8)* 5 (20是地址字节数,32是TX的id字节数,8是交易金额值字节数);
30 = 20 + 8 + 2 ( 20是地址字节数,8是交易金额值字节数,2是nonce②字节数)
但实际节约并没有这么大,因为账户需要被存储在帕特里夏树中。另外以太坊中交易也比比特币中的更小(以太坊中100字节,比特币中200-250字节),因为每次交易只需要生成一次引用,一次签名,以及一个输出。
2.可替代性更高
在UTXO结构中,“有效输出”的源码实现中没有区块链层的概念,所以不管是在技术还是法律上,通过建立一个红名单/黑名单,并依据的这些“有效输出”的来源区分它们并不是很实际。
3.简单
以太坊编码更简单、更易于理解,尤其是在涉及到复杂脚本时。尽管任何去中心化应用都可以用UTXO方式来实现,但这种方式实质上是通过赋予一个脚本限制给定的UTXO能够使用以及请求的UTXO的种类的方式来实现,包括脚本评估的应用更改根状态的默克尔树证明。因此,UTXO实现方式比以太坊使用账户的方式要复杂的多。
4.轻客户端
轻客户端可以随时通过沿指定方向扫描状态树来访问与账户相关的所有数据。在UTXO方式中,引用随着每个交易的变化而变化,这对于长时间运行并使用了上文提到的UTXO根状态传播机制的dapp应用来说,无疑是繁重的。
我们认为,账户的好处大大超过了其他方式,尤其是对于我们正在处理的包含任意状态和代码的dapp应用而言。另外,本着“没有特点就是最大的特点”的指导原则,我们认为如果用户真的关心私密性,则可以通过合约中的签名数据包协议来建立一个加密“混合器”进行加密。
账户方式的一个弱点是:为了阻止重播攻击,每笔交易必须有nonce,这就使得账户需要跟踪nonce的使用情况,并且只有在nonce最后使用后且值为1时才接受交易。这就意味着,即使不再使用的账户,也不能从账户状态中移除。解决这个问题的一个简单方法是让交易包含一个区块号,使它们在几个时间段内不重复,并且每个时间段重置nonce。由于完全扫描账户的开销太大,所以为了删除未使用的账户,矿工或用户需要通过“Ping”操作来实现。在1.0上我们没有实现这个机制,1.1及以上版本可能会使用这个机制。
默克尔帕特里夏树
默克尔帕特里夏树(Merkle Patricia tree/trie),由Alan Reiner提出设想,并在瑞波协议中得到实现,是以太坊的主要数据结构,用于存储所有账户状态,以及每个区块中的交易和收据数据。MPT是默克尔树和帕特里夏树的结合缩写,结合这两种树创建的结构具有以下属性:
1.每个唯一键值对唯一映射到根的hash值;在MPT中,不可能仅用一个键值对来欺骗成员(除非攻击者有~2^128 的算力);
2.增、删、改键值对的时间复杂度是对数级别。
MPT为我们提供了一个高效、易更新、且代表整个状态树的“指纹”。
关于MPT更详细描述:https://github.com/ethereum/wiki/wiki/Patricia-Tree
MPT的具体设计决策如下:
1.有两类节点
KV节点和离散节点。KV节点的存在提高了效率,因为如果在特定区域树是稀疏的,KV节点可作为一个“快捷方式”,代替深度为64的树。
2.离散节点是16进制,不是二进制
这样让查找更有效率,我们现在认识到这种选择并不理想,因为16进制树的查找效率在二进制中可以通过批次存储节点来模拟。MPT树的结构实现是非常容易出错的,最终至少会造成状态根不匹配。
3.空值(empty value)与非会员(non-membership)之间没有区别
这样做是为了简化逻辑,以太坊中未设置的值默认为0,空字符串也用0表示。然而,需要强调的是,这样做牺牲了一些通用性,因而也不是最优的。
4.终节点和非终节点的区别
技术上,标识一个节点“是否是终节点”是没必要的,因为以太坊中所有的树都被用于存储静态秘钥长度,但为了增加通用性,我们还是会添加这个标识,以期望以太坊的MPT的实现方式能够被其他加密货币原样采纳。
5.在安全树中采用SHA3(k)作为秘钥(在状态树和账户存储树中使用)
使用SHA3(k),通过设置离散节点的链的深度为64,以及反复调用SLOAD 和 SSTORE指令,使那些企图对树采取Dos攻击的行为变得非常困难。不过,这也让穷举树的节点变得困难,如果你希望你的客户端有穷举的能力,最简单的方法是维持一个数据库映射:sha3(k) -> k
RLP
RLP(recursive length prefix):递归长度前缀。
RLP编码是以太坊中主要的序列化格式,它的使用无处不在:区块、交易、账户状态以及线路协议消息。详见RLP正式描述: https://github.com/ethereum/wiki/wiki/RLP
RLP旨在成为高度简化的序列化格式,它唯一的目的是存储嵌套的字节数组③。不同于protobuf、BSON等现有的解决方案,RLP并不定义任何指定的数据类型,如Boolean、floa、double或者integer。它仅仅是以嵌套数组的形式存储结构,并将其留给协议来确定数组的含义。RLP也没有明确支持map集合,半官方的建议是采用 [[k1, v1], [k2, v2], ...] 的嵌套数组来表示键值对集合,k1,k2 ... 按照字符串的标准排序。
与RLP具有相同功能的方案是protobuf或BSON,它们是一直被使用的算法。然而,以太坊中,我们更偏向于使用RLP,因为:
1.它易于实现;
2.绝对保证字节的一致性。
许多语言的Map集合没有明确的排序,并且浮点格式有很多特殊情况,这可能造成相同数据却导致不同编码和hash值。通过内部开发协议,我们能确保它是带着这些目标设计的(这是一般原则,也适用于代码的其他部分,如VM)。BitTorrent使用的编码方式bencode也许可以替代RLP。不过它采用的是十进制的编码方式,与采用二进制的RLP相比,稍微逊色了点。
压缩算法
线路协议和数据库都采用了一个自定义的压缩算法来存储数据。该算法可描述为:行程编码④值为0并同时保留其他值(除了一些特殊情况如sha3(' ') ),举例如下:
>>> compress('horse')'horse'>>> compress('donkey dragon 1231231243')'donkey dragon 1231231243'>>> compress('\xf8\xaf\xf8\xab\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe{b\xd5\xcd\x8d\x87\x97')'\xf8\xaf\xf8\xab\xa0\xfe\x9e\xbe{b\xd5\xcd\x8d\x87\x97'>>> compress("\xc5\xd2F\x01\x86\xf7#<\x92~}\xb2\xdc\xc7\x03\xc0\xe5\x00\xb6S\xca\x82';{\xfa\xd8\x04]\x85\xa4p")‘\xfe\x01'
压缩算法存在之前,以太坊协议的许多地方都有一些特殊情况,例如,sha3经常被覆盖,所以sha3(' ')=' ',这样不需要在账户中存储代码,可以节省64字节。然而,最近所有这些使得以太坊数据结构变得臃肿的特殊情况都被删除了,取而代之的是将数据保存函数添加到区块链协议之外的层,也就是将其放入线路协议以及将其插入用户数据库实现。这样增加了模块化能力,简化了共识层,使得压缩算法能持续更新以便相对容易部署。
树(trie)的使用
以太坊区块链中每个区块头都包含指向三个树的指针:状态树、交易树、收据树。
状态树代表访问区块后的整个状态;
交易树代表区块中所有交易,这些交易由index索引作为key;(例如,k0:第一个执行的交易,k1:第二个执行的交易)
收据树代表每笔交易相应的收据。交易的收据是一个RLP编码的数据结构:
[ medstate, gas_used, logbloom, logs ]
其中:
• medstate:交易处理后,树的根的状态;
• gas_used:交易处理后,gas的使用量;
• logs:是表格[address, [topic1, topic2...], data]元素的列表。表格由交易执行期间调用的操作码LOG0 ... LOG4 生成(包含主调用和子调用);address 是生成日志的合约的地址topics是最多4个32字节的值;data 是任意字节大小的数组;
• logbloom:交易中所有logs的address和topic组成的布隆过滤器⑤。
区块头中也存在一个布隆过滤器,它是区块中交易的所有布隆过滤器的逻辑或组成。这样的构造使得以太坊协议轻客户端的使用尽可能的友好。
Uncle块(过时区块)的奖励
2013年10月,由乔森纳和特拉维夫首次提出的GHOST协议是一项不起的革新。它是加快生成区块时间的第一个认真尝试。因为区块在网络中传播需要一定时间,如果矿工A挖到一个区块并向全网广播,在广播的路上,B也挖出了区块,那么B的区块是过时的,且B的本次挖矿对网络的安全没有贡献。GHOST的目的正是要解决挖矿过时造成的安全性降低的问题。
此外,还有一个中心化问题:如果A是一个矿池,有30%的算力,B有10%的算力。A有70%的时间产生过时的区块(因为另外的30%时间会产生最新区块,所以它会立即挖到数据),而B有90%的时间产生过时区块。如果区块的产出时间间隔很短,那么过时率就会变高,则A凭借其更大的算力使挖矿效率也更高。所以,区块生成过快,容易导致网络算力大的矿池控制挖矿过程。
根据乔森纳和特拉维夫的描述,GHOST解决了在计算哪个链是最长的链的过程中,因产生过时区块而造成的网络安全性下降的问题。也就是说,不仅是父区块和更早的区块,同时Uncle区块⑥也被添加到计算哪个块具有最大的工作量证明中去。
为了解决第二个问题:中心化问题,我们采用不同的策略:对过时区块也提供区块奖励:挖到过时区块的奖励是该区块基础奖励的7/8;挖到包含过时区块的nephew区块将收到1/32的基础奖励作为赏金。但是,交易费并不奖励给Uncle区块或nephew区块。
在以太坊,过时分叉上7代内的亲属区块才能称作过时区块。之所以这样限制是因为,首先,GHOST协议若不限制过时区块数量,将会花费大量开销在计算过时区块的有效性上;其次,无限制的过时区块激励政策会让矿工失去在主链上挖矿的热情;最后,计算表明,过时区块奖励政策限制在7层内提供了大部分所需的效果,而且不会带来负面效应。
区块时间算法的设计决策包括:
区块时间12s:选择12s是因为这已经是最快的时间了,基本上比网络延迟更长。在2013年的一份关于测量比特币网络延迟的论文中,确定了12.6秒是新产生的区块传播到95%节点的时间;然而,该论文还指出传播时间与区块大小成比例,因此在更快的货币中,我们可以期待传播时间大大减少。传播间隔时间是恒定的,约为2秒。然而,为了安全起见,在我们的分析中,我们假定区块的传播需要12秒。
7个祖先块的限制:这样设计的目的是希望只保留少量区块,而将更早之前的区块清除。已经证明7个区块可以提供大部分所需的效果。
1个后裔区块的限制:如c(c(p(p(p(head))))) c=child, p = parent,就不合法,因为它有两个后裔区块。这样设计的目的是为了简单,上面的模拟结果显示它并没有构成大的中心化风险。
• **uncle块要求具有有效性: **uncle块必须是有效的header,而不是有效的区块。这样做也是为了简化,将区块链模型保持为线性数据结构。不过,要求uncle块是有效的区块也是合法的方法。
奖金分配:7/8的挖矿基础奖励分配给uncle块,1/32分给nephew块,它们交易费用都是0%。如果费用占多数,从中心化的角度看,这会使uncle块激励机制无效;然而,这也是为什么只要我们继续使用PoW,以太坊就会不断发行以太币的原因。
难度更新算法
目前以太坊通过以下规则进行难度更新:
diff(genesis) = 2^32diff(block) = diff.block.parent + floor(diff.block.parent / 1024) *    1 if block.timestamp - block.parent.timestamp < 9 else    -1 if block.timestamp - block.parent.timestamp >= 9
难度更新规则的设计目标如下:
快速更新:区块间的时间应该随着hash算力的增减而快速调整;
低波动性:如果Hash算力恒定,那么难度不应剧烈波动;
简单:算法的实现应相对简单;
低内存:算法不应依赖于过多的历史区块,要尽可能少的使用”内存变量“。假设有最新的十个区块,将存储在这十个区块头部的内存变量相加,这些区块都可用于算法的计算;
非开发性:算法不应让矿工有过多篡改时间戳或者矿池、反复添加或删除算力的能力,以使他们的收益最大化。
我们当前的算法在低波动性和非开发性上并不理想,至少我们计划切换时间戳比较父区块和祖父区块,所以矿工只有在连续挖2个区块时,才有动力去修改时间戳。另一个更强大的模拟公式: https://github.com/ethereum/economic-modeling/blob/master/diffadjust/blkdiff.py
Gas和费用
比特币中所有交易大体相同,因此它们的网络成本可以建成一个模型。以太坊中的交易要更复杂,所以交易费用需要考虑到账户的许多方面,包括宽带费用,存储费用和计算费用。尤其重要的是,以太坊编程语言是图灵完备的,所以交易会使用任意数量的宽带、存储和计算成本。这就可能会导致在计算成本过程中,突遭停电而计算被迫中止。
以太坊交易费用的基本机制如下:
• 每笔交易必须指明一定数量的gas(即指定startgas的值),以及支付每单元gas所需费用(即gasprice),在交易执行开始时,startgas * gasprice 价值的以太币会从发送者账户中扣除;
• 交易执行期间的所有操作,包括读写数据库、发送消息以及每一步的计算都会消耗一定数量的gas;
• 如果交易执行完毕,消耗的gas值小于指定的限制值,则交易执行正常,并将剩余的gas值赋予变量gas_rem ; 在交易完成后,发送者会收到返回的gas_rem * gasprice 价值的以太币,而给矿工的奖励是(startgas - gas_rem)* gasprice价值的以太币;
• 如果交易执行中,gas消耗殆尽,则所有的执行恢复原样,但交易仍然有效,只是交易的唯一结果是将 startgas * gasprice 价值的以太币支付给矿工,其他不变;
• 当一个合约发送消息给另一个合约,可以对这个消息引起的子执行设置一个gas限制。如果子执行耗尽了gas,则子执行恢复原样,但gas仍然消耗。
上述提到的几点都是必须满足的,例如:
• 如果交易没有指定gas限制,那么恶意用户就会发送一个有数十亿步循环的交易。没有人能够处理这样的交易,因为处理这样的交易花的时间可能很长很长,从而无法预先告知网络上的矿工,这会导致拒绝服务的漏洞产生。
• 替代严格的gas计数、时间限制等机制的方案不起作用,因为它们太主观了
• startgas * gasprice 的整个值,在开始时就应该设置好,这样不至于在交易执行中因gas不够而造成交易终止。注意,仅仅检查账户余额是不够的,因为账户可以在其他地方发送余额。
• 如果在gas不够的情况下,交易执行没有恢复操作(回滚),合约必须采用强有力的安全措施来防止合约发生变化。
• 如果子限制不存在,则恶意账户会通过与其他账户达成协议来对它们采取拒绝服务攻击。在计算开始时插入一个大循环,那么发送消息给受害合约或者受害合约的任何补救尝试,都会使整个交易死锁。
• 要求交易发送者而不是合约来支付gas,这样大大增加了开发人员的可操作性。以太坊早期的版本是由合约来支付gas的,这导致了一个相当严重的问题:每个合约必须实现“守护”代码,确保每个传入的消息有足够的以太币供其消耗。
gas消耗计算有以下特点:
• 对于任何交易,都将收取21000gas的基本费用。这些费用可用于支付运行椭圆曲线算法所需的费用。该算法旨在从签名中恢复发送者的地址以及存储交易所花费的硬盘和带宽空间。
• 交易可以包括无限量的“数据”。虚拟机中的某些操作码,可以让合约允许交易对这些数据的访问。数据的固定消耗计算是:每个零字节4gas,非零字节68gas。这个公式的产生是因为合约中大部分的交易数据由一些列的32字节的参数组成,其中多数参数具有许多前导零字节。该结构看起来似乎效率不高,但由于压缩算法的存在,实际上还是很有效率的。我们希望此结构能够代替其他更复杂的机制:这些机制根据预期字节数严格包装参数,从而导致编译阶段复杂性大增。这是三明治复杂模型的一个例外,但由于成本效益比,这也是合理的模型。
• 用于设置账户存储器的操作码SSTORE的消耗是:1.将零值改为非零值时,消耗20000gas;2.将零值变成零值,或非零值变非零值,消耗5000gas;3.将非零值变成零值,消耗5000gas,加上交易执行成功后退回的20000gas。退款金额上限是交易消耗gas总额的50%。这样设置会激励人们清除存储器。我们注意到,正因为缺乏这样的激励,许多合约造成了存储空间没有被有效使用,从而导致了存储快速膨胀;为存储收取费用提供了很多好处,同时不会失去合约一旦确立就可以永久存在的保证。延迟退款机制是必要的,因为可以阻止拒绝服务攻击。攻击者发送一笔含有少量gas的交易,循环清除大量的存储,直到用光gas,这样消耗了大量的验证算力,但实际并没有真正清除存储或消耗大量gas。50%的上限的是为了确保获得了一定交易gas的旷工依然能够确定执行交易的计算时间的上限。
• 合约提供的消息的数据是没有成本的。因为在消息调用期间不需要实质复制任何数据,调用数据可以简单地视为指向父合约内存的指针,该指针在子进程执行时不会改变。
• 内存是一个可以无限扩展的数组,然而,每扩展32字节的内存就会消耗1gas的成本,不足32字节以32字节计。
• 某些操作码的计算时间极度依赖参数,gas开销计算是动态变化的。例如,EXP的的开销是指数级别的;复制操作码(如:CALLDATACOPY, CODECOPY, EXTCODECOPY)的开销是1+1(每复制32字节)。内存扩展的开销不包含在这里,因为它触发了二次攻击。
• 如果值不是零,操作码CALL会额外消耗9000gas。这是因为任何值传输都会引起归档节点的历史存储显著增大。请注意,实际消耗是6700,在此基础上,我们强制增加了一个自动给予接受者的gas值,这个值最小2300。这样做是为了让接受交易的钱包至少有足够的gas来记录交易。
gas机制的另一个重要部分是gas价格本身体现出的经济学原理。比特币中,默认的方法是采取纯粹自愿的收费方式,矿工扮演守门人的角色并且动态设置收费的最小值。以太坊中允许交易发送者设置任意数目的gas。这种方式在比特币社区非常受欢迎,因为它是“市场经济”的体现:允许矿工和交易者之间依据供需关系来决定价格。然而,这种方式的问题是,交易处理并不遵循市场原则。尽管可以将交易处理看作是矿工向发送者提供的服务(这听起来很直观),但实际上矿工所处理的每个交易都必须由网络中的每个节点处理,所以交易处理的大部分成本都由第三方机构承担,而不是决定是否处理它的矿工。
当前,因为缺乏矿工在实际中的行为的明确信息,所以我们将采取一个非常简单公平的方法:投票系统,来设定gas限定值。矿工有权将当前区块的gas限定值设定在最后区块的gas限定值的0.0975% (1/1024)内。所以最终的gas限定值应该是矿工们设置的中间值。我们希望将来能够采用软分叉的方法来使用更加精确的算法。
虚拟机
以太坊虚拟机是执行交易代码的引擎,也是以太坊与其他系统的核心区别。请注意,虚拟机应该同“合约与消息模型”分开考虑。例如,SIGNEXTEND操作码是虚拟机的一个功能,但实际上“某个合约调用其他合约并指定子调用的gas限定值”是“合约与消息模型”的一部分。 EVM的设计目标如下:
简单:操作码尽可能的少并且低级;数据类型尽可能少;虚拟机的结构尽可能少;
结果明确:在VM规范语句中,没有任何可能产生歧义的空间,结果应该是完全确定的。此外,计算步骤应该是精确的,以便可以测量gas的消耗量;
节约空间:EVM组件应尽可能紧凑;
预期应用应具备专业化能力:在VM上构建的应用应能处理20字节的地址,以及32位的自定义加密值,拥有用于自定义加密的模数运算、读取区块和交易数据与状态交互等能力;
简单安全:为了让VM不被利用,应该能够容易地让建立一套gas消耗成本模型的操作;
优化友好:应该易于优化,以便即时编译(JIT)和VM的加速版本能够构建出来。
同时EVM也有如下特殊设计:
• 临时/永久存储的区别:
我们先来看看什么是临时存储和永久存储。
临时存储:存在于VM的每个实例中,并在VM执行结束后消失;
永久存储:存在于区块链状态层。
假设执行下面的树(S代表永久存储,M代表临时存储):
1.A调用B;
2.B设置B.S[0]=5,B.M[0]=9 ;
3.B调用C;
4.C调用B。
此时,如果B试图读取B.S[0],它将得到B前面存入的数据,也就是5;但如果B试图读取B.M[0],它将得到0,因为B.M是临时存储,读取它的时候是虚拟机的一个新的实例。
在一个内部调用中,如果设置B.M[0] = 13和 B.S[0] = 17 ,然后内部调用和C的调用都终止,再执行B的外部调用,此时读取M,将会看到B.M[0] = 9(此值在上一次同一VM执行实例中设置的),B.S[0] = 17。如果B的外部调用结束,然后A再次调用B,将看到B.M[0] = 0,B.S[0] = 17。这个区别的目的是:1.每个执行实例都分配有内存空间,不会因为循环调用而减损,这让安全编程更加容易。2.提供一个能够快速操作的内存形式:因为需要修改树,所以存储更新必然很慢。
• 栈/内存模式
早期,计算状态有三种:栈(stack,一个32字节标准的LIFO),内存(memory,可无限扩展的临时字节数组),存储(storage,永久存储)。在临时存储端,栈和内存的替代方案是memory-only范式,或者是寄存器和内存的混合体(两者区别不大,寄存器本质上也是一种内存)。在这种情况下,每个指令都有三个参数,例如:ADD R1 R2 R3: M[R1] = M[R2] + M[R3] 。选择栈范式的原因很明显,它使代码缩小了4倍。
• 单词大小32字节
在大多数结构中,如比特币,单词大小是4或8字节。4或8字节对存储地址或加密计算来说局限性太大了。而太大的值又很难建立相应安全的gas模型。32字节是一个理想大小,因为它足够存储下许多加密算法的实现以及地址,又不会因为太大而导致效率低下。
• 我们有自己的虚拟机
我们的虚拟机使用java、Lisp或Lua等语言开发。我们认为开发一款专业的虚拟机是值得的,因为:
1. 我们的VM规范比其他许多虚拟机简单的多,因为其他虚拟机为复杂性付出的代价更小,也就是说它们更容易变得复杂;然而,在我们的方案中每额外增加一点复杂性,都会给集约化发展带来障碍,以及潜在的安全缺陷,比如造成共识失败,这就让我们的复杂性成本很高,因而不容易造成复杂;
2. 我们的VM更加专业化,如支持32字节;
3. 我们不会有复杂的外部依赖,复杂的外部依赖会导致我们安装失败;
4. 完善的审查机制,可以具体到特殊的安全需求;对外部VM而言,这一点无论如何都是必要的。
• 使用了可变、可扩展的内存大小
固定内存的大小是不必要的限制,太小或太大都不合适。如果内存大小是固定的,每次访问内存都需要检查访问是否超出边界,显然这样的效率并不高。
• 栈大小没有限制
没什么特别理由!许多情况下,该设计不是绝对必要的;因为,gas的开销和区块层gas的限制总是会充当每种资源消耗的上限。
• 1024调用深度限制
许多编程语言在栈的深度过大时触发中断比在内存过载时触发中断的策略要快的多。所以区块中gas限制所隐含的限制是不够的。
• 无类型
为了简单起见,可以使用DIV, SDIV, MOD, SMOD的有符号或无符号的操作码代替(事实证明,对于操作码ADD和MUL,有符号和无符号是对等的);转换成定点运算在所有情况下都很简单,例如,在32位深度下,a * b -> (a * b) / 2^32, a / b -> a * 2^32 / b ,+, - 和 * 在整数下不变。
VM中某些操作码的函数和作用很容易理解,但也有一些不太好理解,以下是一些特殊的原因:
*• ADDMOD, MULMOD *
大多数情况下,addmod(a, b, c) = a * b % c,但在椭圆曲线算法中,使用的是32字节模数运算,直接执行a * b % c 实际上是在执行((a * b) % 2^256) % c会得到完全不同的结果。计算公式a * b % c 使用32字节空间的32字节值是非常不常见且繁琐。
• SIGNEXTEND
SIGNEXTEND操作码的作用是为了方便从大的有符号整数到小的有符号整数的类型转换。小的有符号整数是很有用的,因为未来的即时编译虚拟机可能会检测长时间运行的代码块,小的有符号整数能加快处理。
• SHA3
在以太坊代码中SHA3作为安全的高强度的hash集合应用非常广泛,通常在使用存储器时需要使用Hash函数来确保安全,以防止恶意冲突,在验证默克尔树和类似以太坊的数据结构时也需要使用到Hash函数。重要的是,与SHA3的相似的hash函数,如SHA256,ECRECVOR,RIPEM160不是以操作码的形式包含在里面,而是以伪合约的形式。这样做的目的是将它们放在一个单独的类别中,如果当我们以后提出适当的“本地扩展”系统时,可以添加更多这样的合约,而不需要扩展操作码。
• ORIGIN
ORIGIN操作码由交易的发送者提供,主要的作用是允许合约退回支付的gas。
• COINBASE
COINBASE的主要作用是:1.如果使用COINBASE操作码,则允许子货币对网络安全作出贡献;2.开放使用矿工作为一个去中心化的经济体,来设置基于子共识的应用,如Schellingcoin。
• PREVHASH
PREVHASH作为一个半安全的随机来源,允许合约评估上一个区块的默克尔树状态证明,而不需要高度复杂的递归结构“以太坊轻客户端”。
• EXTCODESIZE, EXTCODECOPY
主要的作用是让合约依据模板检查其他合约的代码,甚至是在与其他合约交互前,模拟它们。
• JUMPDEST
当跳转(jump)目的地限制在几个索引时(尤其是,动态目的跳转的计算复杂度是O(log(有效挑战目的数量)),而静态跳转总是恒定的),JIT虚拟机实现起来更简单。于是,我们需要:1.对有效变量跳转目的地做限制;2.使用静态而不是动态跳转的激励方式。为了达到这两个目标,我们定下了以下规则:1.紧接着push后的跳转可以跳到任何地方,而不仅是另一个jump;2.其他的jump只能跳转到JUMPDEST。对跳转的限制是必须的,你可以通过查看代码中的先前操作来决定是静态还是动态的跳转。缺乏对静态跳转的需求是激励使用它们的原因。禁止跳转进入push数据也会加快JIT虚拟机的编译和执行。
*• LOG *
LOG是事件的日志。
• CALLCODE
该操作码允许合约使用自己的存储器,在单独的栈空间和内存中调用其他合约的“函数”。这样可以在区块链上灵活实现标准库代码。
• SELFDESTRUCT
允许合约删除它自己,前提是它已经不需要存在了。SELFDESTRUCT并非立即执行,而是在交易执行完之后执行。这是因为这样做可以恢复那些执行后大大增加了缓存复杂度的SELFDESTRUCT操作码。
• PC
尽管理论上不需要PC操作码,因为所有的PC操作码都可以根据将push操作的索引加入实际程序计数器来代替实现,但使用PC可以创建独立代码的位置(可复制粘贴到其他合约的编译函数,如果它们以不同索引结束,不要打断)。

注释:
① UTXO: unspent transaction outputs。字面理解是:有效的交易输出,它是比特币协议中用于存储交易信息的数据结构。
② Nonce,Number used once或Number once的缩写,在密码学中Nonce是一个只被使用一次的任意或非重复的随机数值,在加密技术中的初始向量和加密散列函数都发挥着重要作用,在各类验证协议的通信应用中确保验证信息不被重复使用以对抗重放攻击(Replay Attack)。
③ 嵌套数组:创建一个数组,并使用其他数组填充该数组。如数组pets:
var cats : String[] = ["Cat","Beansprout", "Pumpkin", "Max"];
var dogs : String[] = ["Dog","Oly","Sib"];
var pets : String[][] = [cats, dogs];
④ 行程编码(run-length-encoding):一种统计编码。主要技术是检测重复的比特或字符序列,并用它们的出现次数取而代之。(百度百科)
⑤ 布隆过滤器:由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员。(百度百科)
⑥ uncle:A挖出区块后广播途中,B也挖出了区块(过时区块),此时区块链会出现分叉。过时分叉上的区块就叫uncle区块。它不是这个块的父区块,父区块的兄弟区块(平级关系)。

原文: https://github.com/ethereum/wiki/wiki/Design-Rationale
作者: Vitalik Buterin
翻译: kim
回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:17:30 | 显示全部楼层
干货 | 以太坊的工作原理
简介
不管你们知不知道以太坊(Ethereum blockchain)是什么,但是你们大概都听说过以太坊。最近在新闻里出现过很多次,包括一些专业杂志的封面,但是如果你们对以太坊到底是什么没有一个基本的了解的话,看这些文章就会感觉跟看天书一样。 所以,什么是以太坊?本质上,就是一个保存数字交易永久记录的公共数据库。重要的是,这个数据库不需要任何中央权威机构来维持和保护它。相反的它以一个“无信任”的交易系统来运行—一个个体在不需要信任任何第三方或对方的情况下进行点对点交易的架构。
依然感到很困惑?这就是这篇文章存在的理由。我的目标是在技术层面来解释以太坊的工作原理,但是不会出现很复杂的数学问题或看起来很可怕的公式。即使你不是一个程序员,我希望你看完之后最起码对技术有个更好的认识。如果有些部分技术性太强不好理解,这是非常正常的,真的没有必要完全理解每一个小细节。我建议只要宏观的理解一下事物就行了。
这篇文章中的很多议点都是以太坊黄皮书中讨论过的概念的细分。我添加了我自己的解释和图表使理解以太坊更加简单一点。那些足够勇敢的人可以挑战一下技术,去阅读一下以太坊的黄皮书。
好了, 让我们开始吧!
区块链定义
区块链就是一个具有共享状态的密码性安全交易的单机(cryptographically secure transactional singleton machine with shared-state)。[1]这有点长,是吧?让我们将它分开来看:
  • “密码性安全(Cryptographically secure)”是指用一个很难被解开的复杂数学机制算法来保证数字货币生产的安全性。将它想象成类似于防火墙的这种。它们使得欺骗系统近乎是一个不可能的事情(比如:构造一笔假的交易,消除一笔交易等等)。
  • “交易的单机(Transactional singleton machine)”是指只有一个权威的机器实例为系统中产生的交易负责任。换句话说,只有一个全球真相是大家所相信的。
  • “具有共享状态(With shared-state)”是指在这台机器上存储的状态是共享的,对每个人都是开放的。

以太坊实现了区块链的这个范例。
以太坊模型说明
以太坊的本质就是一个基于交易的状态机(transaction-based state machine)。在计算机科学中,一个 状态机 是指可以读取一系列的输入,然后根据这些输入,会转换成一个新的状态出来的东西。
根据以太坊的状态机,我们从创世纪状态(genesis state)开始。这差不多类似于一片空白的石板,在网络中还没有任何交易的产生状态。当交易被执行后,这个创世纪状态就会转变成最终状态。在任何时刻,这个最终状态都代表着以太坊当前的状态。
以太坊的状态有百万个交易。这些交易都被“组团”到一个区块中。一个区块包含了一系列的交易,每个区块都与它的前一个区块链接起来。
为了让一个状态转换成下一个状态,交易必须是有效的。为了让一个交易被认为是有效的,它必须要经过一个验证过程,此过程也就是挖矿。挖矿就是一组节点(即电脑)用它们的计算资源来创建一个包含有效交易的区块出来。
任何在网络上宣称自己是矿工的节点都可以尝试创建和验证区块。世界各地的很多矿工都在同一时间创建和验证区块。每个矿工在提交一个区块到区块链上的时候都会提供一个数学机制的“证明”,这个证明就像一个保证:如果这个证明存在,那么这个区块一定是有效的。
为了让一个区块添加到主链上,一个矿工必须要比其他矿工更快的提供出这个“证明”。通过矿工提供的一个数学机制的“证明”来证实每个区块的过程称之为工作量证明(proof of work)。
证实了一个新区块的矿工都会被奖励一定价值的奖赏。奖赏是什么?以太坊使用一种内在数字代币—以太币(Ether)作为奖赏。每次矿工证明了一个新区块,那么就会产生一个新的以太币并被奖励给矿工。
你也许会在想:什么能确保每个人都只在区块的同一条链上呢?我们怎么能确定不会存在一部分矿工创建一个他们自己的链呢?
前面,我们定义了区块链就是一个具有共享状态的交易单机。使用这个定义,我们可以知道正确的当前状态是一个全球真相,所有人都必须要接受它。拥有多个状态(或多个链)会摧毁这个系统,因为它在哪个是正确状态的问题上不可能得到统一结果。如果链分叉了,你有可能在一条链上拥有10个币,一条链上拥有20个币,另一条链上拥有40个币。在这种场景下,是没有办法确定哪个链才是最”有效的“。
不论什么时候只要多个路径产生了,一个”分叉“就会出现。我们通常都想避免分叉,因为它们会破坏系统,强制人们去选择哪条链是他们相信的链。
为了确定哪个路径才是最有效的以及防止多条链的产生,以太坊使用了一个叫做“GHOST协议(GHOST protocol.)”的数学机制。
GHOST = Greedy Heaviest Observed Subtree
简单来说,GHOST协议就是让我们必须选择一个在其上完成计算最多的路径。一个方法确定路径就是使用最近一个区块(叶子区块)的区块号,区块号代表着当前路径上总的区块数(不包含创世纪区块)。区块号越大,路径就会越长,就说明越多的挖矿算力被消耗在此路径上以达到叶子区块。使用这种推理就可以允许我们赞同当前状态的权威版本。
现在你大概对区块链是什么有个理性的认识,让我们在再深入了地解一下以太坊系统主要组成部分:
  • 账户(accounts)
  • 状态(state)
  • 损耗和费用(gas and fees)
  • 交易(transactions)
  • 区块(blocks)
  • 交易执行(transaction execution)
  • 挖矿(mining)
  • 工作量证明(proof of work)
在开始之前需要注意的是:每当我说某某的hash, 我指的都是KECCAK-256hash, 以太坊就是使用这个hash算法。
账户
以太坊的全局“共享状态”是有很多小对象(账户)来组成的,这些账户可以通过消息传递架构来与对方进行交互。每个账户都有一个与之关联的状态(state)和一个20字节的地址(address)。在以太坊中一个地址是160位的标识符,用来识别账户的。
这是两种类型的账户:
  • 外部拥有的账户,被私钥控制且没有任何代码与之关联
  • 合约账户,被它们的合约代码控制且有代码与之关联
外部拥有账户与合约账户的比较
理解外部拥有账户和合约账户的基本区别是很重要的。一个外部拥有账户可以通过创建和用自己的私钥来对交易进行签名,来发送消息给另一个外部拥有账户或合约账户。在两个外部拥有账户之间传送的消息只是一个简单的价值转移。但是从外部拥有账户到合约账户的消息会激活合约账户的代码,允许它执行各种动作。(比如转移代币,写入内部存储,挖出一个新代币,执行一些运算,创建一个新的合约等等)。
不像外部拥有账户,合约账户不可以自己发起一个交易。相反,合约账户只有在接收到一个交易之后(从一个外部拥有账户或另一个合约账户接),为了响应此交易而触发一个交易。我们将会在“交易和消息”部分来了解关于合约与合约之间的通信。
因此,在以太坊上任何的动作,总是被外部控制账户触发的交易所发动的。
账户状态
账户状态有四个组成部分,不论账户类型是什么,都存在这四个组成部分:
  • nonce:如果账户是一个外部拥有账户,nonce代表从此账户地址发送的交易序号。如果账户是一个合约账户,nonce代表此账户创建的合约序号
  • balance: 此地址拥有Wei的数量。1Ether=10^18Wei
  • storageRoot: Merkle Patricia树的根节点Hash值(我们后面在解释Merkle树)。Merkle树会将此账户存储内容的Hash值进行编码,默认是空值
  • codeHash:此账户EVM(以太坊虚拟机,后面细说)代码的hash值。对于合约账户,就是被Hash的代码并作为codeHash保存。对于外部拥有账户,codeHash域是一个空字符串的Hash值
世界状态
好了,我们知道了以太坊的全局状态就是由账户地址和账户状态的一个映射组成。这个映射被保存在一个叫做Merkle Patricia树的数据结构中。
Merkle Tree(也被叫做Merkle trie)是一种由一系列节点组成的二叉树,这些节点包括:
  • 在树底的包含了源数据的大量叶子节点
  • 一系列的中间的节点,这些节点是两个子节点的Hash值
  • 一个根节点,同样是两个子节点的Hash值,代表着整棵树
树底的数据是通过分开我们想要保存到chunks的数据产生的,然后将chunks分成buckets,再然后再获取每个bucket的hash值并一直重复直到最后只剩下一个Hash:根Hash。
这棵树要求存在里面的值(value)都有一个对应的key。从树的根节点开始,key会告诉你顺着哪个子节点可以获得对应的值,这个值存在叶子节点。在以太坊中,key/value是地址和与地址相关联的账户之间状态的映射,包括每个账户的balance, nonce, codeHash和storageRoot(storageRoot自己就是一颗树)。
同样的树结构也用来存储交易和收据。更具体的说,每个块都有一个头(header),保存了三个不同Merkle trie结构的根节点的Hash,包括:
  • 状态树
  • 交易树
  • 收据树
在Merkle tries中存储所有信息的高效性在以太坊中的“轻客户端”和“轻节点”相当的有用。记住区块链就是一群节点来维持的。广泛的说,有两种节点类型:全节点和轻节点。
全节点通过下载整条链来进行同步,从创世纪块到当前块,执行其中包含的所有交易。通常,矿工会存储全节点,因为他们在挖矿过程中需要全节点。也有可能下载一个全节点而不用执行所有的交易。无论如何,一个全节点包含了整个链。
不过除非一个节点需要执行所有的交易或轻松访问历史数据,不然没必要保存整条链。这就是轻节点概念的来源。比起下载和存储整个链以及执行其中所有的交易,轻节点仅仅下载链的头,从创世纪块到当前块的头,不执行任何的交易或检索任何相关联的状态。由于轻节点可以访问块的头,而头中包含了3个tries的Hash,所有轻节点依然可以很容易生成和接收关于交易、事件、余额等可验证的答案。
这个可以行的通是因为在Merkle树中hash值是向上传播的—如果一个恶意用户试图用一个假交易来交换Merkle树底的交易,这个会改变它上面节点的hash值,而它上面节点的值的改变也会导致上上一个节点Hash值的改变,以此类推,一直到树的根节点。
任何节点想要验证一些数据都可以通过Merkle证明来进行验证,Merkle 证明的组成:
  • 一块需要验证的数据
  • 树的根节点Hash
  • 一个“分支”(从 chunk到根这个路径上所有的hash值)
任何可以读取证明的人都可以验证分支的hash是连贯的,因此给出的块在树中实际的位置就是在此处。
总之,使用Merkle Patricia树的好处就是该结构的根节点加密取决于存储在树中的数据,而且根据点的hash还可以作为该数据的安全标识。由于块的头包含了状态、交易、收据树的根hash,所有任何节点都可以验证以太坊的一小部分状态而不用保存整个状态,这整个状态的的大小可能是非常大的。
Gas和费用
在以太坊中一个比较重要的概念就是费用(fees),由以太坊网络上的交易而产生的每一次计算,都会产生费用—没有免费的午餐。这个费用是以称之为”gas”的来支付。
gas就是用来衡量在一个具体计算中要求的费用单位。gas price就是你愿意在每个gas上花费Ether的数量,以“gwei”进行衡量。“Wei”是Ether的最小单位,1Ether表示10^18Wei. 1gwei是1,000,000,000 Wei。
对每个交易,发送者设置gas limit和gas price。gas limit和gas price就代表着发送者愿意为执行交易支付的Wei的最大值。
例如,假设发送者设置gas limit为50,000,gas price为20gwei。这就表示发送者愿意最多支付50,00020gwei = 1,000,000,000,000,000 Wei = 0.001 Ether来执行此交易。
记住gas limit代表用户愿意花费在gas上的钱的最大值。如果在他们的账户余额中有足够的Ether来支付这个最大值费用,那么就没问题。在交易结束时任何未使用的gas都会被返回给发送者,以原始费率兑换。
在发送者没有提供足够的gas来执行交易,那么交易执行就会出现“gas不足”然后被认为是无效的。在这种情况下,交易处理就会被终止以及所有已改变的状态将会被恢复,最后我们就又回到了交易之前的状态—完完全全的之前状态就像这笔交易从来没有发生。因为机器在耗尽gas之前还是为计算做出了努力,所以理论上,将不会有任何的gas被返回给发送者。
这些gas的钱到底去了哪里?发送者在gas上花费的所有钱都发送给了“受益人”地址,通常情况下就是矿工的地址。因为矿工为了计算和验证交易做出了努力,所以矿工接收gas的费用作为奖励。
通常,发送者愿意支付更高的gas price,矿工从这笔交易总就能获得更多的价值。因此,矿工也就更加愿意选择这笔交易。这样的话,矿工可以自由的选择一笔交易自己愿意验证或忽略。为了引导发送者应该设置gas price为多少,矿工可以选择建议一个最小的gas值他们愿意执行一个交易。
存储也有费用
gas不仅仅是用来支付计算这一步的费用,而且也用来支付存储的费用。存储的总费用与所使用的32位字节的最小倍数成比例。
存储费用有一些比较细微的方面。比如,由于增加了的存储增加了所有节点上的以太坊状态数据库的大小,所以激励保持数据存储量小。为了这个原因,如果一个交易的执行有一步是清除一个存储实体,那么为执行这个操作的费用就会被放弃,并且由于释放存储空间的退款就会被返回给发送者。
费用的作用是什么?
以太坊可以运作的一个重要方面就是每个网络执行的操作同时也被全节点所影响。然而,计算的操作在以太坊虚拟机上是非常昂贵的。因此,以太坊智能合约最好是用来执行最简单的任务,比如运行一个简单的业务逻辑或者验证签名和其他密码对象,而不是用于复杂的操作,比如文件存储,电子邮件,或机器学习,这些会给网络造成压力。施加费用防止用户使网络超负荷。
以太坊是一个图灵完备语言(短而言之,图灵机器就是一个可以模拟任何电脑算法的机器。对于图灵机器不太熟悉的人可以看看这个这个 )。这就允许有循环,并使以太坊受到停机问题 的影响,这个问题让你无法确定程序是否无限制的运行。如果没有费用的话,恶意的执行者通过执行一个包含无限循环的交易就可以很容易的让网络瘫痪而不会产生任何反响。因此,费用保护网络不受蓄意攻击。
你也许会想,“为什么我们还需要为存储付费?”其实就像计算一样,以太坊网络上的存储是整个网络都必须要负担的成本。
交易和消息
之前说过以太坊是一个基于交易的状态机。换句话说,在两个不同账户之间发生的交易才让以太坊全球状态从一个状态转换成另一个状态。
最基本的概念,一个交易就是被外部拥有账户生成的加密签名的一段指令,序列化,然后提交给区块链。
有两种类型的交易:消息通信和合约创建(也就是交易产生一个新的以太坊合约)。
不管什么类型的交易,都包含:
  • nonce:发送者发送交易数的计数
  • gasPrice:发送者愿意支付执行交易所需的每个gas的Wei数量
  • gasLimit:发送者愿意为执行交易支付gas数量的最大值。这个数量被设置之后在任何计算完成之前就会被提前扣掉
  • to:接收者的地址。在合约创建交易中,合约账户的地址还没有存在,所以值先空着
  • value:从发送者转移到接收者的Wei数量。在合约创建交易中,value作为新建合约账户的开始余额
  • v,r,s:用于产生标识交易发生着的签名
  • init(只有在合约创建交易中存在):用来初始化新合约账户的EVM代码片段。init值会执行一次,然后就会被丢弃。当init第一次执行的时候,它返回一个账户代码体,也就是永久与合约账户关联的一段代码。
  • data(可选域,只有在消息通信中存在):消息通话中的输入数据(也就是参数)。例如,如果智能合约就是一个域名注册服务,那么调用合约可能就会期待输入域例如域名和IP地址
在“账户”这个章节中我们学到交易—消息通信和合约创建交易两者都总是被外部拥有账户触发并提交到区块链的。换种思维思考就是,交易是外部世界和以太坊内部状态的桥梁。
但是这也并不代表一个合约与另一个合约无法通信。在以太坊状态全局范围内的合约可以与在相同范围内的合约进行通信。他们是通过“消息”或者“内部交易”进行通信的。我们可以认为消息或内部交易类似于交易,不过与交易有着最大的不同点—它们不是由外部拥有账户产生的。相反,他们是被合约产生的。它们是虚拟对象,与交易不同,没有被序列化而且只存在与以太坊执行环境。
当一个合约发送一个内部交易给另一个合约,存在于接收者合约账户相关联的代码就会被执行。
一个重要需要注意的事情是内部交易或者消息不包含gasLimit。因为gas limit是由原始交易的外部创建者决定的(也就是外部拥有账户)。外部拥有账户设置的gas limit必须要高到足够将交易完成,包括由于此交易而长生的任何”子执行”,例如合约到合约的消息。如果,在一个交易或者信息链中,其中一个消息执行使gas已不足,那么这个消息的执行会被还原,包括任何被此执行触发的子消息。不过,父执行没必要被还原。
区块
所有的交易都被组成一个”块”。一个区块链包含了一系列这样的链在一起区块。
在以太坊中,一个区块包含:
  • 区块头
  • 关于包含在此区块中交易集的信息
  • 与当前块的ommers相关的一系列其他区块头
Ommers解释
“ommer”到底是什么? ommer就是一个区块的父区块与当前区块父区块的父区块是相同的。让我们快速了解一下ommers是用来干嘛的,并且为什么一个区块需要为ommers包含区块头。
由于以太坊的构造,它的区块生产时间(大概15秒左右)比其他的区块链例如Bitcoin(大概10分钟左右)要快很多。这使得交易的处理更快。但是,更短的区块生产时间的一个缺点就是:更多的竞争区块会被矿工发现。这些竞争区块同样也被称为“孤区块”(也就是被挖出来但是不会被添加到主链上的区块)。
Ommers的目的就是为了帮助奖励矿工纳入这些孤区块。矿工包含的ommers必须是有效的,也就是ommers必须在父区块的第6个子区块之内或更小范围内。在第6个子区块之后,陈旧的孤区块将不会再被引用(因为包含老旧的交易会使事情变得复杂一点)。
Ommer区块会收到比全区块少一点的奖励。不管怎样,依然存在激励来让矿工们纳入孤区块并能从中获得一些报酬。
区块头
让我们再回到区块的问题上。我们前面提到每个区块都有一个“区块头”,但这究竟是什么?
区块头是一个区块的一部分,包含了:
  • parentHash:父区块头的Hash值(这也是使得区块变成区块链的原因)
  • ommerHash:当前区块ommers列表的Hash值
  • beneficiary:接收挖此区块费用的账户地址
  • stateRoot:状态树根节点的Hash值(回忆一下我们之前所说的保存在头中的状态树以及它使得轻客户端认证任何关于状态的事情都变得非常简单)
  • transactionsRoot:包含此区块所列的所有交易的树的根节点Hash值
  • receiptsRoot:包含此区块所列的所有交易收据的树的根节点Hash值
  • logsBloom:由日志信息组成的一个Bloom过滤器 (数据结构)
  • difficulty: 此区块的难度级别
  • number:当前区块的计数(创世纪块的区块序号为0,对于每个后续区块,区块序号都增加1)
  • gasLimit:每个区块的当前gas limit
  • gasUsed: 此区块中交易所用的总gas量
  • timestamp:此区块成立时的unix的时间戳
  • extraData:与此区块相关的附加数据
  • mixHash:一个Hash值,当与nonce组合时,证明此区块已经执行了足够的计算
  • nonce:一个Hash值,当与mixHash组合时,证明此区块已经执行了足够的计算
注意每个区块是如何包含三个树结构的,三个树结构分别对应:
  • 状态(stateRoot)
  • 交易(transactionsRoot)
  • 收据(receiptsRoot)
这三个树结构就是我们前面讨论的Merkle Patricia树。
另外,上面描述的有几个术语值得说明一下,下面来看一下。
日志
以太坊允许日志可以跟踪各种交易和信息。一个合约可以通过定义“事件”来显示的生成日志。
一个日志的实体包含:
  • 记录器的账户地址
  • 代表本次交易执行的各种事件的一系列主题以及与这些事件相关的任何数据
日志被保存在bloom过滤器 中,过滤器高效的保存了无尽的日志数据。
交易收据
自于被包含在交易收据中的日志信息存储在头中。就像你在商店买东西时收到的收据一样,以太坊为每笔交易都产生一个收据。像你期望的那样,每个收据包含关于交易的特定信息。这些收据包含着:
  • 区块序号
  • 区块Hash
  • 交易Hash
  • 当前交易使用了的gas
  • 在当前交易执行完之后当前块使用的累计gas
  • 执行当前交易时创建的日志
  • 等等
区块难度
区块的难度是被用来在验证区块时加强一致性。创世纪区块的难度是131,072,有一个特殊的公式用来计算之后的每个块的难度。如果某个区块比前一个区块验证的更快,以太坊协议就会增加区块的难度。
区块的难度影响nonce,它是在挖矿时必须要使用proof-of-work算法来计算的一个hash值。
区块难度和nonce之间的关系用数学形式表达就是:
Hd代表的是难度。
找到符合难度阈值的nonce唯一方法就是使用proof-of-work算法来列举所有的可能性。找到解决方案预期时间与难度成正比—难度越高,找到nonce就越困难,因此验证一个区块也就越难,这又相应地增加了验证新块所需的时间。所以,通过调整区块难度,协议可以调整验证区块所需的时间。
另一方面,如果验证时间变的越来越慢,协议就会降低难度。这样的话,验证时间自我调节以保持恒定的速率—平均每15s一个块。
交易执行
我们已经到了以太坊协议最复杂的部分:交易的执行。假设你发送了一笔交易给以太坊网络处理,将以太坊状态转换成包含你的交易这个过程到底发生了什么?
首先,为了可以被执行所有的交易必须都要符合最基础的一系列要求,包括:
  • 交易必须是正确格式化的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费用被加到从发送方传送给接收方的总值。
如何交易符合上面所说的所有要求,那么我们进行下面步骤。
第一步,我们从发送者的余额中扣除执行的前期费用,并为当前交易将发送者账户中的nonce增加1。此时,我们可以计算剩余的gas,将交易的总gas减去使用的intrinsic gas。
第二步,开始执行交易。在交易执行的整个过程中,以太坊保持跟踪“子状态”。子状态是记录在交易中生成的信息的一种方式,当交易完成时会立即需要这些信息。具体来说,它包含:
  • 自毁集:在交易完成之后会被丢弃的账户集(如果存在的话)
  • 日志系列:虚拟机的代码执行的归档和可检索的检查点
  • 退款余额:交易完成之后需要退还给发送账户的总额。回忆一下我们之前提到的以太坊中的存储需要付费,发送者要是清理了内存就会有退款。以太坊使用退款计数进行跟踪退款余额。退款计数从0开始并且每当合约删除了一些存储中的东西都会进行增加。
第三步,交易所需的各种计算开始被处理。
当交易所需的步骤全部处理完成,并假设没有无效状态,通过确定退还给发送者的未使用的gas量,最终的状态也被确定。除了未使用的gas,发送者还会得到上面所说的“退款余额”中退还的一些津贴。
一旦发送者得到退款之后:
  • gas的Ether就会矿工
  • 交易使用的gas会被添加到区块的gas计数中(计数一直记录当前区块中所有交易使用的gas总量,这对于验证区块时是非常有用的)
  • 所有在自毁集中的账户(如果存在的话)都会被删除
最后,我们就有了一个新的状态以及交易创建的一系列日志。
现在我们已经介绍了交易执行的基本知识,让我们再看看合约创建交易和消息通信的一些区别。
合约创建(Contract creation)
回忆一下在以太坊中,有两种账户类型:合约账户和外部拥有账户。当我们说一个交易是“合约创建”,是交易的目的是创建一个新的合约账户。
为了创建一个新的合约账户,我们使用一个特殊的公式来声明新账户的地址。然后我们使用下面的方法来初始化一个账户:
  • 设置nonce为0
  • 如果发送者通过交易发送了一定量的Ether作为value,那么设置账户的余额为value
  • 将存储设置为0
  • 设置合约的codeHash为一个空字符串的Hash值
一旦我们完成了账户的初始化,使用交易发送过来的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位。
EVM有内存,项目按照可寻址字节数组来存储。内存是易失性的,也就是数据是不持久的。
EVM也有一个存储器。不像内存,存储器是非易失性的,并作为系统状态的一部分进行维护。
EVM分开保存程序代码,在虚拟ROM中只能通过特殊指令来访问。这样的话,EVM就与典型的冯·诺依曼架构 不同,此架构将程序的代码存储在内存或存储器中。
EVM同样有属于它自己的语言:“EVM字节码”,当一个程序员比如你或我写一个在以太坊上运行的智能合约时,我们通常都是用高级语言例如Solidity来编写代码。然后我们可以将它编译成EVM可以理解的EVM字节码。
好了,现在来说执行。
在执行特定的计算之前,处理器会确定下面所说的信息是有效和是否可获取:
  • 系统状态
  • 用于计算的剩余gas
  • 拥有执行代码的账户地址
  • 原始触发此次执行的交易发送者的地址
  • 触发代码执行的账户地址(可能与原始发送者不同)
  • 触发此次执行的交易gas价格
  • 此次执行的输入数据
  • Value(单位为Wei)作为当前执行的一部分传递给该账户
  • 待执行的机器码
  • 当前区块的区块头
  • 当前消息通信或合约创建堆栈的深度
执行刚开始时,内存和堆栈都是空的,程序计数器为0。
然后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)。
算法正式定义为:
m代表的是mixHash,n代表的是nonce,Hn代表的是新区块的头(不包含需要计算的nonce和mixHash),Hn是区块头的nonce,d是DAG ,就是一个大数据集。
在”区块”章节,我们讨论了存在于区块头中的多项。其中两项叫做mixHash和nonce。也许你会回忆起:
  • mixHash:一个Hash值,当与nonce组合时,证明此区块已经执行了足够的计算
  • nonce:一个Hash值,当与mixHash组合时,证明此区块已经执行了足够的计算
PoW函数就是用来估算这两项的。
mixHash和nonce到底是如何使用PoW函数来计算出来的有点复杂,如果深入了解的话,我们可以另写一篇文章来讲解了。但是在一个高层面上,它大致就是这样计算的:
会为每个区块计算一个”种子”。每个“时期”的种子都不一样,每个时期是30,000个区块长度。对于第一时期,种子就是32位0的hash值。对于后续的每个时期,种子就是前一个种子hash值的hash值。使用这个种子,节点可以计算一个伪随机“缓存”。
这个缓存是非常有用的,因为它可以使“轻节点”的概念变成现实,轻节点概念在这篇文章的前面讨论过。轻节点的目的就是让某个节点有能力高效的校验交易而用不着存储整个区块链的数据集。一个轻节点可以仅基于缓存来校验一个交易的有效性,因为缓存可以重新生成需要校验的特定块。
使用这个缓存,节点可以生成DAG“数据集”,数据集中的每项取决于缓存中少量伪随机选择项。为了成为矿工,你需要要生成全数据集,所有全客户端和矿工都保存这个数据集,并且这个数据集随着时间线性增长。
然后矿工可以随机抽取数据集中的部分并将它们放入一个数学函数中Hash出一个”mixHash”。矿工会重复生成mixHash直到输出的值小于想要的目标值nonce。当输出的值符合这个条件的时候,nonce就被认为是有效的,然后区块就被添加到链中。
挖矿作为安全机制
总的来说,PoW的目的就是以加密安全的方式证明生成的一些输出(也就是nonce)是经过了一定量的计算的。因为除了列举所有的可能性,没有更好的其他方法来找到一个低于要求阈值的nonce。重复应用Hash函数的输出均匀分布,所以我们可以确保,在平均值上,找到满足要求的nonce所需时间取决于难度阈值。难度系数越大,所需时间越长。这样的话,PoW算法就给予难度这个概念的意义了:用来加强区块链的安全。
我们所说的区块链的安全又是什么意思?这非常简单:我们想要创造一个每个人都信任的区块链。像我们之前在这篇文章中讨论的那样,如果存在超过1条以上的链,用户的信任就会消失,因为他们没有能力合理的确认哪条链才是“有效的”。为了让一群用户接受存储在区块链中的潜在状态,我们需要有一群人信任的一个权威区块链。
这完完全全就是Pow算法所做的事情:它确保特定的区块链直到未来都一直保持着权威性,让攻击者创造一个新区块来重写某个历史部分(例如清除一个交易或者创建一个假的交易)或者保持一个分叉变得非常困难。为了首先让他们的区块被验证,攻击者需要总是比网络上的其他人要更快的解决掉nonce问题,这样网络就会相信他们的链是最重的链(基于我们之前提到的GHOST协议原则)。除非攻击者拥有超过一半的网络挖矿能力(这种场景也被称为大多数51%攻击 ),要不然这基本上是不可能的。
挖矿作为财富分配机制
除了提供一个安全的区块链,PoW同样也是分配财富给那些为提供这个安全而花费自己计算力的人的一种方法。回忆一下,一个矿工挖出一个区块的时候会获得奖励,包括:
  • 为“获胜”区块提供的5 ether静态区块奖励(马上就会变成3 ether )
  • 区块中的交易在区块内所消耗的gas
  • 纳入ommers作为区块的一部分的额外奖励
为了保证PoW共识算法机制对安全和财富分配的使用是长期可持续的,以太坊努力灌输这两个特性:
  • 尽可能的让更多的人可访问。换句话说,人们不需要特殊的或者与众不同的硬件来运行这个算法。这样做的目的是为了让财富分配模式变的尽可能的开放,以便任何人都可以提供一些算力而获得Ether作为回报。
  • 降低任何单个节点(或小组)能够创造与其不成比例的利润可能性。任何可以创造不成比例的利润的节点拥有比较大的影响力来决定权威区块链。这是件麻烦的事情,因为这降低了网络的安全性。
在区块链网络中,一个与上面两个特性有关的一个问题是PoW算法是一个SHA256哈希函数。这种函数的缺点就是它使用特殊的硬件(也被称之为ASCIs)可以更加快速高效的解决nonce问题。
为了减轻这个问题,以太坊选择让PoW算法提高内存级别难度。意思是此算法被设计为计算出要求的nonce需要大量的内存和带宽。大量内存的需求让电脑平行的使用内存同时计算多个nonce变得极其困难,高带宽的需求让即使是超级电脑同时计算多个nonce也变得十分艰难。这种方式降低了中心化的风险,并为正在进行验证的几点提供了更加公平的竞争环境。
有一件值得注意的事情是以太坊正在从PoW共识机制渐渐转换为一个叫做“权益证明(PoS)”的共识算法。这就是一个比较野心的话题了,我们希望可以在未来的文章中探索这个话题。
总结
呼! 你终于坚持到最后了。我希望如此?
这篇文章中有很多的地方需要消化。如果需要你阅读好几遍才能理解怎么回事,这完全正常。我个人重复阅读了好几次以太坊黄皮书,白皮书,以及代码的不同部分才渐渐明白是怎么回事。
无论如何,我希望你觉得这篇文章对你有帮助。如果你发现了任何的错误或失误,我很乐意你给我写个私人消息或者直接在评论区评论(我保证我会查看所有评论)。
记住,我是个人类(对,这是真的),我会犯错误。为了社区的利益,我花时间免费写了这篇文章。所以请你在反馈时不要带着没必要的攻击性,尽量是建设性的反馈。


回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:35:06 | 显示全部楼层
干货 | Vitalik: 25分钟认识以太坊(上)
hongji   |   20. Nov, 2017   |   3594 次阅读

编者按:以下为Vitalik Buterin在Ethereum Devcon3上的演讲《Ethereum in 25 minutes, vision 2017》的上半部分。以下中文皆直接从视频中听写并译出,如有错失,请不吝赐教。
好的,那么,这个演讲希望成为一种尽可能简洁的介绍,与此同时,能够涵盖重要的部分,比如,最基本的,从技术角度来说以太坊(Ethereum)协议在实际上看起来是什么样的。
那么,我将直接切入,下沉到以太坊之所是,以背景,即以太坊存在的理由,来开始基础介绍。回到我在2013年末写出初始白皮书的时候,公众、区块链技术、尤其是那些致力于使区块链技术超越仅仅是比特币(Bitcoin)货币的人们,已经表现出大量的兴趣。现在,人们正致力于开发以太坊应用、发行资产到区块链上、众筹、域名注册、域名币(Namecoin)这样的项目、产权登记、投机、预测市场、物联网(loT)应用、医疗应用。区块链上有许多的应用,超越了像“我有50个比特币,我发20个比特币给你,然后你就有了20个比特币”这样。
问题在于,那时候大多数存在的区块链都是像这样设计的。我的意思是,这种豆豆计算器有何意义呢?它可以做到这件事,它也可以把这件事做得很棒,但这也是它唯一能做到的事。诚然,如果你有一台超级棒的TI-80(译者注:德州仪器发行的一款学生用科学计算器)或是别的,你或许能够通过某种方式在上面编写一个视频游戏,但没有人会真的想这么做。所以,普遍地来说,它最后变成了能用来做一件事情的一个工具。
但是,如果我们想让它做不止一件事情呢?当然,你可以为5个不同的目的买5种不同的设备,但这很快就会(回到原点)。下一步是,人们开始创造像瑞士军刀一样的协议。你可能会想象,一群人走进一个房间,他们头脑风暴了一个钟,然后他们写出了25个不同的区块链应用,然后,他们达成了25种不同的交易类型。交易类型一,创建一个共筹;交易类型二,参与一个众筹;交易类型三,创建一个保险合约;交易类型四,开一个双人房;交易类型五,注册一个域名;等等,乃至他们可以想到的每一种应用。这就是我使用“瑞士军刀”的含义。
但问题又在于,如果你有了一个瑞士军刀协议,你拥有这个在一个房间里孵化出25种不同项目的协议,他们创建这一协议,放出这个协议,一个星期以后,一个芬兰的小伙子写出了第26个区块链应用,然后,你必须更改整个协议。
所以,为什么不创建一个像这个一样的协议?(屏幕上是一台Windows Phone,屏幕下方有一行字:特别感谢微软(Microsoft)赞助本次大会。听众大笑)
为什么不做一个基本上像一台智能手机一样的区块链协议,来取代那些仅支持很少一些应用、你能做的也仅仅是这些应用的协议?因此,我们做了一个区块链协议,它支持编程语言,因此也给了你技能来创建应用。一个应用是什么呢?其实,任何人都可以写一些代码,打包这些代码并上传它,然后你就有一个app!如果任何其他人想使用你的app,他们下载这个app,然后它就会出现在他们的手机上,他们可以使用它,可以运行它。对,就是这样,基本上这就是为什么一个手机可以打电话、浏览网页、听音乐、用文字与其他人会话、玩游戏;只是因为我们将数以千计的东西集成到一个设备上。这就是通用计算的力量。这也是我想带给区块链世界的一种精神。
概念
所以,首先,以太坊是一个区块链!耶~!
加法
但是,你知道,我们增加了一些东西。首先,以太坊拥有一个内置的通用编程语言,允许你在其中编写非常多的应用。
现在,在一个目的只在于支持货币转移的区块链上,那里将只有一种类型的账户。这种类型的账户将成为这样的一个账户:它被某些用户所控制、它将保存货币。你将能够从一个账户发送这些货币到另一个。但在以太坊上我们有两种类型的账户。
1. 第一种类型的账户是被用户控制的,所以你拥有一个加密私钥,你可以用它来代表你的地址、为执行操作的信息打上电子签名。这些操作被称为交易,它们可以被广播到整个网络;如果它们被包含到了一个区块中,这些操作就会生效。
2. 另一种类型的账户在根本上由一段运行在区块链自身的代码来控制。所以,你可以拥有一个被一个计算机程序控制的账户,这个计算机程序有一些规则,这些规则可能说的是:如果A发生了,那就发一些币给X;如果B发生了,那就发一些币给Y;如果C发生了,就仅仅保持现状。如果你发送一些币给这个账户,这个账户的代码就仅仅是这样一个东西:它在那时候起有能力将这些币转移到别的地方去。
从字面上来讲,这些就是被一个计算机程序直接控制的电子资产。当然,这些合约可以被用来做更多事情,不止于仅仅控制电子资产。它们可以被用来表示区块链应用里面任意复杂的商业逻辑。这也包括了像ENS,以太坊域名系统(Ethereum Name System)这样的东西,它可以被用来跟踪一些区块链上的正在投票的方案;它也可以被用来跟踪链上多种多样的发行人背书资产,还有很多不同的用例。基本上,任何人都可以通过定义一个合约来创建一个应用或者任何规则。
DNS, the Hello World of Ethereum
DNS,这个以太坊的Hello World,就是其中一个你可以写出来,并且客观来说仍然很有用的、最简单的应用。重点在于,这是一段代码,而我的意思是,你也许已经注意到了,从去年开始代码已经发生了某种程度的变化。根本上来说,这是因为在去年,你的代码是用Serpent写的,而现在我们有了优于Serpent的Viper,待会可能还会有人来谈这个话题。因此,你有两种函数,而这两种函数代表了通过合约你可以做的事情。
domains: {owner: address, ip: num}[bytes32]def register(addr: bytes32):   if not self.domains[addr].owner:      self.domains[addr].owner = msg.senderdef set_ip(addr: bytes32, ip: num):   if self.domains[addr].owner == msg.sender:      self.domains[addr].ip = ip
(PPT上呈现的代码)
首先,你有了一个关于该合约实际上储存的东西的描述。这个合约储存了关于一个域(domain)的映射,谁是这个域的所有者,这个域支持指向的IP地址是什么。然后,有一个函数叫做注册(register),如果一个域还没有一个所有者,所有者会被给这个域发送信息的人所确定,无论TA是谁。所以无论是谁发送了交易,这个函数就被激活了。然后你还有另一个设置IP函数,激活这个函数也是非常简单的,它仅仅只是检查一下当你试图为一个域设置IP地址的时候你是否拥有它,如果是,它就会把IP设置为任何你想要的地方。
所以,在一个合约中,所有信息都储存在哪里呢?在一个简单的区块链上,你可以将区块链记录的状态(state)认为是仅仅对账户的余额作了一个简单的映射。地址12345拥有70个币,地址B7884拥有2万个币,诸如此类。以太坊的状态要略微丰富一点。但也仍然是对内在于账户的东西的一个映射,但这些内在于该账户的信息可以是复杂很多的。
所有,首先,你有账户余额,就是这个账户有多少以太币(ether)。你也有Nonce,基本上是一个用于重播攻击保护(replay protection)的对冲措施。你有合约的代码,如果该账户是一个合约的话。你也有合约库(contract storage),合约库就是一种小型的数据库,任何以太坊上的合约都可以使用。在这个案例中,从域到谁拥有这个域、它的IP地址是什么的映射,将在实际上被保存在合约库里。区块链上的历史就是发生过的事情,所以你拥有交易记录。在以太坊上,你拥有这个叫做“收据(receipt)”的概念。就现在而言,所有全节点都储存状态,一些全节点储存历史,而不存储历史的全节点也是有可能存在的。
所以,那就是我们到达的地方。每一个账户对象都包括4段数据。我会打开它大概5秒钟,因为每个人都想拍下它。5,4,3,2,1,下一张。
state
  • State consists of key value mapping addressed to account objects
  • Every account objest contains 4 pieces of data:
    • Nonce
    • Balance
    • Code hash(code = empty string for private key-controlled accounts )
    • Storage trie root

(当时的PPT内容)
代码运行
然后,代码运行。每一笔交易都指定了一个TO地址,每一笔交易都明确了该交易的目的地或者说目标是什么。如果交易的目标只是一个普通账户,或者在任何意义上是一个真实的人;以及,如果交易包含了以太币,那么该交易就意味着从一个账户到另一个账户的转账。
然而,如果交易的目标包含代码,也就是说如果交易的目标是一个合约,则目标地址的代码就会运行。代码能够做一系列的事情。因此合约也有能力发送以太币给另一个合约。它有能力读取和写入一个合约内部的库。所以,如果你回顾这个例子(译者注:上述domain例子),一个对注册函数(register function)的调用将变成一个交易,而这一交易将,你懂的,导致前述域的所有者被确定,以及在库中写入该信息,以及,(如果有需要)该声明从另一个库中读取信息。综上,它可以读取也可以写入库,它甚至可以调用另一个合约。这也被称为一个内部交易。基本上,合约可以与其它合约通信,其方式与外部用户与合约通信的方式完全一致。每一个区块链上的全节点都运行每一个交易并存储全部状态。我把它加粗了,因为这是重要的。
Gas
然后,以太坊上的Gas。普遍来说,有一个东西被称为“停机问题”(Halting Problem),它的基本意思是,你没有办法真正从原则上断定一个程序会不会永远跑个没完。分辨该程序会不会在一系列步骤之后结束,或者将一直运行下去,是一个不管用此种还是彼种方式都不可能从数学上得到证明的东西。所以,我们用的解决方案是这样一个机制:我们根据交易消耗的运算步骤对交易收费,而我们衡量运算步骤的单位就被叫做Gas。
Gas不是一种货币,对吗?Gas不是一种你可以转载或是持有的东西。Gas只是一个计量单位。它的意思是,这个计算,如果它消耗了3万单位的gas,那么它意味着该协议说为运行这一计算花费了3万单位的努力。同样也有特殊的gas费用用于占用库的操作,(因为)交易会占据空间。而以太坊网络招致的任何类型的成本都可以换算为某种类型的Gas支出。
每一笔交易都必须指定Gas限制,该交易必须明确它可以消耗的gas的最大数量;然后,当代码运行的时候,运行开始使用Gas;如果代码运行在Gas被耗尽之前停止了,那么万事大吉;但如果代码运行到达了一个所有Gas都被花费掉的点上,那么该交易会回复原状,从空气中消失,但交易的发送者仍然必须支付一笔费用。
所以,以太坊上的Gas限制是比特币上区块大小限制的对应物,而它被设定的方式也是非常简单的——基本上由矿工们投票来决定。现在,Gas上限是6.7百万单位。如果我们到达了上限并且有必要提高它,矿工们可以投票。非常简单。

视频链接: https://www.youtube.com/watch?v=Yo9o5nDTAAQ&feature=youtu.be
作者: Vitalik Buterin
翻译&校对: 阿剑 & Elisa

回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:35:37 | 显示全部楼层
干货 | Vitalik: 25分钟认识以太坊(下)
hongji   |   23. Nov, 2017   |   2162 次阅读

编者按:以下为Vitalik Buterin在Ethereum Devcon3上的演讲《Ethereum in 25 minutes, vision 2017》的下半部分。以下中文皆直接从视频中听写并译出,如有错失,请不吝赐教。
附: 干货 | Vitalik: 25分钟认识以太坊(上)
交易
以太坊上的交易有7个部分:
  • 交易nonce,基本上就是一种反交易重播措施,如果你正在发送交易,让我们假设如果我发送了10个以太币给Bob,它(nonce)防止Bob提取这一交易并在区块链上包含它100次,那样的话我就发送1000个了以太币给Bob。每一个交易都最多只能被包含一次。
  • Gas价格,就是你为你的交易所占用每一单位的gas付出的以太币数量,这就是给予矿工的交易费用。
  • Startgas,交易可以使用的gas最大数量限制,也就是该交易可以消耗的计算资源的最大数量。
  • To,就是目标。
  • 价值(Value),交易发送的以太币数量。
  • 数据,就是说,如果你的交易有一个合约目标,那么该合约就可以读取数据。所以,接着就是一种做比如明确函数争议这样的事情的方式。
  • V,R,S,就是一个ECDSA签名,这是为解密者设计的。V在这儿因为你需要额外的一个部分以从签名中还原公钥。所以,我们做的是公钥恢复,而非任何种类的验证,我们说那是比特币做事情的方式。
Log
Log是一种只可添加、而不可被合约所读取的库的形式。关于Log的重点是,让我们假设,现在有一个事件在合约运行过程中发生了,我们希望让人们搜索这些事件以及侦测这些已经发生的事件变得非常容易。所以一个Log可以长达4个“topic”(32 bytes),并且,这里有一个布隆过滤器(Bloom Fliter)所以你可以非常容易地搜寻topic。同时这也允许你存储任意数量的数据。这些Log被放进了一棵默克尔树,它允许非常高效的通往Log的轻客户端通道。如果你有一个轻客户端,你可以通过Log来搜索,你可以拿topic当作关键词,这也允许你非常容易地搜索到合约已经创建的一种特定类型的事件。这对于分散化应用(Dapp)编程来说是非常有用的。
以太坊虚拟机
以太坊虚拟机(Ethereum Virtual Machine,EVM)。一开始,你有一个堆栈,数字可以被加入(push)栈以及从栈中输出(pop)。你拥有内存,内存就是一个虚拟机可以进入的临时数据组。所以内存只能在我短暂地处于运行环境中的时候才能存在,一旦运行结束,内存也就停止存在了。(stortage),就像合约数据库一样,是永久的存储空间。环境变量,以太坊虚拟机上的合约可以获得像是区块数量或是时间戳这样的东西。而且你还有Log次级调用(sub-calling)所以合约有能力通过发送我们说的“内部交易”来调用其他合约。
大多数时候,你并不准备直接写作EVM代码,因为要直接写EVM代码是非常琐碎的。相反,你将用高级语言写作,然后编译成EVM代码。这里有一些这样的高级语言,你可以用Viper,Solidity,LLL,还有Bamboo。再一次地你可能注意到,Serpent不再被放在这个列表中了,如果你还在用Serpent,我建议你转换到Viper。
ABI
这就是函数调用得到被编译或说其代码被写到交易数据中的方式。所以如果你正在调用一个合约,那么实际上发生的事情就是它做了一个函数调用,以及,额,抱歉,如果你调用了一个函数,那么实际上发生的事情就是它创建了一个交易,并且该交易包含了在这一公式中被指定的数据。所以一开始有4byte是函数ID,然后32byte是一个要求,再来32byte是另一个要求。如果你试图请求一个合约中的一个函数,那么你的客户端将创建这个交易,广播这一交易到网路上,然后合约代码就可以读取交易数据,然后它将交易数据的初始4个byte解析为被调用的函数,而其它byte就是其他声明。所以,基本上这就是如何简单调用函数的。
默克尔树(Merkle tree)
(PPT上放着Ralph Merkle的照片)让我们都向Ralph Merkle(译者注:Merkle树的发明人。)鞠躬、祈祷! Ralph Merkle,他的Merkle树是唯一真正让轻客户端成为可能的东西,所以,这在技术上是非常重要的突破,它值得人们赋予崇高的敬意。
重点是,默克尔树允许一个交易被包含在一个区块中的证据成为可高效验证的,或者说,普遍性地允许任何特定的数据片段被包含在在一个非常大的数据块中的证据成为可高效验证的。所以,如果你拥有一大块的数据,你可以从你的数据中创建这个叫做“Merkle树”的数据结构,有了这棵默克尔树之后,你可以为任何在这棵树上的数据片段创建叫做“默克尔分支”的东西,也就是组成了默克尔树的这种哈希值。 加上所有这些中间层,通过把哈希值相互匹配,你就可以判断这段数据是不是真的在这棵树上,对吧?
所以,为了建立起这棵树,你可以拿来你的数据,把两个片段的数据放在一起哈希;为每两片数据做完哈希之后,再把得到的(两个)哈希值放在一起哈希;如是反复,最终将只剩下一个哈希值在顶端。要证明其中存在任何特定的数据,你只要得到这些哈希值的分支,然后让它们相互匹配。如果是否存在一个错误的话,(也就是说)如果你想证明一段数据并不在那里的话,那么至少其中一个哈希值将是无法匹配的。
在以太坊上,我们使用它以证明一些特定的交易是包含在区块中的,但也存在一些叫做“状态树(State Tree)”的东西。状态树就是整个以太坊状态的一棵默克尔树。所以,每一个账户、每一个合约,余额,Nonce,合约代码,合约库,以太坊上的所有数据的全部状态都被哈希在这棵树的结构中,而这棵树的根哈希值将成为区块头,这就是所谓的“状态根”。所以,从任何一个区块到下一个区块,总是会有一部分状态被修改,然后默克尔树就会改变。但我们有一种特定类型的树叫做“默克尔帕特里夏树(Merkle Patricia tree)”,意味着当状态发生改变的时候,默克尔树上必须做出的更新的数量实际上是非常小的。它是像对数那样变化的。有了这个,一个轻客户端就可以要求网络,“给我一个特定账户的默克尔分支”;而一些全节点可以用这一分支来回复;轻客户端自己就可以从头到尾检查该分支的哈希值。如果所有的哈希值都相互匹配,那么,太棒了!然后轻客户端就可以接受并且证实显示账户余额的特定数据、或者一些库的钥匙,是确实在默克尔树上的。
所以,在以太坊中,默克尔树是用在交易、状态和收据上的。帕特里夏树则允许高效的插入和删除操作。区块头则包含了这三种树。
拜占庭版本(Byzantium)中的更新
拜占庭是我们做的一个硬分叉,从10月16号开始运行,它引入了一系列新的很棒的隐私保护措施。拜占庭中有三种主要的、可能也是最让人感兴趣的特性。理论上来说,当然还有其他特性,但这三种让人感兴趣的东西是因为拜占庭中的新特性才成为可能的,对吧?这里包括我们叫做“预编译(pre-compile)”的东西,可以充分利用虚拟合约。虚拟合约的功能是做椭圆曲线编辑(eliptic curve edition)、椭圆曲线标量乘法(eliptic curve multiplication)、椭圆曲线配对(eliptic curve pairing)还有大数计算。这也允许你在以太坊上写合约来做一些事情,比如:验证环签名(Ring Signature),验证ZK-SNARKs,验证RSA签名(RSA signature),所以,这也可以被用来提升以太坊跟使用公钥、授权证书以及其他东西的现有系统的兼容性。接下来你还将听到这些东西。
除了这些,还有一系列很重要的特性,比如说:静态调用操作码(STATICCALL opcode),它允许你写作没有同等程度可变性的安全合约,以及在一些情况下重新进入(出现)问题(的地方),它同样允许你更容易去做纯粹功能性的变成。你拥有一个回返数据备份、恢复原状操作码(REVERT opcode),帮助你节约Gas,以及让EVM在某些情况下更高效的操作码,还有一系列更小的提升。但我会说,拜占庭硬分叉的主题是把这类强大的密码学加进去,以使强大的隐私保护应用成为可能。还有非常有有意思的的东西正在被建构到上面,比如说,你知道的, 建立在声誉系统上的ZK-SNARK(我昨天才听到这个东西)。这些都在非常快速地往前推进。
未来的方向
Casper,你们可以看Changwu的演讲,就在下一场。Vlad也准备展示他自己的Casper版本,称为“Casper CBC”。
分片(Sharding),可以看今天结束的时候我的演讲。虽然,我会说它不仅仅是关于分片的,它的主题在实际上比分片要广泛得多。它同样也是EVM更新的尾巴,一个小很多的协议升级。
现在,比起以太坊区块链核心技术的未来方向,可以被建设在以太坊上的第二层(second layer,数据链路层)架构、中间工具和系统有一个大得多的关于未来方向的列表。这包括可扩展性方案,比如Plasma;也包括可以被建设在环签名上的所有东西,你已经知道了,椭圆曲线乘法、匹配,ZK-SNARK;还包括多种其他多种隐私保护协议。还有状态通道(State Channel)系统。所有这些都是很棒的,也是非常重要的改进,我希望我们将听到更多关于它们的消息。
那么,谢谢你们。再一次,希望你能享受这次大会。

回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:36:06 | 显示全部楼层
以太坊概况
你可能已经听过“区块链”和“智能合约”这两个术语,但它们实际是什么意思?我们将揭开其神秘面纱,向你解释实用的区块链解决方案,然后给你一些如何创建它们的指导。这是一个高层次概述,包括:
区块链基础
为什么使用区块链?
什么是区块链?
区块链如何工作?
以太坊区块链
什么是以太坊?
什么是智能合约?
以太坊网络
分布式应用(Dapps)
为什么使用区块链?
当有很多个位于世界各地的参与方,它们之间在无法互相信任、但需要共享数据和传输价值情况下,就需要使用区块链了。金融界将这种信任描述为交易对手风险,即其他参与方最后不履约的风险。区块链通过一种创新的数学系统、密码学和点对点网络,完全解决了交易对手风险。在我们详细了解它们的工作原理之前,我们需要回顾一些历史,以及区块链产生的必要性。
第一个数据库
在20世纪60年代,第一台计算机式数据库出现。这些硬件占据了很多房间,而互联网还有几十年才出现,数据通常存储于中心的实体位置。这是一种中心化方式,意味着数据的位置和访问都由中央机构控制。中心化系统可由恶意角色从内部或外部控制,所以我们相信这些系统拥有者有足够意愿和资源来保护数据的安全性和完整性。中心化数据库在今天依然是最常见的,支持着大多数在线和离线应用。
自我托管博客就是中心化数据库的一种常见形式。所有者为了让文章更好,可以进行事后编辑,或者无需追索就可以审查用户。即使拥有一名正直的所有者,黑客也会渗透到服务器并实施恶意行为。如果没有数据库备份,那就几乎无法确认哪些数据被修改或损坏。
如下图所示,每个服务器边上的箭头都是需要信任的连接。
共享数据需求
共享大量数据是非常昂贵和麻烦的。我们可以通过在需要共享的各参与方分配数据来缓解这种负担。读 / 写由这个群体中的一方或多方控制,因此受制于类似中心化数据库的变化方式。
现代共享数据库使用技术来减少这种损坏,其中部分技术与区块链重叠。根据不同的共享数据库系统,它可以有以下特点:
  • 永久性:创建一个新拷贝并将旧数据保留为历史记录,而不是直接覆盖旧数据。该记录可以被访问,用于证明某一时刻存在的数据。
  • 共识性:对于要共享的数据库,所有参与方必须就其内容达成一致(达成共识)。有很多种达成共识的方法,其中一种(工作量证明),我们将在下一节区块链中讨论。

区块链具有以上特点并将其运用到更深层次,完全解决了信任问题。
什么是区块链?
区块链是核心是一个共享数据库,该数据库称作分类账本。就像一个银行,简单的区块链分类账本会跟踪货币(这里指加密货币)所有权。与中心化银行不同,每个人都有该账本的拷贝,而且可以验证彼此的账户。这就是区块链的分布式(或去中心化)特点。每个包含账本拷贝的连接设备被称作节点。
区块链网络中账户之间的交互被称作交易(Transactions),它们可以是货币交易,例如发给某个人以太坊中的加密货币以太币;它们还可以是数据传输,例如评论或用户名。区块链上的每个账户都有唯一的签名,让每个人都知道是哪个账户激活该交易。
比起之前的数据库,区块链除了解决信任问题,还有以下主要优点:
  • 完全去中心化:读 / 写数据库是分散和安全的,单独某个人或某个组无法控制区块链。
  • 极致容错:容错是系统处理损坏数据的能力,虽然容错能力不是区块链特有的,它将此概念逻辑化,让每个人共享数据库来验证其变化。
  • 独立验证:交易可以由任何人验证,无须第三方,这有时也被称作脱媒。

现在我们对区块链价值有一定了解,下面让我们来深入了解它们的工作原理。
区块链如何工作?
在一个公链中,任何人都可以读写数据。读取数据是免费的,但向公链中写数据是需要花费的。这种花费有助于阻止垃圾内容,并通过支付保护其安全性。网络上的任何节点都可以参与称作挖矿的方式来保护网络。由于挖矿需要计算能力和电费,矿工们的服务会得到一定报酬。
挖矿
网络中的每个节点可以选择参与挖矿。通常,节点的矿工需要竞争解决保护区块链内容的数学问题。每个区块都是刚创建的待处理交易集合,需要添加进链条中最新的区块后面。数学问题比赛的获胜者创造了下一个区块,并收到一些加密货币作为奖励。这激励了节点来保护网络,防止太多权力掌握在任何一个矿工手中。
哈希
一旦新区块被开采出来,其他矿工将被通知,它们开始验证并将这个新区块添加到其链条的副本中。我们之前提到的数学问题称作加密哈希(或简称哈希)。哈希函数是一个特殊单向的过程,它接收数据并返回一个表示该数据固定长度的字符串。虽然原始数据不能从其哈希值中再现,但相同数据始终产生相同的哈希值。因此,未验证的数据可以使用相同函数进行哈希,并与原始数据比较。 如果它们相同,则数据验证通过。
一旦一半以上的矿工验证了新区块,网络则就新区块达成共识,并成为链条中永久的一部分。现在这个数据可以很容易被非采矿节点下载(同步),且其有效性得到保证。
这是整个可视化过程:
1.Bob 尝试向 Alice 发送 1 ETH。
2.Bob 和 Alice 的交易与其它自上个区块之后发生的交易绑定在一起。
3.矿工们竞争验证新交易集合产生的区块。
4.成功创建新区块的矿工将会得到报酬。
5.交易通过验证,Alice 收到 1 ETH。
什么是以太坊?
以太坊不仅是一个数据库,它还允许你在区块链的可信环境中运行程序。以太坊在区块链上搭建了一个名为 EVM(Ethereum Virtual Machine,以太坊虚拟机)的虚拟机。EVM 允许在区块链上验证和执行代码,为代码在每个人的机器上以相同方式运行提供保障。这些代码包含在智能合约中(更多如下)。
除了追踪账户余额,以太坊使用相同方法将 EVM 的状态保存在区块链上。所有节点处理智能合约,来验证合约本身及其输出的完整性。
什么是智能合约?
智能合约是指在 EVM 上运行的程序,它们与其他编程语言十分相似。智能合约可以接受和存储以太币、数据、或两者组合。然后,使用编入合约的逻辑,它可以将以太币分发到其他帐户、甚至其他智能合约。你可以看到复杂系统是如何从这种灵活性中发展起来的。
智能合约是用 Solidity 语言编写的。Solidity 是静态类型,支持继承、库和复杂的用户定义类型等功能。它的文件扩展名是“.sol”。 Solidity 的语法类似于 JavaScript。 我们将在以后教程中介绍 Solidity 基础知识,但你也可以通过查看文档来深入了解。
这里继续 Bob 和 Alice 的智能合约案例。这一次,他们正在使用托管合约(一个货币储存空间,储存一定货币直到满足某条件),以便在最终交易之前存储其以太币。
1.Alice 想雇佣 Bob 来建立一个露台。为了让双方保持诚实,Alice 同意在托管合约中存放露台款项,Bob 同意在合约中存入同等金额。
2.Bob 完成了露台,Alice 很激动!她许可智能合约释放资金。
3.Bob 收回了 1 ETH 的抵押,和 Alice 支付的 1 ETH
在更复杂的托管合约中,如果 Bob 没有完成露台,或他完成的非常糟糕,可以将规定写入合约代码中,以释放 Bob 给 Alice 的抵押。
以太坊网络
到目前为止,我们已经描述了主要网络(或主网),以太坊的公链。任何人都可以创建一个节点并开始验证交易;因此,它是高度安全的。链上的数据,包括账户余额和交易,都是公开的。网络上的以太币具有市场价值,并可以交换其他数字货币、或例如美元的法定货币。
除了主网,还有测试网络(本地和公有),以及私有网络。
本地测试网络
以太坊区块链可以在本地进行模拟开发。本地测试网络可以即时处理交易,并且以太币可以根据需求进行分配。存在一系列的以太坊模拟器;我们推荐我们自己的:Ganache。
公有测试网络
这些测试网络是存在和公开的。这些网络上的以太币仅用于测试目的,没有货币价值。由于这些网络是公有的,所以货币是免费的,开发人员在最终部署以太坊应用程序到主网之前,需要使用它们测试。
* Ropsten:由以太坊基金会创建的官方测试网络。
  • Kovan:一种使用“权威证明(Proof of Authority)”共识方法的公有测试网络。这意味着其交易由选定人员进行验证,从而只需要4秒的出块时间。此测试环境上的以太币供应也受到控制,以减轻垃圾内容的攻击。这个链条的信息是公开的。 Kovan 是由 Parity 科技创建的,需要他们的 Parity 以太坊客户端。
  • Rinkeby:一个同样使用权威证明的官方测试网络。 任何以太坊客户端都可以访问,由以太坊基金会创建。

私有 / 企业网络
私有以太坊网络允许各参与方共享数据,而不使其公开访问。私有区块链是一个很好的选择,当:
  • 分享敏感数据,如医疗保健记录,这是不允许或不希望公开的。
  • 小团体需要更大的容量。随着网络规模的缩小,私有区块链可以扩展到更大的规模,并处理比公链更重的读 / 写量。

基于以太坊的私链同样运行EVM,因此也兼容 Truffle 和其他开发工具。摩根大通最初开发的Quorum就是一个非常好的例子,也与Truffle兼容。更多关于在Quorum上使用Truffle的内容请访问我们的博客。
Dapps(分布式应用程序)
使用智能合约的应用程序大多数(虽然不是全部)的后端处理称为 dapps,分布式应用程序的缩写。这些 dapps 的用户界面使用包括你可能已经知道的语言:HTML,CSS和JavaScript。这些文件可以托管在传统可信的 Web 服务器上,或无需信用的分布式文件服务上,如 SwarmIPFS
鉴于以太坊区块链的好处,dapp 可能是许多行业的解决方案,包括但不限于:
  • 档案保存
  • 货币(金融)
  • 供应链
  • 房地产
  • 交易市场
…这种例子不胜枚举。我们将在不久后提供如何建立自己的 dapps 的详细教程,所以将本教程加入书签,并继续关注吧。

原文链接: http://truffleframework.com/tutorials/ethereum-overview
作者: Truffle Team
翻译&校对: Nina & Elisa
回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-4-22 15:37:09 | 显示全部楼层
以太坊代币入门指南
什么是以太坊代币?
在学习以太坊代币(Ethereum tokens)之前,有必要先了解以太坊的基本原理。对于刚接触这些概念的人,可以先看我之前写的《以太坊入门指南》。以太坊代币是内置在以太坊区块链上的数字资产。它们受益于以太坊现有的基础设施,而不需要开发者重新构建全新区块链。它们还通过以太币(以太坊的本地货币,被用来驱动智能合约)来加强以太坊生态系统。这份入门指南可以帮助那些数字资产新人从更高的层面了解以太坊代币,以及它们和以太币的区别。

(数据采集于2017年5月22日)
对比
以太坊可以创建任何智能合约,包括可以表示数字资产的智能合约,而这些数字资产被称为以太坊代币。这类似 App Store 是提供 iOS apps 的平台一样,其中部分 apps 会在它们的游戏或平台中发行数字货币。然而,和 Apple 不同的是,以太坊没有中心实体来控制哪些 apps 可以上 App Store,每个人都可以在以太坊上发行代币。
以太坊代币可以用本地货币来表示任何实物,例如黄金(Digix)、用作支付交易费用的本地货币(Golem)。未来,代币甚至可以用来代表股票和债券等金融工具。每个代币的属性和功能完全遵守其预期用途的约束。代币可以有固定的供应量、恒定的通货膨胀率、甚至由复杂的货币政策来决定的供应量。代币可以用作多样化目的,例如支付访问网络,或用作去中心化组织的管理。
代币通常通过初始货币众筹(Initial Coin Offering,ICO)的销售方式进入公众视野。这些代币创建者会通过提供内置代币,来交换以太币、比特币或其他数字资产。近期有非常多的 ICO,在短短时间内改变了项目资金筹集的方式。尽管创建者希望去中心化应用程序中的代币尽可能被更多人拥有,但如何良好分配这些代币并没有限制。
图表来自于 thecontrol.co
现在有很多资料会教你创建新代币的过程,而且它们从技术层面解释了代币的工作原理。例如,代币工厂提供了一个简单的用户界面,允许你使用自定义参数来创建自己的以太坊代币。
类似比特币和以太,这些代币被记录在区块链上,也就是说所有已经发生的交易都被登记在了一个公开分类账本中。这是因为以太坊上的代币只是基于以太坊区块链一种特定的智能合约。
Aragon’s token tracked on Etherscan.io
现在市场上最大的以太坊代币是 Augur’s REP 和 Golem’s GNT。目前两个项目都在开发阶段,总市值 4.5 亿美元。我将简短阐述它们的工作原理,以便大家更好理解以太坊代币中的不同功能。
Augur
Augur是由 Joey Krug 和 Jack Peterson 共同创建的去中心化预测市场。该预测市场允许用户下注不同事件的结果,也可以用来对冲。例如,如果你有一枚价值 2000 美元的比特币,而且想对冲持有,你可以打赌比特币的价格在某一天会低于 2000 美元。如果比特币上涨,那么你持有的比特币会更加值钱,如果比特币价格下跌,那么通过该预测市场你将缩小你的损失。这些事件结果的报告并没有中心化来源,所以会降低有一个腐败记者的风险,但也增加了对分散报告的需求。
Augur 发布的以太坊代币称为 Reputation (REP),REP的恒定供应量为 1100 万枚,其中 80%众筹到了 530 万美元,这些代币用于预测市场事件结果的报告。所有活跃的 REP 持有者必须报告随机选择事件的结果,这维护了用来解决 Augur 预测市场结果的去中心化报告池。作为提供这一关键报告功能的奖励,REP持有人可获得平台上预测市场产生的所有交易费用的一半。如果有人试图撒谎或报告错误结果,那么作为惩罚,他们必须放弃所持的一部分 REP。此外,如果大部分 REP 持有者是不诚实的,那么人们将再也不想用 Augur,REP 的价格也会随之下跌。这鼓励人们在 Augur 系统中诚实行事。
Golem
Golem是一个由 Julian Zawistowski 领导的项目,它允许人们出租他们电脑的闲置算力。这个想法是通过创建一个全球超级计算机,使得计算能力更加便宜,有更多用户可以使用。
Golem 发行的以太坊代币叫 Golem Network Token (GNT),其恒定供应量为 10 亿枚代币,其中82% 通过众筹获得了 860 万美元。这些代币必须与 Golem 网络配合使用,用来支付算力的租用。由于访问此网络的代币有限,如果有更多的人想使用 Golem,那么 GNT 的价格就会上升。这理论上使GNT的持有者和使用者动机一致。
ERC20 代币
你也许听以太坊社区成员提起过 ERC20 代币。最初的 ERC20页面 “描述了实现代币合约的标准功能”,ERC20 是各个代币的标准接口。ERC20 代币仅仅是以太坊代币的子集。为了充分兼容 ERC20,开发者需要将一组特定的函数集成到他们的智能合约中,以便在高层面能够执行以下操作:
获得代币总供应量
获得账户余额
转让代币
批准花费代币
ERC20 让以太坊区块链上的其他智能合约和去中心化应用之间无缝交互。一些具有部分但非所有ERC20标准功能的代币被认为是部分 ERC20兼容,这还要视其具体缺失的功能而定,但总体是它们仍然很容易与外部交互。
资源
目前已经有很多现有和即将到来的以太坊代币。下面是一些能帮助你更好地理解以太坊代币的链接,同时有最及时和让人兴奋的新闻。
理解以太坊代币
以太坊代币最新消息
ICO Alert(https://www.icoalert.com/
Smith + Crown(https://www.smithandcrown.com/
Ethereum Subreddit(https://www.reddit.com/r/ethereum/
The Control(https://thecontrol.co/
Week in Ethereum News(http://www.weekinethereum.com/
The Dapp Daily(https://dappdaily.com/
感谢 Will Warren,和 Coinbase(https://www.coinbase.com/)的员工们,尤其是 Jordan Clifford、Reuben Bramanathan、David Farmer 和 Dan Romero。
免责声明:本文作者拥有很多种基于以太坊的资产,包括 Augur 的 Rep 和 Golem 的 Gnt。该文章中所有观点为作者所有。以太坊爱好者不会为文章中任何资产背书,你在交易或持有任何数字资产前须意识到损失风险。

原文链接:https://blog.coinbase.com/a-beginners-guide-to-ethereum-tokens-fbd5611fe30b
作者:Linda Xie
翻译&校对:Nina & Elisa
回复

使用道具 举报

622

主题

988

帖子

3549

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3549
 楼主| 发表于 2018-5-9 12:55:06 | 显示全部楼层
详解以太坊的工作原理
春花秋梦









不管你们知不知道以太坊(Ethereum blockchain)是什么,但是你们大概都听说过以太坊。最近在新闻里出现过很多次,包括一些专业杂志的封面,但是如果你们对以太坊到底是什么没有一个基本的了解的话,看这些文章就会感觉跟看天书一样。 所以,什么是以太坊?本质上,就是一个保存数字交易永久记录的公共数据库。重要的是,这个数据库不需要任何中央权威机构来维持和保护它。相反的它以一个“无信任”的交易系统来运行—一个个体在不需要信任任何第三方或对方的情况下进行点对点交易的架构。


依然感到很困惑?这就是这篇文章存在的理由。我的目标是在技术层面来解释以太坊的工作原理,但是不会出现很复杂的数学问题或看起来很可怕的公式。即使你不是一个程序员,我希望你看完之后最起码对技术有个更好的认识。如果有些部分技术性太强不好理解,这是非常正常的,真的没有必要完全理解每一个小细节。我建议只要宏观的理解一下事物就行了。

这篇文章中的很多议点都是以太坊黄皮书中讨论过的概念的细分。我添加了我自己的解释和图表使理解以太坊更加简单一点。那些足够勇敢的人可以挑战一下技术,去阅读一下以太坊的黄皮书。

好了, 让我们开始吧!

区块链定义

区块链就是一个具有共享状态的密码性安全交易的单机(cryptographically secure transactional singleton machine with shared-state)。[1]这有点长,是吧?让我们将它分开来看:

“密码性安全(Cryptographically secure)”是指用一个很难被解开的复杂数学机制算法来保证数字货币生产的安全性。将它想象成类似于防火墙的这种。它们使得欺骗系统近乎是一个不可能的事情(比如:构造一笔假的交易,消除一笔交易等等)。

“交易的单机(Transactional singleton machine)”是指只有一个权威的机器实例为系统中产生的交易负责任。换句话说,只有一个全球真相是大家所相信的。

“具有共享状态(With shared-state)”是指在这台机器上存储的状态是共享的,对每个人都是开放的。

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

以太坊模型说明

以太坊的本质就是一个基于交易的状态机(transaction-based state machine)。在计算机科学中,一个 状态机 是指可以读取一系列的输入,然后根据这些输入,会转换成一个新的状态出来的东西。


根据以太坊的状态机,我们从创世纪状态(genesis state)开始。这差不多类似于一片空白的石板,在网络中还没有任何交易的产生状态。当交易被执行后,这个创世纪状态就会转变成最终状态。在任何时刻,这个最终状态都代表着以太坊当前的状态。


以太坊的状态有百万个交易。这些交易都被“组团”到一个区块中。一个区块包含了一系列的交易,每个区块都与它的前一个区块链接起来。


为了让一个状态转换成下一个状态,交易必须是有效的。为了让一个交易被认为是有效的,它必须要经过一个验证过程,此过程也就是挖矿。挖矿就是一组节点(即电脑)用它们的计算资源来创建一个包含有效交易的区块出来。

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

为了让一个区块添加到主链上,一个矿工必须要比其他矿工更快的提供出这个“证明”。通过矿工提供的一个数学机制的“证明”来证实每个区块的过程称之为工作量证明(proof of work)。

证实了一个新区块的矿工都会被奖励一定价值的奖赏。奖赏是什么?以太坊使用一种内在数字代币—以太币(Ether)作为奖赏。每次矿工证明了一个新区块,那么就会产生一个新的以太币并被奖励给矿工。

你也许会在想:什么能确保每个人都只在区块的同一条链上呢?我们怎么能确定不会存在一部分矿工创建一个他们自己的链呢?

前面,我们定义了区块链就是一个具有共享状态的交易单机。使用这个定义,我们可以知道正确的当前状态是一个全球真相,所有人都必须要接受它。拥有多个状态(或多个链)会摧毁这个系统,因为它在哪个是正确状态的问题上不可能得到统一结果。如果链分叉了,你有可能在一条链上拥有10个币,一条链上拥有20个币,另一条链上拥有40个币。在这种场景下,是没有办法确定哪个链才是最”有效的“。

不论什么时候只要多个路径产生了,一个”分叉“就会出现。我们通常都想避免分叉,因为它们会破坏系统,强制人们去选择哪条链是他们相信的链。


为了确定哪个路径才是最有效的以及防止多条链的产生,以太坊使用了一个叫做“GHOST协议(GHOST protocol.)”的数学机制。

GHOST = Greedy Heaviest Observed Subtree

简单来说,GHOST协议就是让我们必须选择一个在其上完成计算最多的路径。一个方法确定路径就是使用最近一个区块(叶子区块)的区块号,区块号代表着当前路径上总的区块数(不包含创世纪区块)。区块号越大,路径就会越长,就说明越多的挖矿算力被消耗在此路径上以达到叶子区块。使用这种推理就可以允许我们赞同当前状态的权威版本。


现在你大概对区块链是什么有个理性的认识,让我们在再深入了地解一下以太坊系统主要组成部分:

账户(accounts)

状态(state)

损耗和费用(gas and fees)

交易(transactions)

区块(blocks)

交易执行(transaction execution)

挖矿(mining)

工作量证明(proof of work)

在开始之前需要注意的是:每当我说某某的hash, 我指的都是KECCAK-256 hash, 以太坊就是使用这个hash算法。

账户

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

这是两种类型的账户:

外部拥有的账户,被私钥控制且没有任何代码与之关联

合约账户,被它们的合约代码控制且有代码与之关联


外部拥有账户与合约账户的比较

理解外部拥有账户和合约账户的基本区别是很重要的。一个外部拥有账户可以通过创建和用自己的私钥来对交易进行签名,来发送消息给另一个外部拥有账户或合约账户。在两个外部拥有账户之间传送的消息只是一个简单的价值转移。但是从外部拥有账户到合约账户的消息会激活合约账户的代码,允许它执行各种动作。(比如转移代币,写入内部存储,挖出一个新代币,执行一些运算,创建一个新的合约等等)。

不像外部拥有账户,合约账户不可以自己发起一个交易。相反,合约账户只有在接收到一个交易之后(从一个外部拥有账户或另一个合约账户接),为了响应此交易而触发一个交易。我们将会在“交易和消息”部分来了解关于合约与合约之间的通信。


因此,在以太坊上任何的动作,总是被外部控制账户触发的交易所发动的。


账户状态

账户状态有四个组成部分,不论账户类型是什么,都存在这四个组成部分:

nonce:如果账户是一个外部拥有账户,nonce代表从此账户地址发送的交易序号。如果账户是一个合约账户,nonce代表此账户创建的合约序号

balance: 此地址拥有Wei的数量。1Ether=10^18Wei

storageRoot: Merkle Patricia树的根节点Hash值(我们后面在解释Merkle树)。Merkle树会将此账户存储内容的Hash值进行编码,默认是空值

codeHash:此账户EVM(以太坊虚拟机,后面细说)代码的hash值。对于合约账户,就是被Hash的代码并作为codeHash保存。对于外部拥有账户,codeHash域是一个空字符串的Hash值


世界状态

好了,我们知道了以太坊的全局状态就是由账户地址和账户状态的一个映射组成。这个映射被保存在一个叫做Merkle Patricia树的数据结构中

Merkle Tree(也被叫做Merkle trie)是一种由一系列节点组成的二叉树,这些节点包括:

在树底的包含了源数据的大量叶子节点

一系列的中间的节点,这些节点是两个子节点的Hash值

一个根节点,同样是两个子节点的Hash值,代表着整棵树


树底的数据是通过分开我们想要保存到chunks的数据产生的,然后将chunks分成buckets,再然后再获取每个bucket的hash值并一直重复直到最后只剩下一个Hash:根Hash。


这棵树要求存在里面的值(value)都有一个对应的key。从树的根节点开始,key会告诉你顺着哪个子节点可以获得对应的值,这个值存在叶子节点。在以太坊中,key/value是地址和与地址相关联的账户之间状态的映射,包括每个账户的balance, nonce, codeHash和storageRoot(storageRoot自己就是一颗树)。


同样的树结构也用来存储交易和收据。更具体的说,每个块都有一个头(header),保存了三个不同Merkle trie结构的根节点的Hash,包括:

状态树

交易树

收据树


在Merkle tries中存储所有信息的高效性在以太坊中的“轻客户端”和“轻节点”相当的有用。记住区块链就是一群节点来维持的。广泛的说,有两种节点类型:全节点和轻节点。

全节点通过下载整条链来进行同步,从创世纪块到当前块,执行其中包含的所有交易。通常,矿工会存储全节点,因为他们在挖矿过程中需要全节点。也有可能下载一个全节点而不用执行所有的交易。无论如何,一个全节点包含了整个链。

不过除非一个节点需要执行所有的交易或轻松访问历史数据,不然没必要保存整条链。这就是轻节点概念的来源。比起下载和存储整个链以及执行其中所有的交易,轻节点仅仅下载链的头,从创世纪块到当前块的头,不执行任何的交易或检索任何相关联的状态。由于轻节点可以访问块的头,而头中包含了3个tries的Hash,所有轻节点依然可以很容易生成和接收关于交易、事件、余额等可验证的答案。

这个可以行的通是因为在Merkle树中hash值是向上传播的—如果一个恶意用户试图用一个假交易来交换Merkle树底的交易,这个会改变它上面节点的hash值,而它上面节点的值的改变也会导致上上一个节点Hash值的改变,以此类推,一直到树的根节点。


任何节点想要验证一些数据都可以通过Merkle证明来进行验证,Merkle 证明的组成:

一块需要验证的数据

树的根节点Hash

一个“分支”(从 chunk到根这个路径上所有的hash值)


任何可以读取证明的人都可以验证分支的hash是连贯的,因此给出的块在树中实际的位置就是在此处。

总之,使用Merkle Patricia树的好处就是该结构的根节点加密取决于存储在树中的数据,而且根据点的hash还可以作为该数据的安全标识。由于块的头包含了状态、交易、收据树的根hash,所有任何节点都可以验证以太坊的一小部分状态而不用保存整个状态,这整个状态的的大小可能是非常大的。

Gas和费用

在以太坊中一个比较重要的概念就是费用(fees),由以太坊网络上的交易而产生的每一次计算,都会产生费用—没有免费的午餐。这个费用是以称之为”gas”的来支付。

gas就是用来衡量在一个具体计算中要求的费用单位。gas price就是你愿意在每个gas上花费Ether的数量,以“gwei”进行衡量。“Wei”是Ether的最小单位,1Ether表示10^18Wei. 1gwei是1,000,000,000 Wei。

对每个交易,发送者设置gas limit和gas price。gas limit和gas price就代表着发送者愿意为执行交易支付的Wei的最大值。

例如,假设发送者设置gas limit为50,000,gas price为20gwei。这就表示发送者愿意最多支付50,000*20gwei = 1,000,000,000,000,000 Wei = 0.001 Ether来执行此交易。


记住gas limit代表用户愿意花费在gas上的钱的最大值。如果在他们的账户余额中有足够的Ether来支付这个最大值费用,那么就没问题。在交易结束时任何未使用的gas都会被返回给发送者,以原始费率兑换。


在发送者没有提供足够的gas来执行交易,那么交易执行就会出现“gas不足”然后被认为是无效的。在这种情况下,交易处理就会被终止以及所有已改变的状态将会被恢复,最后我们就又回到了交易之前的状态—完完全全的之前状态就像这笔交易从来没有发生。因为机器在耗尽gas之前还是为计算做出了努力,

所以理论上,将不会有任何的gas被返回给发送者。


这些gas的钱到底去了哪里?发送者在gas上花费的所有钱都发送给了“受益人”地址,通常情况下就是矿工的地址。因为矿工为了计算和验证交易做出了努力,所以矿工接收gas的费用作为奖励。


通常,发送者愿意支付更高的gas price,矿工从这笔交易总就能获得更多的价值。因此,矿工也就更加愿意选择这笔交易。这样的话,矿工可以自由的选择一笔交易自己愿意验证或忽略。为了引导发送者应该设置gas price为多少,矿工可以选择建议一个最小的gas值他们愿意执行一个交易。

存储也有费用

gas不仅仅是用来支付计算这一步的费用,而且也用来支付存储的费用。存储的总费用与所使用的32位字节的最小倍数成比例。

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

费用的作用是什么?

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

以太坊是一个图灵完备语言(短而言之,图灵机器就是一个可以模拟任何电脑算法的机器。对于图灵机器不太熟悉的人可以看看这个 和这个 )。这就允许有循环,并使以太坊受到停机问题 的影响,这个问题让你无法确定程序是否无限制的运行。如果没有费用的话,恶意的执行者通过执行一个包含无限循环的交易就可以很容易的让网络瘫痪而不会产生任何反响。因此,费用保护网络不受蓄意攻击。

你也许会想,“为什么我们还需要为存储付费?”其实就像计算一样,以太坊网络上的存储是整个网络都必须要负担的成本。

交易和消息

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

最基本的概念,一个交易就是被外部拥有账户生成的加密签名的一段指令,序列化,然后提交给区块链。

有两种类型的交易:消息通信和合约创建(也就是交易产生一个新的以太坊合约)。

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

nonce:发送者发送交易数的计数

gasPrice:发送者愿意支付执行交易所需的每个gas的Wei数量

gasLimit:发送者愿意为执行交易支付gas数量的最大值。这个数量被设置之后在任何计算完成之前就会被提前扣掉

to:接收者的地址。在合约创建交易中,合约账户的地址还没有存在,所以值先空着

value:从发送者转移到接收者的Wei数量。在合约创建交易中,value作为新建合约账户的开始余额

v,r,s:用于产生标识交易发生着的签名

init(只有在合约创建交易中存在):用来初始化新合约账户的EVM代码片段。init值会执行一次,然后就会被丢弃。当init第一次执行的时候,它返回一个账户代码体,也就是永久与合约账户关联的一段代码。

data(可选域,只有在消息通信中存在):消息通话中的输入数据(也就是参数)。例如,如果智能合约就是一个域名注册服务,那么调用合约可能就会期待输入域例如域名和IP地址


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


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

当一个合约发送一个内部交易给另一个合约,存在于接收者合约账户相关联的代码就会被执行。


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

区块

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

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

区块头

关于包含在此区块中交易集的信息

与当前块的ommers相关的一系列其他区块头

Ommers解释

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

由于以太坊的构造,它的区块生产时间(大概15秒左右)比其他的区块链例如Bitcoin(大概10分钟左右)要快很多。这使得交易的处理更快。但是,更短的区块生产时间的一个缺点就是:更多的竞争区块会被矿工发现。这些竞争区块同样也被称为“孤区块”(也就是被挖出来但是不会被添加到主链上的区块)。

Ommers的目的就是为了帮助奖励矿工纳入这些孤区块。矿工包含的ommers必须是有效的,也就是ommers必须在父区块的第6个子区块之内或更小范围内。在第6个子区块之后,陈旧的孤区块将不会再被引用(因为包含老旧的交易会使事情变得复杂一点)。

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

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

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

parentHash:父区块头的Hash值(这也是使得区块变成区块链的原因)

ommerHash:当前区块ommers列表的Hash值

beneficiary:接收挖此区块费用的账户地址

stateRoot:状态树根节点的Hash值(回忆一下我们之前所说的保存在头中的状态树以及它使得轻客户端认证任何关于状态的事情都变得非常简单)

transactionsRoot:包含此区块所列的所有交易的树的根节点Hash值

receiptsRoot:包含此区块所列的所有交易收据的树的根节点Hash值

logsBloom:由日志信息组成的一个Bloom过滤器 (数据结构)

difficulty: 此区块的难度级别

number:当前区块的计数(创世纪块的区块序号为0,对于每个后续区块,区块序号都增加1)

gasLimit:每个区块的当前gas limit

gasUsed: 此区块中交易所用的总gas量

timestamp:此区块成立时的unix的时间戳

extraData:与此区块相关的附加数据

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

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


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

状态(stateRoot)

交易(transactionsRoot)

收据(receiptsRoot)

这三个树结构就是我们前面讨论的Merkle Patricia树。

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

日志

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

一个日志的实体包含:

记录器的账户地址

代表本次交易执行的各种事件的一系列主题以及与这些事件相关的任何数据

日志被保存在bloom过滤器 中,过滤器高效的保存了无尽的日志数据。

交易收据

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

区块序号

区块Hash

交易Hash

当前交易使用了的gas

在当前交易执行完之后当前块使用的累计gas

执行当前交易时创建的日志

等等

区块难度

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

区块的难度影响nonce,它是在挖矿时必须要使用proof-of-work算法来计算的一个hash值。

区块难度和nonce之间的关系用数学形式表达就是:


Hd代表的是难度。

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

另一方面,如果验证时间变的越来越慢,协议就会降低难度。这样的话,验证时间自我调节以保持恒定的速率—平均每15s一个块。

交易执行

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


首先,为了可以被执行所有的交易必须都要符合最基础的一系列要求,包括:

交易必须是正确格式化的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费用被加到从发送方传送给接收方的总值。


如何交易符合上面所说的所有要求,那么我们进行下面步骤。

第一步,我们从发送者的余额中扣除执行的前期费用,并为当前交易将发送者账户中的nonce增加1。此时,我们可以计算剩余的gas,将交易的总gas减去使用的intrinsic gas。


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

自毁集:在交易完成之后会被丢弃的账户集(如果存在的话)

日志系列:虚拟机的代码执行的归档和可检索的检查点

退款余额:交易完成之后需要退还给发送账户的总额。回忆一下我们之前提到的以太坊中的存储需要付费,发送者要是清理了内存就会有退款。以太坊使用退款计数进行跟踪退款余额。退款计数从0开始并且每当合约删除了一些存储中的东西都会进行增加。

第三步,交易所需的各种计算开始被处理。

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

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

gas的Ether就会矿工

交易使用的gas会被添加到区块的gas计数中(计数一直记录当前区块中所有交易使用的gas总量,这对于验证区块时是非常有用的)

所有在自毁集中的账户(如果存在的话)都会被删除

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

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

合约创建(Contract creation)

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

为了创建一个新的合约账户,我们使用一个特殊的公式来声明新账户的地址。然后我们使用下面的方法来初始化一个账户:

设置nonce为0

如果发送者通过交易发送了一定量的Ether作为value,那么设置账户的余额为value

将存储设置为0

设置合约的codeHash为一个空字符串的Hash值

一旦我们完成了账户的初始化,使用交易发送过来的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位。

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

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


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

好了,现在来说执行。

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

系统状态

用于计算的剩余gas

拥有执行代码的账户地址

原始触发此次执行的交易发送者的地址

触发代码执行的账户地址(可能与原始发送者不同)

触发此次执行的交易gas价格

此次执行的输入数据

Value(单位为Wei)作为当前执行的一部分传递给该账户

待执行的机器码

当前区块的区块头

当前消息通信或合约创建堆栈的深度

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

1

PC: 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)。

算法正式定义为:


m代表的是mixHash,n代表的是nonce,Hn代表的是新区块的头(不包含需要计算的nonce和mixHash),Hn是区块头的nonce,d是DAG ,就是一个大数据集。

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

PoW函数就是用来估算这两项的。

mixHash和nonce到底是如何使用PoW函数来计算出来的有点复杂,如果深入了解的话,我们可以另写一篇文章来讲解了。但是在一个高层面上,它大致就是这样计算的:

会为每个区块计算一个”种子”。每个“时期”的种子都不一样,每个时期是30,000个区块长度。对于第一时期,种子就是32位0的hash值。对于后续的每个时期,种子就是前一个种子hash值的hash值。使用这个种子,节点可以计算一个伪随机“缓存”。

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

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

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

挖矿作为安全机制

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

我们所说的区块链的安全又是什么意思?这非常简单:我们想要创造一个每个人都信任的区块链。像我们之前在这篇文章中讨论的那样,如果存在超过1条以上的链,用户的信任就会消失,因为他们没有能力合理的确认哪条链才是“有效的”。为了让一群用户接受存储在区块链中的潜在状态,我们需要有一群人信任的一个权威区块链。

这完完全全就是Pow算法所做的事情:它确保特定的区块链直到未来都一直保持着权威性,让攻击者创造一个新区块来重写某个历史部分(例如清除一个交易或者创建一个假的交易)或者保持一个分叉变得非常困难。为了首先让他们的区块被验证,攻击者需要总是比网络上的其他人要更快的解决掉nonce问题,这样网络就会相信他们的链是最重的链(基于我们之前提到的GHOST协议原则)。除非攻击者拥有超过一半的网络挖矿能力(这种场景也被称为大多数51%攻击 ),要不然这基本上是不可能的。


挖矿作为财富分配机制

除了提供一个安全的区块链,PoW同样也是分配财富给那些为提供这个安全而花费自己计算力的人的一种方法。回忆一下,一个矿工挖出一个区块的时候会获得奖励,包括:

为“获胜”区块提供的5 ether静态区块奖励(马上就会变成3 ether )

区块中的交易在区块内所消耗的gas

纳入ommers作为区块的一部分的额外奖励

为了保证PoW共识算法机制对安全和财富分配的使用是长期可持续的,以太坊努力灌输这两个特性:

尽可能的让更多的人可访问。换句话说,人们不需要特殊的或者与众不同的硬件来运行这个算法。这样做的目的是为了让财富分配模式变的尽可能的开放,以便任何人都可以提供一些算力而获得Ether作为回报。

降低任何单个节点(或小组)能够创造与其不成比例的利润可能性。任何可以创造不成比例的利润的节点拥有比较大的影响力来决定权威区块链。这是件麻烦的事情,因为这降低了网络的安全性。

在区块链网络中,一个与上面两个特性有关的一个问题是PoW算法是一个SHA256哈希函数。这种函数的缺点就是它使用特殊的硬件(也被称之为ASCIs)可以更加快速高效的解决nonce问题。

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

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



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Hi,Tokens  |网站地图

GMT+8, 2019-8-22 19:54 , Processed in 0.094316 second(s), 6 queries , File On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表