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

以太坊基金会 著

李志阔(网名:面神护法) 赵海涛 焦锋 译

中本聪2009年发明的比特币经常被视作货币和通货领域内一次激进的发展,这种激进首先表现为一种没有资产担保或内生价值[1],也没有中央发行者或控制者的数字资产。然而,在比特币这场实验里面,更重要的创新可能是其底层作为分布式共识实现机制的区块链技术,它一出现,便迅速吸引了人们的注意力。常常被人们提及的区块链技术的其他应用包括使用链上数字资产来代表定制货币和金融工具(彩色币[2]),某种基础物理硬件的所有权(智能资产[3]),如域名一样的没有可替代性的资产(域名币[4]),更复杂的应用包括数字资产直接被一段可以执行任意条款的代码控制(智能合约[5]),甚至还有基于区块链的“去中心化自治组织”(DAOs[6])。以太坊的目标就是提供一个内置成熟的图灵完备语言的区块链,用这种语言可以创建“合约”,编码任意状态转换功能。以太坊将允许用户通过简单的几行代码实现逻辑,创建上面提到的所有系统,以及更多的我们尚未想到的新系统。

以太坊

以太坊的目标是创建一个可实现去中心化应用的替代性协议,并提供一种不同的权衡模式,这在很多去中心化应用的实践 中是非常有用的。我们特别强调,时间快速发展的状态、简单稀有应用的安全性、不同应用有效地相互作用的能力都是很重要的。以太坊通过图灵完备编程语言的区 块链来实现这一点。以太坊允许任何人编写智能合约和去中心化的应用,并允许在其中自定义所有权规则、交易格式和状态转换函数。要使用以太坊,对于一个准域 名币的系统,只需要两行代码就可以完成,而其他的诸如货币和信誉系统,也可以用不到二十行代码完成。智能合约(包含价值且只有达成某些条件时才能打开的加 密“箱子”)也可以在以太坊平台上创建,由于增加了图灵完备性(Turing-Completeness)、价值知晓(Value- Awareness)、区块链知晓(Blockchain-Awareness)和状态(State)等特点,以太坊所能提供的智能合约比比特币脚本提供 的(智能合约)功能强大得多。

以太坊账户

在以太坊系统中,状态是由被称为“账户”(每个账户有一个20字节的地址)的对象和在两个账户之间转移价值与信息的状态转换构成的。以太坊的账户包含4个部分:

1)随机数,用于确定一笔交易只能被处理一次的计数器。

2)账户目前的以太币余额。

3)账户的合约代码(如果有的话)。

4)账户的存储(默认为空)。

以太币(Ether)是以太坊内部的主要加密燃料(Crypto-Fuel),用于支付交易费用。一般来说,以太 坊有两种类型的账户:外部所有者账户(由私钥控制)和合约账户(由合约代码控制)。外部所有者账户没有代码,人们可以通过创建和签署一笔交易而从一个外部 所有者账户发送消息;每当合约账户收到一条可以激活其内部代码的消息,就会允许它对内部存储进行读写,发送其他消息或者创建新的相应合约。

注意,以太坊中使用的“合约”不应该被看作某些应该被“完成”或者“遵守”的东西,它们更像是生活在以太坊执行环境内部的“自动代理人”,当被某条消息或者交易“拨动”时,他们总是执行某个特定的代码,对以太币余额和秘钥/价值存储直接控制,对账户的变化持续追踪。

交易和消息

交易

以太坊中使用的“交易”是指从外部所有者的账户签发包含消息的数据包。交易包括:

·消息的接收者。

·验证发送者的签名。

·从发送者到接收者转移的以太币的数量。

·一个可选的数据区。

·一个STARTGAS值,代表交易执行过程中被允许的计算步骤的最大值。

·一个GASPRICE值,发送者为每一步计算支付的费用。

前三步在任何加密货币体系中都是可预期的标准步骤。可选的数据区目前并没有任何默认功能,但是有这样的操作码,即允许合约引用这里的数据。

在以太坊抵抗拒绝服务攻击的模式中,STARTGAS和GASPRICE字段是关键的部分。为了防止代码中出现计 算浪费,乃至出现意外或者恶意定义的无限循环,每个交易被要求设定一个代码执行过程可以使用的计算步骤的上限。计算的基本单位是“瓦斯”(gas),通常 一步计算消耗1gas,但是有些计算由于更加复杂,或者增加了作为状态的一部分而必需存储的数据量,会消耗更多的瓦斯。每一个字节的交易数据也会消耗 5gas。费用系统的初衷在于要求攻击者为他们消耗的资源支付相应的代价,比如计算能力、带宽、存储等。因此会带来更多网络消耗的交易也要支付大致相应的 交易费(瓦斯)。

消息

交易可以向其他合约发送“消息”,消息是虚拟的,永远不会序列化,只存在于以太坊执行环境中。一则消息包括:

·消息的发送者(隐式的)。

·消息的接收者。

·与消息同时传递的以太币的数量。

·一个可选的数据区。

·一个STARTGAS值。

基本上,除了消息是由一个合约而不是外部所有者账户发出之外,消息和交易类似。当一个合约执行“CALL”操作码 的时候,消息产生,该操作码的功能就是生成和执行消息。像交易一样,消息可以使接受消息的合约执行自己的代码。因此合约可以和外部所有者的账户一样,与其 他账户发生关系。

以太坊状态转换函数

以太坊的状态转换函数:APPLY(S,TX)->S',可以定义如下:

image.png

1)检查交易格式是否正确(比如数值是否正确等)、签名是否有效、随机数是否与发送者账户的随机数匹配。如果不是,返回错误。

2)计算交易费用:fee=STARTGAS*GASPRICE,并从签名中确定发送者地址。从发送者的账户中减去交易费用,增加发送者的随机数。如果账户余额不足,返回错误。

3)初始值GAS=STARTGAS,按交易中的字节数减去一定量的瓦斯值。

4)将交易价值从发送者的账户转移到接收者账户。如果接收账户还不存在,则创建此账户。如果接收账户是一个合约,则运行该合约的代码,直到代码运行结束或者瓦斯用完。

5)如果因为发送者账户没有足够的钱或者代码执行耗尽瓦斯,从而导致价值转移失败,则恢复除了交易费之外的初始状态,交易费送至矿工账户。

6)如果没有失败,则将所有剩余的瓦斯归还给发送者,消耗掉的瓦斯作为交易费用发送给矿工。

例如,假设合约代码如下:


 

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


需要注意的是,在现实中,合约代码是用底层以太坊虚拟机(EVM)代码写成的。而为了清楚起见,上面的合约用的是 高级语言Serpent语言写成的,它可以被编译成EVM代码。假设合约存储器在开始时是空的,交易发送值为10以太,瓦斯数为2000,瓦斯价格为 0.001以太,整个数据大小为64字节。0~31字节代表号码2,32~63字节代表字符串CHARLIE。交易发送后,状态转换函数的处理过程如下。

1)检查交易是否有效、格式是否正确。

2)检查交易发送者是否至少有2000×0.001=2个以太币。如果有,从账户中减去2个以太币。

3)初始设定gas=2000,假设交易长为170字节,每字节的费用是5,减去850,所以还剩1150。

4)从发送者账户减去10个以太币,为合约账户增加10个以太币。

5)运行代码。在此案例中,运行代码很简单:它检查合约存储索引为2的位置是否已被使用,如果未被使用,将其值设为CHARLIE。假设这消耗187gas,于是剩余瓦斯为1150-187=963gas。

6)向发送者的账户增加963×0.001=0.963个以太币,返回最终状态。

如果交易的接收端没有任何合约,那么所有的交易费用就等于GASPRICE乘以交易的字节长度,与交易同时传递的消息数据与交易费用无关。

代码执行

以太坊合约使用的代码是低级的基于堆栈的字节码语言,被称为“以太坊虚拟机代码”或者“EVM代码”。代码由一系 列的字节构成,每一字节代表一项操作。一般而言,代码执行的是重复操作构成的无限循环,程序计数器(初始值为零)随着每一次执行加1,直到代码执行完毕或 者遇到错误,或者发现STOP/RETURN指令。操作可以访问3种存储数据的空间:

1)堆栈,一种后进先出的数据存储。

2)内存,可无限扩展的字节队列。

3)合约的长期存储,一个秘钥/数值的存储,不像计算结束后将重置的堆栈和内存,该空间的存储内容将长期保持。

代码可以像访问区块头数据一样,访问数值、发送者和接收到的消息数据,代码还可以返回数据的字节队列作为输出。

EVM代码的正式执行模型惊人的得简单。当以太坊虚拟机运行的时候,它的完整计算状态可以由元组 (block_state,transaction,message,code,memory,stack,pc,gas)来定义,这里的 block_state是包含所有账户余额和存储的全局状态。每轮执行开始时,通过调出代码的第pc(程序计数器)个字节,找到当前指令。在如何影响元组 上,每个指令都有自己的定义。例如,ADD使两个元素出栈并将它们的和入栈,将gas减1并使pc加1,SSTORE使顶部的两个元素出栈并将第二个元素 插入由第一个元素定义的合约存储位置,同样减少最多200的瓦斯值并将pc加1,虽然通过即时编译,有许多方法可以优化以太坊虚拟机的执行,但以太坊的基 本功能可以用几百行代码来实现。

区块链和挖矿

image.png

虽然有一些不同,但以太坊的区块链在很多方面类似于比特币区块链。它们的区块链架构的主要不同在于,以太坊区块不仅包含交易记录还包括最近的状态,除此之外,以太坊区块链还包含区块序号和难度值。以太坊中的基本的区块确认算法如下:

1)检查区块引用的上一个区块是否存在和有效。

2)检查区块的时间戳是否大于引用的上一个区块,而且小于当前时间之后的15min。

3)检查区块序号、难度值、交易根,叔根和瓦斯限额(许多以太坊特有的底层概念)是否有效。

4)检查区块的工作量证明是否有效。

5)将S[0]作为上一个区块结束时的状态。

6)将TX作为区块的交易列表,设有n笔交易。对于属于0~n-1之间的任意一笔交易i,令S[i+1]=APPLY(S[i],TX[i])。如果任何一个过程发生错误,或者程序执行到此处所花费的瓦斯超过了GASLIMIT,则返回错误。

7)用S[n]给S_FINAL赋值,向矿工支付区块奖励。

8)检查S_FINAL状态的Merkle根是否与区块头提供的状态根一致。如果是,区块有效,如果不是,区块无效。

乍看起来,这一确认方法的效率似乎很低,因为它需要存储每个区块的所有状态,但是事实上以太坊的确认效率可以不低 于比特币。原因是状态存储在树结构中,每经过一个区块后,只需要改变树结构的一小部分。因此,一般而言,两个相邻的区块的树结构绝大部分是相同的,因此存 储一次数据,可以利用指针(即子树哈希)引用两次。一种被称为“帕特里夏树”(Patricia Tree)的树结构可以实现这一点,其中包括对Merkle树概念的修改,不仅允许改变节点,而且还可以插入和删除节点。另外,因为所有的状态信息是最后 一个区块的一部分,所以不用存储全部的区块历史——如果这一策略可以应用到比特币系统中,则可以提供5~20倍的空间节省。

一个经常被问及的问题是,在物理硬件层面上,合约代码在哪里执行。简单的回答是,合约代码的执行过程是状态转换函 数定义的一部分,是区块确认算法的一部分,所以如果一笔交易被加入到区块B中,那么这个交易引发的代码执行将会在所有目前和将来会下载与验证区块B的节点 中进行。

计算和图灵完备

很重要的一点是,以太坊虚拟机是图灵完备的,这意味着EVM代码可以完成人们能想到的所有计算,包括无限循环。 EVM允许两种形式的循环:首先,有一个JUMP指令,允许程序跳回到代码前面的某处,而JUMP1指令则可以实现有条件的跳转,允许类似下面的语 句:while x<27:x=x*2。其次,合约可以调用其他的合约,潜在地允许通过递归实现循环。这自然带来一个问题:恶意用户可以通过使矿工和全节点进入无限 循环而令用户不得不关机吗?这个问题出现的原因是:一般意义上,我们没有办法预知一个程序是否会结束(计算机科学中的停机问题(Halting Problem))。

正如前面所述,解决方案是为每一个交易设定计算步骤的最大数量,如果执行超过设定的步骤,则将交易恢复成原状但仍要支付费用。消息发送以同样的方式工作。为显示这一方案背后的动机,考虑下面的例子:

·攻击者创建了一个运行无限循环的合约,然后发送一个激活该循环的交易给矿工,矿工将处理交易,运行无限循环直到瓦斯耗尽。尽管瓦斯耗尽,交易半途停止,但交易依然是正确的(返回原状),并且矿工依然从攻击者那里得到了每一步计算的费用。

·攻击者创建一个非常长的无限循环,试图令矿工长时间计算,在计算结束前,若干区块已经产生,于是矿工无法收录交易以赚取费用。然而,攻击者需要发布一个STARTGAS值以限制可执行步数,因而矿工将提前知道该计算将耗费过多的步数。

·为减少风险,一个金融合约靠提取9个专用数据发布的中值来工作,攻击者接管了其中一个数据发布器,然后按可变地址调用机制将其更改为运行一个无限循环,试图令任何使用此金融合约的尝试都因瓦斯耗尽而中止。然而,该金融合约可以在消息里设置瓦斯限制以防范此类问题。

此外,图灵不完备甚至不是一个大的限制,在我们设想的所有合约例子中,至今只有一个需要循环,而且这一个循环也可 以被26个重复的单行代码段代替。既然图灵完备会带来很多潜在的麻烦并且益处有限,为什么不简单地使用一种图灵不完备语言呢?事实上图灵不完备并非一个简 洁的问题解决方案。为什么?请考虑下面的合约:

C0:call(C1)call(C1)

C1:call(C2)call(C2)

C2:call(C3)call(C3)

...

C49:call(C50)call(C50)

C50:(运行程序中的每一个步骤并在存储中记录发生的变化)

现在,发送一个交易给A,这样,在51个交易中,我们有了一个需要花费250步计算的合约,矿工可能会尝试通过为 每一个合约设置一个最高可执行步数,并且针对递归调用其他合约的合约计算可能执行的步数,从而预先检测出这样的逻辑炸弹,但是这会使矿工禁用可以创建其他 合约的合约(因为上面26个合约的创建和执行可以很容易地放入一个单独合约内)。另外一个问题是消息的地址字段是一个变量,所以通常来讲,几乎无法预知一 个合约将要调用哪一个合约。于是,最终我们得到一个令人惊诧的结论:对图灵完备协议的管理很容易,而除非有相当的控制措施,图灵不完备时的管理惊人得困难 ——那为什么不让协议图灵完备呢?

[1] 引用自http://bitcoinmagazine.com/8640/an-exploration-of-intrinsic-value- whatit-is-why-bitcoin-doesnt-have-it-and-why-bitcoin-does-have-it/。

[2] 引用自https://docs.google.com/a/buterin.com/document/d/1AnkP_cVZTCMLIzw4DvsW6M8Q2JC0lIzrTLuoWu2z1BE/edit。

[3] 引用自https://en.bitcoin.it/wiki/Smart_Property。

[4] 引用自http://namecoin.org/。

[5] 引用自http://szabo.best.vwh.net/smart_contracts_idea.html。

[6] 引用自http://bitcoinmagazine.com/7050/bootstrapping-a-decentralized-autonomouscorporation-part-i/。

来源:我是码农,转载请保留出处和链接!

本文链接:http://www.54manong.com/?id=338

'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646208", container: s }); })();
'); (window.slotbydup = window.slotbydup || []).push({ id: "u3646147", container: s }); })();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值