以太坊是一个开源的有智能合约功能的公共区块链平台,通过提供专用加密货币以太币(Ether)以及去中心化的以太坊虚拟机(EVM)来处理点对点合约。
预备知识
以太坊
以太坊是一个可编程的区块链,它并没有给用户提供一组预定义的操作(如比特币交易),而是允许用户创建他们自己的操作,这些操作可以任意复杂。这样一来,以太坊就成为了多种不同类型去中心化区块链的平台,包括且不仅限于密码学货币。
以太坊平台对底层区块链技术进行了封装,让区块链应用开发者可以直接基于以太坊平台进行开发。这样一来开发者只需要专注于应用本身的开发,从而大大降低了开发的难度。
狭义上来说,以太坊是一套可以实现分布式应用的平台协议,它的核心是可以执行任意复杂度算法的以太坊虚拟机(EVM)。
和其他区块链一样,以太坊也包含一套P2P协议。以太坊区块链数据由网络上的节点进行维护和更新,网络上的每一个节点都运行着EVM并执行相同的指令。因此,以太坊经常被描述为“世界电脑”。
以太坊网络中大规模的并行计算并不是为了计算更高效——事实上,这个过程让计算速度比传统的计算更为低效。另一方面,以太坊中每一个节点都运行着EVM的目的是保持整个区块链的共识。分散式的共识机制给予了以太坊极高的容错能力,确保零宕机,并且使存储于区块链的数据永远不可更改并且可被审查。
以太坊本质上就是一个保存数字交易永久记录的公共数据库。重要的是,这个数据库不需要任何中央权威机构来维持和保护,这是一个个体在不需要信任任何第三方或对方的情况下进行P2P交易的架构。
智能合约
以太坊上的程序 被称为 智能合约,它是 代码和数据(状态)的集合。
比特币的交易是可以编程的,但是比特币脚本有很多的限制,能够编写的程序也有限。而以太坊则是图灵完备的,可以让我们像使用任何高级语言一样来编写几乎可以做任何事情的程序(即智能合约)。
智能合约非常适合对信任、安全和持久性要求较高的应用场景,比如:数字货币、数字资产、投票、保险、金融应用、预测市场、产权所有权管理、物联网、点对点交易等等。但目前除了数字货币之外,真正落地的应用还并不多。
编程语言:Solidity
EVM有自己内含的语言——EVM操作码。类似其他高级语言,EVM也有自己的高级语言,当下流行的是 Solidity和 Viper,编译后可在EVM中执行。
智能合约的默认编程语言是Solidity,文件扩展名以
.sol
结尾。Browser-Solidity Web IDE是一个基于Web的Solidity IDE。
Solidity是和JavaScript相似的语言,用来开发智能合约并将其编译成以太坊虚拟机字节代码。
运行环境:以太坊虚拟机(EVM)
EVM ( Ethereum Virtual Machine ) 即 以太坊虚拟机 是以太坊中智能合约的运行环境。而EVM运行在以太坊节点上,当我们把合约部署到以太坊网络上之后,合约就可以在以太坊网络中运行了。
- EVM使用了256比特长度的机器码,是一种基于堆栈的虚拟机,用于执行智能合约,并使用了以太坊账户模型(Account Model)来进行价值传输。
- EVM是图灵完备的,由于以太坊系统中引入了
Gas
的概念,所以原则上在EVM中可执行的计算总量受Gas
总量限制。 - EVM是一个隔离的环境,在EVM内部运行的代码不能跟外部有任何联系。
EVM采用了基于栈(Stack)的架构,也就是后进先出(LIFO)的方式。
在以太坊设计原理中描述了EVM的设计目标:
- 简单:操作码尽可能的少并且低级,数据类型尽可能少,虚拟机的结构尽可能少;
- 结果明确:在VM规范语句中,没有任何可能产生歧义的空间,结果应该是完全确定的。此外,计算步骤应该是精确的,以便可以测量Gas的消耗量;
- 节约空间:EVM组件应尽可能紧凑;
- 预期应用应具备专业化能力:在VM上构建的应用应能处理20字节的地址,以及32位的自定义加密值,拥有用于自定义加密的模数运算、读取区块和交易数据与状态交互等能力;
- 简单安全:为了让VM不被利用,应该能够容易地建立一套Gas消耗成本模型的操作;
- 优化友好:应该易于优化,以便即时编译(JIT)和VM的加速版本能够构建出来。
同时EVM也有如下特殊设计:
- 区分临时存储(Memory,存在于VM的每个实例中,并在VM执行结束后消失)和永久存储(Storage,存在于区块链状态层);
- 采用基于栈(Stack)的架构;
- 机器码长度为256比特,即32字节;
- 使用了可变、可扩展的内存大小;
- 栈的大小没有限制;
- 1024调用深度限制;
- 无类型。
像之前定义的那样,EVM是图灵完备虚拟机器,而EVM本质上是被Gas束缚,因此可以完成的计算总量本质上是被提供的Gas总量限制的。
此外,EVM具有基于堆栈的架构。每个堆栈顶的大小为256位,堆栈有一个最大的大小,为1024位。
EVM有内存(Memory),项目按照可寻址字节数组来存储。内存是易失的,也就是说数据是不持久的。EVM还有一个存储器(Storage),与内存不同,存储器是非易失的,并作为系统状态的一部分进行维护。EVM分开保存程序代码,在虚拟ROM中只能通过特殊指令来访问。
合约的编译
EVM上运行的是合约的字节码形式,需要我们在部署之前先对合约进行编译。可以选择Browser-Solidity Web IDE或者solc编译器。
合约的部署
在以太坊上开发应用时,常常要使用到 以太坊客户端(钱包)。其实我们可以把以太坊客户端理解为一个开发者工具,它提供 账户管理、挖矿、转账、智能合约的部署和执行 等功能,EVM也是由以太坊客户端提供的。
以太坊客户端:Geth
Geth 是典型的开发以太坊时使用的客户端,基于Go语言开发。Geth提供了一个交互式命令控制台,其中包含了以太坊的各种功能(API)。
Geth控制台和 Chrome浏览器开发者工具里的控制台是类似的,不过是跑在终端里。
相对于Geth,Mist则是图形化操作界面的以太坊客户端。
合约如何部署?
智能合约的部署是指把合约字节码发布到区块链上,并使用一个特定的地址来表示这个合约,这个地址称为合约账户。
以太坊中有两种不同类型但是共享同一地址空间的账户:
- 外部账户由一对公私钥控制,没有关联任何代码,其地址是由公钥(经过Hash运算)决定的
- 合约账户由账户内部的合约代码控制,该类账户被它们的合约代码控制且有代码与之关联,其地址在此合约被创建的时候决定。每个账户都有一个持久的
Key-Value
类型的存储,并将256位的Key
映射到256位的Value
上
合约的运行
合约部署后,当需要调用这个智能合约的方法时,只需要向这个合约账户发送消息(交易)即可。通过交易消息触发后,智能合约的代码就会在EVM中执行了。
Gas机制
和云计算类似,占用区块链的资源需要付出相应的费用。
以太坊上用Gas机制来计费,可以将其看作一个工作量单位。智能合约越复杂(计算步骤的数量和类型、占用的内存等),用来完成运行就需要越多的Gas
。
任何特定的合约所需的运行合约的Gas数量是固定的,由合约的复杂度决定。而 Gas价格由运行合约的人在提交运行合约请求的时候规定,以确定他愿意为这次交易付出的费用:
Gas
价格 ×Gas
数量。
Gas
的目的是限制执行交易所需的工作量,同时为执行支付费用。
如果没有
Gas
机制,就会有人写出无法停止(如死循环)的合约来阻塞网络。
当EVM执行交易时,Gas
将按照特定规则被逐渐消耗,无论执行到什么位置,一旦Gas
被耗尽,将会触发异常,当前调用帧所做的所有状态修改都将被回滚。如果执行结束还有Gas
剩余,这些Gas
将被返还给发送账户。
以太坊网络
要进行智能合约的开发,需要有以太币,可以选择以下方式:
以太坊官网测试网络Testnet
在该测试网络中,很容易就可以获得免费的以太币,缺点是需要花很长时间对节点进行初始化。
使用私有链
创建自己的以太币私有测试网络,通常也成为私有链,我们可以用它来作为一个测试环境来开发、调试和测试智能合约。
通过之前提到的Geth
很容易就可以创建一个属于自己的测试网络,以太币想挖多少挖多少,也免去了同步正式网络整个区块链数据所耗费的时间。
使用开发者网络
相比私有链,开发者网络下会自动分配一个有大量余额的开发者账户供我们使用。
使用模拟环境
另一个创建测试网络的方法是使用testrpc
,testrpc
是在本地使用内存模拟的一个以太坊环境,对于开发调试来说,更方便快捷。而且testrpc
可以在启动时帮我们创建10个存有资金的测试账户。
进行合约开发时,可以先在testrpc
中测试通过后,再部署到Geth
节点中去。
testrpc
现在已经并入到Truffle
开发框架中,现在的名字是Ganache CLI
。
Dapp:去中心化的应用程序
以太坊社区把基于智能合约的应用称为去中心化的应用程序(Decentralized App)。
如果我们把区块链理解为一个不可篡改的数据库,把智能合约理解为和数据库打交道的程序,那就很容易理解Dapp了。
总结
以太坊是平台,它让我们方便的使用区块链技术开发去中心化的应用。
在这个应用中,使用Solidity
来编写和区块链交互的智能合约。
合约编写好之后,我们需要用以太坊客户端和一个有余额的账户去部署及运行合约。
使用
Truffle
框架可以更好的帮助我们做这些事情。
为了开发方便,我们可以用Geth或testrpc来搭建一个测试网络。
EVM的缺陷与不足
机器码长度为256位
目前大多数的处理器主要由以下4种选择来实现快速的数学运算:
- 8bit整数
- 16bit整数
- 32bit整数
- 64bit整数
虽然在一些情况下32bit比16bit快,并且在x86架构中8bit数学运算并不是完全支持,但基本上如果你采用以上的任意一种,都可以保证数学运算在若干个时钟周期内完成,并且这个过程非常迅速,往往是纳秒级的。因此,可以说这些位长的整数是目前主流处理器能够原生支持且不需要额外操作的。
EVM处于所谓运算速度和效率方面考虑,采用了非主流的256bit整数。x86汇编码运算的比较实验,证明了采用256bit整数远比采用处理器原生支持的整数长度要复杂,即EVM的运算效率并不高。
缺少标准库
在开发Solidity智能合约时就会碰到这个问题,因为Solidity中根本没有标准库。目前的情况是,人们只能不断的从一些开源软件中复制粘贴代码。首先这些代码的安全性无法保证,再加上人们会为了更小的Gas消耗而不断修改代码,这就有可能对他们的合约引入更严重的安全性问题。
难以调试和测试
这个问题不仅仅是EVM的设计缺陷,也和其实现方式有关。EVM唯一能抛出的异常就是OutOfGas
,并且没有调试日志,也无法调用外部代码。同时,以太坊本身很难生成一条测试网络的私链,即使成功,私链的参数和行为也与公链不同。
不支持浮点数
浮点数有很多应用实例,比如风险建模、科学计算,以及其他一些范围和近似值比准确值更加重要的情况。EVM将浮点数排除在外的做法有潜在的局限性。
不可修改的代码
智能合约在设计时需要考虑的重要问题之一就是是可升级性,因为合约的升级是必然的。
在EVM中代码是完全不可修改的,并且由于其采用哈佛计算机结构,也就不可能将代码在内存中加载并执行,代码和数据是被完全分离的。
目前只能够通过部署新的合约来达到升级的目的,这可能需要复制原合约中的所有代码,并将老的合约重定向到新的合约地址。给合约打补丁或是部分升级合约代码在EVM中是完全不可能的。
参考文章
- 以太坊设计原理 | ETHFANS
- 深入理解以太坊系列(8):以太坊虚拟机EVM
- 以太坊虚拟机EVM是什么 | 金色百科
- 以太坊虚拟机 | Oriovo的博客
- 详解以太坊的工作原理 | CSDN
- 以太坊源码分析 Ⅰ. 区块和交易,合约和虚拟机 | CSDN
- 【区块链】以太坊源码学习-EVM | CSDN
- Solidity中文文档——1.3 以太坊虚拟机
- Diving Into The Ethereum VM Part One | Qtum’s Blog
- 深入了解以太坊虚拟机 | 简书
- What is the Ethereum Virtual Machine? | The Merkle
- What is Ethereum? | Ethereum Docs
- 以太坊是什么?| CnBlogs 深入浅出区块链
- 以太坊是什么?| 以太坊开发入门指南
- 智能合约开发环境搭建及Hello World合约 | 深入浅出区块链
- 也来谈一谈以太坊虚拟机EVM的缺陷和不足 | BITKAN
- How Ethereum Works? | coindesk
- Optimizing the Ethereum Virtual Machine | Medium.com