比特坊研究报告之——以太坊白皮书解读
作者:比特币咕噜
比特坊数字资产研究俱乐部 出品(www.bitfarm.io)
虽然以太坊白皮书的中文版已经面世几个月了,但由于其中涉及了很多技术细节,阅读白皮书要求读者本身掌握一定的计算机编程知识,这样的门槛不可避免地将一部分读者拒之门外。介于此,本文将先从非技术的角度,带读者一起走进以太坊的世界,之后再举两个例子,对以太坊中的合约的运行进行解析,对于不想细究技术原理的读者,此处可跳过 。
背景
比特币开创了去中心化密码货币的先河,五年多的时间充分检验了区块链技术的可行性和安全性。比特币的区块链事实上是一套分布式的数据库,如果再在其中加进一个符号——比特币,并规定一套协议使得这个符号可以在数据库上安全地转移,并且无需信任第三方,这些特征的组合完美地构造了一个货币传输体系——比特币网络。然而比特币作为一次密码货币的伟大尝试,她并不完美,其中,协议的扩展性是一项不足,例如比特币网络里只有一种符号——比特币,用户无法自定义另外的符号,这些符号可以是代表公司的股票,或者是债务凭证等,这就损失了一些功能。另外,比特币协议里使用了一套基于堆栈的脚本语言,这语言虽然具有一定灵活性,使得像多重签名这样的功能得以实现,然而却不足以构建更高级的应用,例如去中心化交易所等。
为了解决这个问题,社区的Mastercoin团队和Countparty团队都试图在比特币之上创建另外一套协议,同时也创建一种新币,这些币可以统称为Metacoin。具体的方式是通过在比特币的交易里添加额外的信息,再用另外的客户端来解析这些信息,他们把Meatcoin这种方式自比“在TCP/IP协议之上构建HTTP协议”。但问题来了,首先,这种方式的效率不高,例如在利用Metacoin系统构建的去中心化交易所里,当用户发出指令要买入某种资产时候,挟带这条指令的那笔比特币交易必须要被加入到区块之后,指令才能生效。高效的做法应该是这条指令直接保存在矿工的内存里,如果买入指令跟已有的卖单匹配,矿工则撮合交易,并写入下一个区块。而现在的情况是,比特币矿工根本不知道交易中嵌入的额外信息是什么意思,这样看起来“TCP/IP协议”和“HTTP协议”之间其实并不怎么配合,正如以太坊白皮书里所说,这倒更像是在SMTP协议上建立HTTP协议。以太坊的白皮书还指出,Metacoin不可能实现完全安全的轻钱包,也就是说客户端需要保留Metacoin创世区块后的所有比特币区块,这对用户来说是一件多么头大的事情啊!
以太坊是什么?
以太坊从设计上就是为了解决比特币扩展性不足的问题。总的来说,以太坊是一个平台,她上面提供各种模块让用户来搭建应用,如果将搭建应用比作造房子,那么以太坊就提供了墙面、屋顶、地板等模块,用户只需像搭积木一样把房子搭起来,因此在以太坊上建立应用的成本和速度都大大改善。具体来说,以太坊通过一套图灵完备的脚本语言(Ethereum Virtual Machine code,简称EVM语言)来建立应用,它类似于汇编语言,我们知道,直接用汇编语言编程是非常痛苦的,但以太坊里的编程并不需要直接使用EVM语言,而是类似C语言、Python、Lisp等高级语言,再通过编译器转成EVM语言。
上面所说的平台之上的应用,其实就是合约,这是以太坊的核心。合约是一个活在以太坊系统里的自动代理人,他有一个自己的以太币地址,当用户向合约的地址里发送一笔交易后,该合约就被激活,然后根据交易中的额外信息,合约会运行自身的代码,最后返回一个结果,这个结果可能是从合约的地址发出另外一笔交易。需要指出的是,以太坊中的交易,不单只是发送以太币而已,它还可以嵌入相当多的额外信息。如果一笔交易是发送给合约的,那么这些信息就非常重要,因为合约将根据这些信息来完成自身的业务逻辑。
合约所能提供的业务,几乎是无穷无尽的,它的边界就是你的想象力,因为图灵完备的语言提供了完整的自由度,让用户搭建各种应用。白皮书举了几个例子,如储蓄账户、用户自定义的子货币等,这里再列举几个笔者想到的例子:1)去中心化交易所,2)各种金融衍生合约,3)彩票,4)基于预测未来事件的打赌,5)投票/仲裁系统,6)去中心化自治组织(DAO),例如基金。这些合约之间可以互动,例如4)打赌合约可以访问5)仲裁合约,而仲裁合约可能是一个基于POS的投票系统,投票的结果作为外部事件的结果返回给打赌合约,作为最后的裁定。
合约示例
对于希望了解如何建立合约、以及合约如何运转的读者,以下两个例子应该能提供一些帮助,但最好结合白皮书中的交易格式、费用组成、数据存储结构等知识进行理解。以下的例子采用类似C的语言编写。
Name Registration
[1] if tx.value < block.basefee * 200:
[2] stop
[3] if contract.storage[tx.data[0]] or tx.data[0] < 100:
[4] stop
[5] contract.storage[tx.data[0]] = tx.data[1]
第1行:如果手续费不够,退出。
第3行:contract.storage[tx.data[0]] 是为了检查tx.data[0]所代表的名称是不是已经被注册了,例如www.bitfarm.io。因为所有contract.storage的项的初始值都是0,所以如果contract.storage[tx.data[0]]不为0,说明之前已经注册过了,而如果if从句返回一个非0的值,则执行stop。tx.data[0] |