天涯书库 > 区块链:技术驱动金融 > 10.7 以太坊和智能合约 >

10.7 以太坊和智能合约

我们已经介绍了几种用比特币的脚本语言写出有趣的应用的方法,如有托管功能的支付交易。我们也看到比特币脚本语言的一些瓶颈:只有很少的指令,并不符合图灵计算的标准。因此,很多新的另类币增添与应用程序相关的特殊功能。域名币是第一个尝试,后来又有许多加密货币,类似于比特币但是支持赌博、股票发行、市场预测等。

设想我们不需要为了每个应用程序,每次都建设一套新的系统,而是创造出一个加密货币系统,以支持所有未来可以想象到的任何应用。这就是所谓的图灵完备——据我们理解,满足图灵完备标准的编程语言,可以让你写出图灵机可以完成的任意功能,它可计算的函数和图灵机可计算的函数是完全相同的。因此,每一图灵完备的编程语言——包括我们熟悉的Java、Python和Lisp——都是图灵等价的。如果不考虑实际中的简单性和表现,图灵完备是我们在编程语言有关表达能力上需要的最好的性质。

从某种程度上讲,今天加密货币的发展使人回想起20世纪40年代早期计算机发展的时代:在第二次世界大战时,建造大量的复杂的只有某种特定功能的计算器(比如用于暴力破解密码的机器和海军用于确定发射弹道轨道的机器),这些工作促使研究专家致力于建造第一个可重复编程的通用计算机。任何可预见的应用程序都可以使用该计算机(见图10.8)。

图10.8 在布莱切利园(Bletchley Park)博物馆重建的炸弹机(Bombe)

注:炸弹机是一个由阿兰·图灵(Alan Turing)设计的特殊功能的高级计算机,用于破解德国的英格玛(Enigma)密码。通用计算机取代类似炸弹机的精巧装备,以太币能否也能像这样取代特殊功能的另类币呢?

以太币(Ethereum)是一种雄心勃勃的另类币,致力于提供一种满足图灵计算要求的可编程语言,用这种语言可以编写脚本或者合约。虽然有其他方案可以做到这一点,但是以太坊无疑是最引人注目的:它使用了几个创新的技术,成功地完成了众筹,在几个月内筹资两千万美元,并且采用激进的参数,比如使用较短的产生区块的时间参数。以太坊系统本身很复杂,需要再编写一本新的教材才能完整阐述,本节只做简要讨论。

智能合约编程模式

智能合约最初是用来指使用计算机系统(或者其他自动化方式)来执行合约。例如,你可以把自动售货机看成一个销售商品的智能合约,执行的就是你和机器主人之间关于如何购买一个糖果的合约。

在以太坊体系,一个合约就是一个存在区块链里的程序。任何人支付一点费用,就可以用特定的操作将他的程序上传,建立一个以太坊合约。这个合约是用字节码(bytecode)写的,可以被特殊的以太坊专用虚拟机(Ethereum-specific Virtual Machine,简称EVM)执行。一旦合约上传,便永远存在在区块链里。智能合约有它自己的资金账户,其他用户可以调用程序里面开放的应用程序编程接口(API),合约可以收发款项。

一个简单的例子:以太坊中的域名币

我们说以太坊可以用来执行任何特定应用的另类币功能。举个简单的例子,我们可以展示使用一个简单的以太坊合约,来构建出域名币形式的功能。

图10.9 所示就是一个构建的案例。它是以“稳健”语言(Solidity)编写,“稳健”是以太坊里用于定义合约的高级编程语言。这个合约产生一个原始的域名/数值(name/value)储存配对或者注册名。名字永远连着数字。这个合约定义了一个数字变量——注册表(registryTable), 里面有32比特长字节和公开密钥的配对关系。初始时期,每个字节都对应着空地址0×0000000…000。这个合约同时定义了单一入口点,叫“用户名称”(claimName)。这个入口点只接受名字参数。首先,这个合约确认调用这个合约的人已经支付了至少10个wei。wei是在以太坊里最小的货币单位。如果没有支付10wei, 合约自动终止并发出错误信号(“throw”的编程命令就做这些)。如果足够的wei已经发出而且这个名字还没有被注册,那么这个名字就和调用的地址永久地联系在一起。

图10.9 一个用于实现域名注册功能的简单以太坊智能合约

以上就是这个8行代码的合约能做的事。我们还可以多花点时间,把其他域名币有的功能都在这个合约里实现。比如,可以存储拥有者地址以外的信息,通过存储上次更新时间来要求域名的主人定期地重新注册,并且允许其他用户拥有长期不更新的域名权。

我们还可以加第二个功能,允许钱回撤。按照初始的代码设计,钱只能不断堆积在合约里,也就意味着从流通中消失。当然,在可以回撤钱的程序里,最好能设定,调用回撤的是合约的主人。任何人在以太坊都可以调用任何方程,但是用户是指定的,所以能确认谁是真正调用方程的人。

燃料、激励和安全

和比特币不一样的是,以太坊支持循环语句,虽然第一个例子里并不需要循环。循环语句一听就容易让人产生警觉,因为有循环的地方就会有无限死循环。从根本上说,以太坊合约有可能因为种种原因而无限循环。计算机领域里一个著名的研究结果(难以判断的终止问题)证明,不存在任何算法,可以根据源代码去判断一个程序是否可以无限运行下去。因此,我们如何防止合约无限运行下去呢?

更进一步讲,即使条约不会无限运行,也需要某种方式来限制它不会运行太久。以太坊体系通过一种称作“燃料费用”的机制来实现这一点。简单地说,每执行一条虚拟机器的指令需要花费一小部分的成本费用,我们称之为“燃料费用”。不同的操作花费不同。基本的像加减操作只花费1单位燃料费用,而计算SHA-3哈希值(内置函数)需要20单位燃料费用,在永久存储器上写256比特长的字符需要100单位燃料费用。每笔交易也需要先支付21 000单位燃料费用。你可以把以太坊体系想象成超级折扣的航空公司。机票只是你支付乘飞机的费用,任何其他需求都要多付钱。完整操作清单和固定的燃料费用都可以从以太坊里找到。任何清单和费用的变动都需要以太坊产生一个硬分叉,这和比特币脚本语言的语义改变一样。

燃料费用是通过以太坊体系内部被称为以太(ether)的货币来支付的。它只是在用来支付合约操作的时候才叫燃料费用。每笔交易都规定了燃料的价格,也就是说,每份燃料需要多少以太。燃料费用就像比特币的交易费,矿工可以自由公布交易的燃料费用,每个矿工都可以独立地决定收费方式。这样会得出一个反映市场供求关系的燃料市场价格。2016年年初,虽然以太坊网络体系还是属于实验阶段,市场已经默认50 gigawei为1单位价格。50gigawei等于5×10-8以太,根据以太币和比特币2016年1月的汇兑比例,这也就是大约3×10-10比特币。

每次调用之前,必须设定燃料费用的最高限,也就是愿意支付价格的最大值。当达到这个值(燃料用完了),程序就会终止,发生的所有程序状态的变化就会被重新设置到原始状态,但是矿工还是保留燃料。由此可见,不要用完燃料,这一点非常重要。

燃料的使用要求,意味着以太坊不适合很耗费资源的计算。以太坊系统未被设计成像云计算那样的服务,即支付一定的费用让云服务完成自己无法做到的计算。像亚马逊的弹性计算云或者微软云计算平台,提供划算百万倍的计算量。另一方面,以太坊更加适合创建安全逻辑协议。本质上来说,以太坊提供了一种两个或者多个匿名交易者可以信赖的服务系统。

以太坊上区块链的安全还没有像比特币一样完善。理论上,以太坊比较复杂,也比较难以用数学推理来论证。实际上,以太坊才刚刚开始发展,其安全性还没有像比特币一样经过很多考验。尤其是,担心处理交易的成本会让类似比特币的激励机制失效,我们在共同挖矿的分析中讨论过存在这种担心的情况。当交易成本占矿工的总成本的比重不再能忽略不计的时候,大的矿工有明显优势,因为成本和哈希算力相互独立。更重要的是,燃料只支付给最初包括该交易的区块的挖工。但是所有的在这之上建立区块的矿工都必须验证该区块,却得不到任何报酬。这意味着,他们将有动力去跳过该验证。正如之前所看到的,这种情况不利于区块链体系的健康发展。

第二个例子:以太坊体系中的国际象棋

我们还没涉及以太坊中新功能如何运用,所以让我们看第二个案例。假设爱丽丝和鲍勃下国际象棋,赌注是一定数额的金钱。唯一的问题是爱丽丝和鲍勃生活在不同的国家,他们都不相信对方输了会支付赌注。这个问题可以用以太坊来解决。

爱丽丝写下以太坊程序,这个程序设定了国际象棋的规则并且被上传到以太坊网络。她给这个合约支付一定数量的以太作为赌注。鲍勃可以看到这个合约,如果他答应接受挑战,他把他的赌注支付给这个合约,就等于开始了这个游戏。鲍勃在接受挑战之前应该确认,这个合约是准确无误地遵守了国际象棋的规则,并且最后会把所有赌注支付给获胜者。

一旦双方都支付了赌注,假设他们约定下同样的赌注,合约会检查双方的赌注是否相等。这时候,游戏就开始了。任何一方除非赢了游戏,否则无法从合约里取出钱来。其他人在任何情况下也无法取得这笔钱。

爱丽丝和鲍勃轮流把自己的下棋步骤发给这个合约。这个合约也会检查轮到谁下确保指令是由爱丽丝或者鲍勃发出,而不是其他人。大家是否还记得调用者需要在每个操作(促使合约执行一个动作)上签名,因为合约可以根据签名确认调用者。合约也会根据国际象棋的规则校验双方的步骤。如果一方试图把兵移动3格,合约会拒绝该步骤。

到最后游戏结束。合约在每一步都会检测是否有一方被将军,或者双方打平,或者满足其他打平的条件。玩家也可以发送投降的指令。当游戏结束时,合约终止,并把所有的钱支付给获胜者,或者平局下平分赌注。

从概念上看,这是一个以太坊的简单应用,但是有很多微妙的地方值得探讨。如果一方快输了他就放弃了?合约应该设定一个机制,如果一方在规定的时间没有提交有效的下一步,钱就支付给另一方。

哪个玩家先走呢?白方先走的话,白方就拥有微小的优势。因此,双方都想做白方。这就碰到了以太坊合约的一个难题:没有内置的随机源。之所以是一个难题,是因为随机数发生器需要所有矿工的检验(因为他们需要检验合约是否正确地执行),但是这些随机数对任何人来说都是不可预测的(否则的话,玩家也许就因为不能先走而拒绝参加这个游戏)。

随机数“信号塔”(randomness beacons)可以解决这个问题。正如9.4节讨论的,在双方都加入游戏后,合约计算区块链下一个区块的哈希值。对这个特定的游戏应用而言,这个问题比较容易解决,因为只要让爱丽丝和鲍勃双方确信决定谁先谁后是随机的,这样就满足要求,而不需要向所有人证明。所以他们可以采用9.3节的办法:他们两个同时提交一个随机数的哈希值,并且公开他们的输入值,然后从双方的输入总值算出随机数。实际操作中,以上两种方法都可以使用。

其他应用

下棋也许很有趣,但是真正激动人心的是以太坊在金融领域的应用。我们在课本里讨论的大部分应用,包括市场预计、智能资产、托管支付、微支付渠道和混合服务,都可以在以太坊体系里实现。这些应用都有其细微的区别,但是相对比特币死板的协议,大多数情况下,这些应用都能相对容易地在以太坊体系内完成。

以太坊的状态和账户余额。第3章中,我们讨论了账本的两种方法: 基于账户和基于交易。在一个基于交易的账本中,如比特币,区块链只存储交易(加上一些少量的转载标题的设置数据)。为了方便验证交易,比特币的币值是无法分割的,即交易的结果必须整体被消费,可以自己消费,或者如果需要的话,换地址消费。交易实际上是在全球状态表上操作的,这个表称为“未花费交易输出列表”。但是比特币的协议并没有明确规定这个全球状态表。全球状态表的产生纯粹是矿工为了加快验证过程而创造出来的。

另一方面,以太坊则是基于账户的模式。由于以太坊已经存储了合约地址和状态的对照表的数据结构,很自然地也同时存储每个普通地址(或者叫拥有者的地址)的账户余额。这意味着,与非闭环式的交易支付模式必须有输入和输出不同,以太坊存储每个地址的账户余额,这一点,与银行存储每个账户余额的方式类似。

以太坊的数据结构。在第3章,我们提到基于账户的账本需要精心设计的数据结构来存储记录。以太坊就有这样的数据结构。具体来说,每个区块包含每个地址的目前状态(账户余额和交易数)的摘要,同时也包含每个合约的状态(余额和存储空间)。每个合约的存储树结构映射256比特的地址和256比特的字节。这样可以存储巨量的(2256×256=2264 )信息。当然,这只不过是理论上的可能空间,我们不会用到这么大的存储空间。数据结构里面提供的摘要,使验证一个地址有多少余额或者空间变得相对容易。比如,不需要鲍勃从头到尾扫描整个区块链,爱丽丝就可以向鲍勃证明她有多少余额。

此时,比特币用简单的二项梅克尔树的结构可以派得上用场。因为它可以把有效的证明数据存在该区块里(要求矿工确信对于相同的地址,每个树状数据结构都要求该地址相同的状态)。但是我们也希望能够更快地查询地址并且能够有效更新地址的数值。为了达到这个目的,以太坊使用比较复杂的树状结构,叫帕特里夏树(Patricia tree)、前缀树(prefix tree)、字典树(trie)或基数树(radix tree)。每个以太坊区块包含梅克尔-帕特里夏树(Merkle Patricia tree)的树根,它保存每个地址的状态,也包含合约地址。每个合约的状态,包含一个树状数据结构用来保存合约的存储状态。

基于账户账本的另一个不易处理的问题是防止重复攻击。在比特币里,每个交易都使用“未花费交易输出列表”输入,因此,任何相同签名认证过的交易,不可能被重复使用两次。但是在以太坊设计里,需要确保当爱丽丝签下支付给鲍勃1以太交易的时候,鲍勃不能一次又一次地对外广播并重复使用这个1以太,直到把爱丽丝的账户用光。这样的交易不能重复,因为一旦使用了,爱丽丝的交易计数会增加一次,而这个交易计数是一个全局的状态参数。

总的来说,以太坊使用比比特币更加强大的数据结构来管理它的账本。虽然我们没有深入研究它的数据结构,但我们知道,这个数据结构使得账户、合约,以及交易相关声明的有效验证变成可能。

以太坊项目

以太坊最早于2013年年末开始讨论,并于2015年第一次发布,代号先行者(Frontier)。以太坊采用预售的方式,以固定比特币价格公开出售,并把所有的预售款投入以太坊基金会。

和其他另类币相比,以太坊发展比较缓慢,这也反映了以太币是一个比较复杂的系统。与比特币相比,以太坊增加以太坊专用虚拟机(EVM),一个全新编程模式,一个全新的数据结构。此外,以太坊还对比特币的共识模式做了大的修改。每个区块产生的时间不是10分钟,而是12秒。在以太坊体系里,过时区块的比例高于比特币体系,为了减少过时的区块对系统的影响,以太坊采用另一个叫“精灵”(GHOST)的协议来计算共识分支。同时,以太坊采用不同的工作量证明。目前采用的是一个混合的哈希方程,被设计成只能用记忆体计算。未来以太坊计划转为通过权益证明份额证明的体系。

以太坊呈现出和比特币在设计理念上的巨大差异。以太坊项目由非营利机构主导并且在规划和决策上相对比较集中,它们根据历史经验对以太坊协议进行修改,并且都有一个公开的时间表。按规划,将来也会有硬分叉。而且,所有以太坊合约都要在版本更新前销毁。所以,以太坊还是一个未来会有很多变更的实验性体系。截至2015年,投入大量精力在以太坊上并构建真正有用的应用,现在看来是有点太早。但是以太坊无疑是一个非常有潜力的系统。也许这本书未来的版本将会命名为“以太坊和加密货币技术”。

本章主要讨论了比特币如何成为其他加密货币和另类币的重要组成部分。它们在各方面相互竞争、合作并且相互影响,有些相辅相成,有些是相互阻碍。在未来,可能会出现新的技术,使得在一种区块链可以直接引用另一个区块链的交易。

但截至目前,有些问题仍然悬而未决。另类币会演变并相互合并,最后成为少数另类币主宰的生态系统吗?还是和现在一样多样化?特定功能的另类币会蓬勃发展,还是以以太坊为标志的通用编程平台最后成为主流?比特币和另类币之间的相互影响是有益的吗?每个另类币之间应该相互独立,比如用不同的挖矿谜题而不是去共同挖矿?我们现在无法回答上述这些问题,但我们已经讨论了所有这些你需要理解和评估的重要概念。

延展阅读

侧链白皮书:

Back,Adam,Matt Corallo,Luke Dashjr,Mark Friedenbach,Gregory Maxwell,Andrew Miller, Andrew Poelstra,Jorge Timón,and Pieter Wuille.“Enabling Blockchain Innovations with Pegged Sidechains.”2014.

您可以通过如下网址阅读:

https://blockstream.com/sidechains.pdf.

关于域名币和使用其他用加密币设计域名/价值储存方法的论文:

Kalodner,Harry,Miles Carlsten,Paul Ellenbogen,Joseph Bonneau,and Arvind Narayanan.“An Empirical Study of Namecoin and Lessonsf or Decentralized Namespace Design. Presented at the Workshop on the Economics of Information Security,2015.

您可以通过如下网址阅读:

http://randomwalker.info/publications/namespaces.pdf.

以太坊白皮书:

Various authors.“A Next-Generation Smart Contract and Decentralized Application Platform.”

您可以通过以下网址阅读:

http://github.com/ethereum/wiki/wiki/white-paper.

分析以太坊激励机制错配的学术论文:

Luu,Loi,Jason Teutsch,Raghav Kulkarni,and Prateek Saxena.“Demystifying Incentives in the Consensus Computer.” Proceeding of the 22nd ACM SIGSAC Conference on Computer and Communications Security ,New York:ACM, 2015.